17 |
ilm |
1 |
/*
|
|
|
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
|
|
3 |
*
|
|
|
4 |
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
|
|
|
5 |
*
|
|
|
6 |
* The contents of this file are subject to the terms of the GNU General Public License Version 3
|
|
|
7 |
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
|
|
|
8 |
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
|
|
|
9 |
* language governing permissions and limitations under the License.
|
|
|
10 |
*
|
|
|
11 |
* When distributing the software, include this License Header Notice in each file.
|
|
|
12 |
*/
|
|
|
13 |
|
|
|
14 |
package org.openconcerto.odtemplate.statements;
|
|
|
15 |
|
|
|
16 |
import org.openconcerto.odtemplate.TemplateException;
|
|
|
17 |
import org.openconcerto.odtemplate.engine.DataModel;
|
|
|
18 |
import org.openconcerto.odtemplate.engine.Material;
|
|
|
19 |
import org.openconcerto.odtemplate.engine.Parsed;
|
|
|
20 |
import org.openconcerto.odtemplate.engine.Processor;
|
|
|
21 |
import org.openconcerto.openoffice.ODPackage;
|
|
|
22 |
import org.openconcerto.openoffice.ODSingleXMLDocument;
|
|
|
23 |
import org.openconcerto.utils.ExceptionUtils;
|
|
|
24 |
import org.openconcerto.utils.cache.CacheResult;
|
|
|
25 |
import org.openconcerto.utils.cache.ICache;
|
|
|
26 |
|
|
|
27 |
import java.io.File;
|
|
|
28 |
import java.io.IOException;
|
|
|
29 |
import java.util.Collections;
|
|
|
30 |
|
|
|
31 |
import org.jdom.Element;
|
|
|
32 |
import org.jdom.JDOMException;
|
|
|
33 |
import org.jdom.xpath.XPath;
|
|
|
34 |
|
|
|
35 |
public class Include extends Statement {
|
|
|
36 |
|
|
|
37 |
private static final String PREFIX = "[IOD";
|
|
|
38 |
|
180 |
ilm |
39 |
// Cache whole file to avoid disk access since there can be a lot of sections in a single file
|
17 |
ilm |
40 |
private final ICache<File, ODSingleXMLDocument, File> cache;
|
180 |
ilm |
41 |
// Cache the Parsed of just one section in the above file
|
|
|
42 |
// { filePath#sectionName -> Parsed }
|
17 |
ilm |
43 |
private final ICache<String, Parsed<ODSingleXMLDocument>, File> parsedCache;
|
|
|
44 |
|
|
|
45 |
public Include() {
|
|
|
46 |
super("include");
|
|
|
47 |
this.cache = new ICache<File, ODSingleXMLDocument, File>(180);
|
|
|
48 |
this.parsedCache = new ICache<String, Parsed<ODSingleXMLDocument>, File>(180);
|
|
|
49 |
}
|
|
|
50 |
|
180 |
ilm |
51 |
@Override
|
|
|
52 |
public void destroy() {
|
|
|
53 |
this.cache.getSupp().die();
|
|
|
54 |
this.parsedCache.getSupp().die();
|
|
|
55 |
super.destroy();
|
|
|
56 |
}
|
|
|
57 |
|
17 |
ilm |
58 |
public boolean matches(Element elem) {
|
|
|
59 |
if (!elem.getQualifiedName().equals("text:a"))
|
|
|
60 |
return false;
|
|
|
61 |
final String name = getName(elem);
|
|
|
62 |
// see 5.1.4 Hyperlinks § Name
|
|
|
63 |
return name != null && name.startsWith(PREFIX);
|
|
|
64 |
}
|
|
|
65 |
|
|
|
66 |
private static String getName(Element elem) {
|
|
|
67 |
return elem.getAttributeValue("name", elem.getNamespace("office"));
|
|
|
68 |
}
|
|
|
69 |
|
|
|
70 |
public void prepare(Element script) {
|
|
|
71 |
// ../file.odt#source|region
|
|
|
72 |
final String href = script.getAttributeValue("href", script.getNamespace("xlink"));
|
|
|
73 |
|
|
|
74 |
final int sharp = href.indexOf('#');
|
|
|
75 |
final String path = href.substring(0, sharp);
|
|
|
76 |
// oo sometimes encodes the pipe, sometimes it doesn't
|
|
|
77 |
final int lastIndex;
|
|
|
78 |
final int pipe = href.lastIndexOf('|');
|
|
|
79 |
if (pipe < 0)
|
|
|
80 |
lastIndex = href.lastIndexOf("%7C");
|
|
|
81 |
else
|
|
|
82 |
lastIndex = pipe;
|
|
|
83 |
final String section = href.substring(sharp + 1, lastIndex);
|
|
|
84 |
|
|
|
85 |
final String name = getName(script);
|
|
|
86 |
final String paramS = name.substring(PREFIX.length(), name.lastIndexOf(']')).trim();
|
|
|
87 |
final Element param = paramS.length() > 0 ? new Element("param").setText(paramS) : null;
|
|
|
88 |
|
|
|
89 |
script.removeContent();
|
|
|
90 |
script.getAttributes().clear();
|
|
|
91 |
script.setName(this.getName());
|
|
|
92 |
script.setNamespace(stmtNS);
|
|
|
93 |
script.setAttribute("path", path);
|
|
|
94 |
script.setAttribute("section", section);
|
|
|
95 |
if (param != null)
|
|
|
96 |
script.addContent(param);
|
|
|
97 |
}
|
|
|
98 |
|
|
|
99 |
public void execute(Processor<?> processor, Element tag, DataModel model) throws TemplateException {
|
|
|
100 |
if (processor.getMaterial().getBase() == null)
|
|
|
101 |
throw new TemplateException("no base file for " + processor.getMaterial());
|
|
|
102 |
|
|
|
103 |
try {
|
|
|
104 |
// relative to the file, so use getCanonicalFile to remove ..
|
|
|
105 |
final String relativePath = tag.getAttributeValue("path");
|
|
|
106 |
final File ref = new File(processor.getMaterial().getBase(), relativePath).getCanonicalFile();
|
|
|
107 |
final Parsed<ODSingleXMLDocument> parsed = getParsed(ref, tag.getAttributeValue("section"), processor.getParsed());
|
|
|
108 |
final ODSingleXMLDocument docExecuted = parsed.execute(this.getModel(model, tag));
|
|
|
109 |
|
|
|
110 |
// replace enclosing text:p
|
|
|
111 |
final Object whole = processor.getMaterial().getWhole();
|
|
|
112 |
final ODSingleXMLDocument single;
|
|
|
113 |
if (whole instanceof ODPackage)
|
|
|
114 |
single = (ODSingleXMLDocument) ((ODPackage) whole).getContent();
|
|
|
115 |
else
|
|
|
116 |
single = (ODSingleXMLDocument) whole;
|
|
|
117 |
single.replace(getAncestorByName(tag, "p"), docExecuted);
|
|
|
118 |
} catch (IOException e) {
|
|
|
119 |
throw ExceptionUtils.createExn(TemplateException.class, "", e);
|
|
|
120 |
} catch (JDOMException e) {
|
|
|
121 |
throw ExceptionUtils.createExn(TemplateException.class, "", e);
|
|
|
122 |
}
|
|
|
123 |
tag.detach();
|
|
|
124 |
}
|
|
|
125 |
|
|
|
126 |
private Parsed<ODSingleXMLDocument> getParsed(final File ref, final String sectionName, final Parsed<?> parsed) throws JDOMException, IOException, TemplateException {
|
|
|
127 |
final Parsed<ODSingleXMLDocument> res;
|
|
|
128 |
final String key = ref.getPath() + "#" + sectionName;
|
|
|
129 |
final CacheResult<Parsed<ODSingleXMLDocument>> cached = this.parsedCache.check(key);
|
|
|
130 |
if (cached.getState() == CacheResult.State.NOT_IN_CACHE) {
|
|
|
131 |
res = this.createParsed(ref, sectionName, parsed);
|
|
|
132 |
this.parsedCache.put(key, res, Collections.<File> emptySet());
|
|
|
133 |
} else {
|
|
|
134 |
res = cached.getRes();
|
|
|
135 |
}
|
|
|
136 |
return res;
|
|
|
137 |
}
|
|
|
138 |
|
|
|
139 |
private Parsed<ODSingleXMLDocument> createParsed(final File ref, final String sectionName, final Parsed<?> parsed) throws JDOMException, IOException, TemplateException {
|
|
|
140 |
final ODSingleXMLDocument docToAdd = getXMLDocument(ref).clone();
|
|
|
141 |
|
180 |
ilm |
142 |
// replace the body with just sectionName
|
17 |
ilm |
143 |
final XPath sectionXP = docToAdd.getXPath("//text:section[@text:name = '" + sectionName + "']");
|
|
|
144 |
final Element section = (Element) sectionXP.selectSingleNode(docToAdd.getDocument());
|
180 |
ilm |
145 |
// ajouter la section elle-même car souvent des if s'y réfèrent.
|
17 |
ilm |
146 |
docToAdd.getBody().setContent(section.detach());
|
|
|
147 |
|
|
|
148 |
final Material<ODSingleXMLDocument> from = Material.from(docToAdd);
|
|
|
149 |
from.setBase(ref);
|
|
|
150 |
return new Parsed<ODSingleXMLDocument>(from, parsed);
|
|
|
151 |
}
|
|
|
152 |
|
|
|
153 |
private ODSingleXMLDocument getXMLDocument(final File ref) throws JDOMException, IOException {
|
|
|
154 |
final ODSingleXMLDocument res;
|
|
|
155 |
final CacheResult<ODSingleXMLDocument> cached = this.cache.check(ref);
|
|
|
156 |
if (cached.getState() == CacheResult.State.NOT_IN_CACHE) {
|
57 |
ilm |
157 |
res = ODSingleXMLDocument.createFromPackage(ref);
|
17 |
ilm |
158 |
this.cache.put(ref, res, Collections.<File> emptySet());
|
|
|
159 |
} else {
|
|
|
160 |
res = cached.getRes();
|
|
|
161 |
}
|
|
|
162 |
return res;
|
|
|
163 |
}
|
|
|
164 |
|
|
|
165 |
// creates a new model if tag has parameters
|
|
|
166 |
private DataModel getModel(final DataModel dm, final Element tag) throws TemplateException {
|
|
|
167 |
final DataModel res;
|
|
|
168 |
final Element param = tag.getChild("param");
|
|
|
169 |
if (param != null) {
|
|
|
170 |
res = dm.copy();
|
|
|
171 |
// evaluate
|
|
|
172 |
res.eval(param.getText());
|
|
|
173 |
} else
|
|
|
174 |
res = dm;
|
|
|
175 |
return res;
|
|
|
176 |
}
|
|
|
177 |
}
|