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}