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