OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 57 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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
}