001/*
002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Thierry Delprat
018 */
019package org.nuxeo.template.processors.xdocreport;
020
021import java.io.File;
022import java.io.FileOutputStream;
023import java.io.IOException;
024import java.io.OutputStream;
025import java.util.ArrayList;
026import java.util.List;
027import java.util.Map;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.nuxeo.common.utils.FileUtils;
032import org.nuxeo.ecm.core.api.Blob;
033import org.nuxeo.ecm.core.api.Blobs;
034import org.nuxeo.ecm.core.api.DocumentModel;
035import org.nuxeo.ecm.core.api.impl.blob.FileBlob;
036import org.nuxeo.runtime.api.Framework;
037import org.nuxeo.template.api.InputType;
038import org.nuxeo.template.api.TemplateInput;
039import org.nuxeo.template.api.TemplateProcessor;
040import org.nuxeo.template.api.adapters.TemplateBasedDocument;
041import org.nuxeo.template.fm.FMContextBuilder;
042import org.nuxeo.template.fm.FreeMarkerVariableExtractor;
043import org.nuxeo.template.processors.AbstractTemplateProcessor;
044
045import fr.opensagres.xdocreport.core.XDocReportException;
046import fr.opensagres.xdocreport.document.IXDocReport;
047import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
048import fr.opensagres.xdocreport.template.IContext;
049import fr.opensagres.xdocreport.template.TemplateEngineKind;
050import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
051
052/**
053 * XDocReport based {@link TemplateProcessor}
054 *
055 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a>
056 */
057public class XDocReportProcessor extends AbstractTemplateProcessor implements TemplateProcessor {
058
059    protected static final Log log = LogFactory.getLog(XDocReportProcessor.class);
060
061    public static final String TEMPLATE_TYPE = "XDocReport";
062
063    public static final String OOO_TEMPLATE_TYPE = "OpenDocument";
064
065    public static final String DocX_TEMPLATE_TYPE = "DocX";
066
067    protected FMContextBuilder fmContextBuilder = new FMContextBuilder();
068
069    protected String getTemplateFormat(Blob blob) {
070        String filename = blob.getFilename();
071        if (filename == null && blob instanceof FileBlob) {
072            File file = ((FileBlob) blob).getFile();
073            if (file != null) {
074                filename = file.getName();
075            }
076        }
077        if (filename != null && !filename.isEmpty()) {
078            if (filename.endsWith(".docx")) {
079                return DocX_TEMPLATE_TYPE;
080            } else if (filename.endsWith(".odt")) {
081                return OOO_TEMPLATE_TYPE;
082            }
083        }
084        return OOO_TEMPLATE_TYPE;
085    }
086
087    @Override
088    public List<TemplateInput> getInitialParametersDefinition(Blob blob) throws IOException {
089
090        List<TemplateInput> params = new ArrayList<>();
091        String xmlContent = null;
092
093        if (OOO_TEMPLATE_TYPE.equals(getTemplateFormat(blob))) {
094            xmlContent = ZipXmlHelper.readXMLContent(blob, ZipXmlHelper.OOO_MAIN_FILE);
095        } else if (DocX_TEMPLATE_TYPE.equals(getTemplateFormat(blob))) {
096            xmlContent = ZipXmlHelper.readXMLContent(blob, ZipXmlHelper.DOCX_MAIN_FILE);
097        }
098
099        if (xmlContent != null) {
100            List<String> vars = FreeMarkerVariableExtractor.extractVariables(xmlContent);
101
102            for (String var : vars) {
103                TemplateInput input = new TemplateInput(var);
104                params.add(input);
105            }
106        }
107        return params;
108    }
109
110    @Override
111    public Blob renderTemplate(TemplateBasedDocument templateBasedDocument, String templateName) throws IOException {
112
113        Blob sourceTemplateBlob = getSourceTemplateBlob(templateBasedDocument, templateName);
114
115        // load the template
116        IXDocReport report;
117        try {
118            report = XDocReportRegistry.getRegistry().loadReport(sourceTemplateBlob.getStream(),
119                    TemplateEngineKind.Freemarker, false);
120        } catch (XDocReportException e) {
121            throw new IOException(e);
122        }
123
124        // manage parameters
125        List<TemplateInput> params = templateBasedDocument.getParams(templateName);
126        FieldsMetadata metadata = new FieldsMetadata();
127        for (TemplateInput param : params) {
128            if (param.getType() == InputType.PictureProperty) {
129                metadata.addFieldAsImage(param.getName());
130            }
131        }
132        report.setFieldsMetadata(metadata);
133
134        // fill Freemarker context
135        DocumentModel doc = templateBasedDocument.getAdaptedDoc();
136        Map<String, Object> ctx = fmContextBuilder.build(doc, templateName);
137
138        XDocReportBindingResolver resolver = new XDocReportBindingResolver(metadata);
139        resolver.resolve(params, ctx, templateBasedDocument);
140
141        // add default context vars
142        IContext context;
143        try {
144            context = report.createContext();
145        } catch (XDocReportException e) {
146            throw new IOException(e);
147        }
148        for (String key : ctx.keySet()) {
149            context.put(key, ctx.get(key));
150        }
151        // add automatic loop on audit entries
152        metadata.addFieldAsList("auditEntries.principalName");
153        metadata.addFieldAsList("auditEntries.eventId");
154        metadata.addFieldAsList("auditEntries.eventDate");
155        metadata.addFieldAsList("auditEntries.docUUID");
156        metadata.addFieldAsList("auditEntries.docPath");
157        metadata.addFieldAsList("auditEntries.docType");
158        metadata.addFieldAsList("auditEntries.category");
159        metadata.addFieldAsList("auditEntries.comment");
160        metadata.addFieldAsList("auditEntries.docLifeCycle");
161        metadata.addFieldAsList("auditEntries.repositoryId");
162
163        File workingDir = getWorkingDir();
164        File generated = new File(workingDir, "XDOCReportresult-" + System.currentTimeMillis());
165        generated.createNewFile();
166
167        OutputStream out = new FileOutputStream(generated);
168
169        try {
170            report.process(context, out);
171        } catch (XDocReportException e) {
172            throw new IOException(e);
173        }
174
175        Blob newBlob = Blobs.createBlob(generated);
176
177        String templateFileName = sourceTemplateBlob.getFilename();
178
179        // set the output file name
180        String targetFileExt = FileUtils.getFileExtension(templateFileName);
181        String targetFileName = FileUtils.getFileNameNoExt(templateBasedDocument.getAdaptedDoc().getTitle());
182        targetFileName = targetFileName + "." + targetFileExt;
183        newBlob.setFilename(targetFileName);
184
185        // mark the file for automatic deletion on GC
186        Framework.trackFile(generated, newBlob);
187        return newBlob;
188    }
189}