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