001/* 002 * (C) Copyright 2006-20012 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 */ 018 019package org.nuxeo.template.processors.jod; 020 021import java.io.File; 022import java.io.FileOutputStream; 023import java.io.IOException; 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.Date; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030import java.util.zip.ZipEntry; 031import java.util.zip.ZipInputStream; 032 033import net.sf.jooreports.templates.DocumentTemplate; 034import net.sf.jooreports.templates.DocumentTemplateException; 035import net.sf.jooreports.templates.DocumentTemplateFactory; 036 037import org.nuxeo.ecm.core.api.Blob; 038import org.nuxeo.ecm.core.api.Blobs; 039import org.nuxeo.ecm.core.api.DocumentModel; 040import org.nuxeo.ecm.core.api.NuxeoException; 041import org.nuxeo.ecm.core.api.PropertyException; 042import org.nuxeo.ecm.core.api.model.Property; 043import org.nuxeo.ecm.core.schema.types.Type; 044import org.nuxeo.ecm.core.schema.types.primitives.BooleanType; 045import org.nuxeo.ecm.core.schema.types.primitives.DateType; 046import org.nuxeo.ecm.core.schema.types.primitives.StringType; 047import org.nuxeo.ecm.platform.rendering.fm.adapters.DocumentObjectWrapper; 048import org.nuxeo.runtime.api.Framework; 049import org.nuxeo.template.api.InputType; 050import org.nuxeo.template.api.TemplateInput; 051import org.nuxeo.template.api.TemplateProcessor; 052import org.nuxeo.template.api.adapters.TemplateBasedDocument; 053import org.nuxeo.template.api.adapters.TemplateSourceDocument; 054import org.nuxeo.template.fm.FMContextBuilder; 055import org.nuxeo.template.fm.FreeMarkerVariableExtractor; 056import org.nuxeo.template.odt.OOoArchiveModifier; 057import org.nuxeo.template.processors.AbstractTemplateProcessor; 058 059import freemarker.template.TemplateModelException; 060 061/** 062 * {@link TemplateProcessor} for ODT based templates. Using JODReports but also custom ODT hacks. May be migrated to 063 * pure ODT + Custom Freemarker soon. 064 * 065 * @author Tiry (tdelprat@nuxeo.com) 066 */ 067public class JODReportTemplateProcessor extends AbstractTemplateProcessor implements TemplateProcessor { 068 069 public static final String TEMPLATE_TYPE = "JODTemplate"; 070 071 protected FMContextBuilder fmContextBuilder = new FMContextBuilder(); 072 073 @Override 074 public List<TemplateInput> getInitialParametersDefinition(Blob blob) throws IOException { 075 076 List<TemplateInput> params = new ArrayList<TemplateInput>(); 077 String xmlContent = readXMLContent(blob); 078 079 List<String> vars = FreeMarkerVariableExtractor.extractVariables(xmlContent); 080 081 for (String var : vars) { 082 TemplateInput input = new TemplateInput(var); 083 params.add(input); 084 } 085 086 // add includes 087 // params.addAll(IncludeManager.getIncludes(xmlContent)); 088 089 return params; 090 } 091 092 @Override 093 public Blob renderTemplate(TemplateBasedDocument templateBasedDocument, String templateName) throws IOException { 094 095 OOoArchiveModifier modifier = new OOoArchiveModifier(); 096 097 Blob sourceTemplateBlob = templateBasedDocument.getTemplateBlob(templateName); 098 if (templateBasedDocument.getSourceTemplateDoc(templateName) != null) { 099 sourceTemplateBlob = templateBasedDocument.getSourceTemplateDoc(templateName).getAdapter( 100 TemplateSourceDocument.class).getTemplateBlob(); 101 } 102 List<TemplateInput> params = templateBasedDocument.getParams(templateName); 103 104 // init Jod template from the template DocumentModel Blob 105 DocumentTemplateFactory documentTemplateFactory = new DocumentTemplateFactory(); 106 DocumentTemplate template = documentTemplateFactory.getTemplate(sourceTemplateBlob.getStream()); 107 108 // build fm context 109 Map<String, Object> context = new HashMap<String, Object>(); 110 111 // store Blobs to be inserted 112 List<Blob> blobsToInsert = new ArrayList<Blob>(); 113 114 DocumentObjectWrapper nuxeoWrapper = new DocumentObjectWrapper(null); 115 116 for (TemplateInput param : params) { 117 if (param.isSourceValue()) { 118 Property property = null; 119 try { 120 property = templateBasedDocument.getAdaptedDoc().getProperty(param.getSource()); 121 } catch (PropertyException e) { 122 log.warn("Unable to ready property " + param.getSource(), e); 123 } 124 if (property != null) { 125 Serializable value = property.getValue(); 126 if (value != null) { 127 if (Blob.class.isAssignableFrom(value.getClass())) { 128 Blob blob = (Blob) value; 129 if (param.getType() == InputType.PictureProperty) { 130 if (blob.getMimeType() == null || "".equals(blob.getMimeType().trim())) { 131 blob.setMimeType("image/jpeg"); 132 } 133 context.put(param.getName(), blob); 134 blobsToInsert.add((Blob) value); 135 } 136 } else { 137 try { 138 context.put(param.getName(), nuxeoWrapper.wrap(property)); 139 } catch (TemplateModelException e) { 140 throw new NuxeoException(e); 141 } 142 } 143 } else { 144 // no available value, try to find a default one ... 145 Type pType = property.getType(); 146 if (pType.getName().equals(BooleanType.ID)) { 147 context.put(param.getName(), new Boolean(false)); 148 } else if (pType.getName().equals(DateType.ID)) { 149 context.put(param.getName(), new Date()); 150 } else if (pType.getName().equals(StringType.ID)) { 151 context.put(param.getName(), ""); 152 } else if (pType.getName().equals(StringType.ID)) { 153 context.put(param.getName(), ""); 154 } else { 155 context.put(param.getName(), new Object()); 156 } 157 } 158 } 159 } else { 160 if (InputType.StringValue.equals(param.getType())) { 161 context.put(param.getName(), param.getStringValue()); 162 } else if (InputType.BooleanValue.equals(param.getType())) { 163 context.put(param.getName(), param.getBooleanValue()); 164 } else if (InputType.DateValue.equals(param.getType())) { 165 context.put(param.getName(), param.getDateValue()); 166 } 167 } 168 } 169 170 // add default context vars 171 DocumentModel doc = templateBasedDocument.getAdaptedDoc(); 172 context.putAll(fmContextBuilder.build(doc, templateName)); 173 174 File workingDir = getWorkingDir(); 175 File generated = new File(workingDir, "JODReportresult"); 176 generated.createNewFile(); 177 178 try { 179 template.createDocument(context, new FileOutputStream(generated)); 180 } catch (DocumentTemplateException e) { 181 throw new NuxeoException(e); 182 } 183 184 generated = modifier.updateArchive(workingDir, generated, blobsToInsert); 185 186 Blob newBlob = Blobs.createBlob(generated); 187 newBlob.setMimeType("application/vnd.oasis.opendocument.text"); 188 if (templateBasedDocument.getTemplateBlob(templateName) != null) { 189 newBlob.setFilename(templateBasedDocument.getTemplateBlob(templateName).getFilename()); 190 } else { 191 newBlob.setFilename(sourceTemplateBlob.getFilename()); 192 } 193 194 // mark the file for automatic deletion on GC 195 Framework.trackFile(generated, newBlob); 196 197 return newBlob; 198 } 199 200 public String readXMLContent(Blob blob) throws IOException { 201 ZipInputStream zIn = new ZipInputStream(blob.getStream()); 202 ZipEntry zipEntry = zIn.getNextEntry(); 203 String xmlContent = null; 204 while (zipEntry != null) { 205 if (zipEntry.getName().equals("content.xml")) { 206 StringBuilder sb = new StringBuilder(); 207 byte[] buffer = new byte[BUFFER_SIZE]; 208 int read; 209 while ((read = zIn.read(buffer)) != -1) { 210 sb.append(new String(buffer, 0, read)); 211 } 212 xmlContent = sb.toString(); 213 break; 214 } 215 zipEntry = zIn.getNextEntry(); 216 } 217 zIn.close(); 218 return xmlContent; 219 } 220 221}