Dépôt officiel du code source de l'ERP OpenConcerto
Rev 17 | Rev 180 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.odtemplate.statements;
import org.openconcerto.odtemplate.TemplateException;
import org.openconcerto.odtemplate.engine.DataModel;
import org.openconcerto.odtemplate.engine.Material;
import org.openconcerto.odtemplate.engine.Parsed;
import org.openconcerto.odtemplate.engine.Processor;
import org.openconcerto.openoffice.ODPackage;
import org.openconcerto.openoffice.ODSingleXMLDocument;
import org.openconcerto.utils.ExceptionUtils;
import org.openconcerto.utils.cache.CacheResult;
import org.openconcerto.utils.cache.ICache;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.xpath.XPath;
public class Include extends Statement {
private static final String PREFIX = "[IOD";
private final ICache<File, ODSingleXMLDocument, File> cache;
private final ICache<String, Parsed<ODSingleXMLDocument>, File> parsedCache;
public Include() {
super("include");
this.cache = new ICache<File, ODSingleXMLDocument, File>(180);
this.parsedCache = new ICache<String, Parsed<ODSingleXMLDocument>, File>(180);
}
public boolean matches(Element elem) {
if (!elem.getQualifiedName().equals("text:a"))
return false;
final String name = getName(elem);
// see 5.1.4 Hyperlinks § Name
return name != null && name.startsWith(PREFIX);
}
private static String getName(Element elem) {
return elem.getAttributeValue("name", elem.getNamespace("office"));
}
public void prepare(Element script) {
// ../file.odt#source|region
final String href = script.getAttributeValue("href", script.getNamespace("xlink"));
final int sharp = href.indexOf('#');
final String path = href.substring(0, sharp);
// oo sometimes encodes the pipe, sometimes it doesn't
final int lastIndex;
final int pipe = href.lastIndexOf('|');
if (pipe < 0)
lastIndex = href.lastIndexOf("%7C");
else
lastIndex = pipe;
final String section = href.substring(sharp + 1, lastIndex);
final String name = getName(script);
final String paramS = name.substring(PREFIX.length(), name.lastIndexOf(']')).trim();
final Element param = paramS.length() > 0 ? new Element("param").setText(paramS) : null;
script.removeContent();
script.getAttributes().clear();
script.setName(this.getName());
script.setNamespace(stmtNS);
script.setAttribute("path", path);
script.setAttribute("section", section);
if (param != null)
script.addContent(param);
}
public void execute(Processor<?> processor, Element tag, DataModel model) throws TemplateException {
if (processor.getMaterial().getBase() == null)
throw new TemplateException("no base file for " + processor.getMaterial());
try {
// relative to the file, so use getCanonicalFile to remove ..
final String relativePath = tag.getAttributeValue("path");
final File ref = new File(processor.getMaterial().getBase(), relativePath).getCanonicalFile();
final Parsed<ODSingleXMLDocument> parsed = getParsed(ref, tag.getAttributeValue("section"), processor.getParsed());
final ODSingleXMLDocument docExecuted = parsed.execute(this.getModel(model, tag));
// replace enclosing text:p
final Object whole = processor.getMaterial().getWhole();
final ODSingleXMLDocument single;
if (whole instanceof ODPackage)
single = (ODSingleXMLDocument) ((ODPackage) whole).getContent();
else
single = (ODSingleXMLDocument) whole;
single.replace(getAncestorByName(tag, "p"), docExecuted);
} catch (IOException e) {
throw ExceptionUtils.createExn(TemplateException.class, "", e);
} catch (JDOMException e) {
throw ExceptionUtils.createExn(TemplateException.class, "", e);
}
tag.detach();
}
private Parsed<ODSingleXMLDocument> getParsed(final File ref, final String sectionName, final Parsed<?> parsed) throws JDOMException, IOException, TemplateException {
final Parsed<ODSingleXMLDocument> res;
final String key = ref.getPath() + "#" + sectionName;
final CacheResult<Parsed<ODSingleXMLDocument>> cached = this.parsedCache.check(key);
if (cached.getState() == CacheResult.State.NOT_IN_CACHE) {
res = this.createParsed(ref, sectionName, parsed);
this.parsedCache.put(key, res, Collections.<File> emptySet());
} else {
res = cached.getRes();
}
return res;
}
private Parsed<ODSingleXMLDocument> createParsed(final File ref, final String sectionName, final Parsed<?> parsed) throws JDOMException, IOException, TemplateException {
final ODSingleXMLDocument docToAdd = getXMLDocument(ref).clone();
final XPath sectionXP = docToAdd.getXPath("//text:section[@text:name = '" + sectionName + "']");
final Element section = (Element) sectionXP.selectSingleNode(docToAdd.getDocument());
// ajouter la section car souvent des if s'y réfèrent.
docToAdd.getBody().setContent(section.detach());
final Material<ODSingleXMLDocument> from = Material.from(docToAdd);
from.setBase(ref);
return new Parsed<ODSingleXMLDocument>(from, parsed);
}
private ODSingleXMLDocument getXMLDocument(final File ref) throws JDOMException, IOException {
final ODSingleXMLDocument res;
final CacheResult<ODSingleXMLDocument> cached = this.cache.check(ref);
if (cached.getState() == CacheResult.State.NOT_IN_CACHE) {
res = ODSingleXMLDocument.createFromPackage(ref);
this.cache.put(ref, res, Collections.<File> emptySet());
} else {
res = cached.getRes();
}
return res;
}
// creates a new model if tag has parameters
private DataModel getModel(final DataModel dm, final Element tag) throws TemplateException {
final DataModel res;
final Element param = tag.getChild("param");
if (param != null) {
res = dm.copy();
// evaluate
res.eval(param.getText());
} else
res = dm;
return res;
}
}