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.jxls;
020
021import java.io.BufferedInputStream;
022import java.io.BufferedOutputStream;
023import java.io.File;
024import java.io.FileInputStream;
025import java.io.FileOutputStream;
026import java.io.IOException;
027import java.io.InputStream;
028import java.io.OutputStream;
029import java.util.ArrayList;
030import java.util.List;
031import java.util.Map;
032
033import net.sf.jxls.exception.ParsePropertyException;
034import net.sf.jxls.transformer.XLSTransformer;
035
036import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
037import org.jxls.common.Context;
038import org.jxls.util.JxlsHelper;
039import org.nuxeo.common.utils.FileUtils;
040import org.nuxeo.ecm.core.api.Blob;
041import org.nuxeo.ecm.core.api.Blobs;
042import org.nuxeo.ecm.core.api.DocumentModel;
043import org.nuxeo.ecm.core.api.NuxeoException;
044import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry;
045import org.nuxeo.runtime.api.Framework;
046import org.nuxeo.runtime.services.config.ConfigurationService;
047import org.nuxeo.template.api.TemplateInput;
048import org.nuxeo.template.api.TemplateProcessor;
049import org.nuxeo.template.api.adapters.TemplateBasedDocument;
050import org.nuxeo.template.context.SimpleContextBuilder;
051import org.nuxeo.template.processors.AbstractTemplateProcessor;
052
053/**
054 * JXLS {@link TemplateProcessor}
055 *
056 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a>
057 */
058public class JXLSTemplateProcessor extends AbstractTemplateProcessor {
059
060    public static final String TEMPLATE_TYPE = "JXLS";
061
062    /**
063     * Configuration property to use the old JXLS 1 instead of JXLS 2.
064     *
065     * @since 11.1
066     */
067    public static final String USE_JXLS1_CONFIG_PROP = "org.nuxeo.template.rendering.jxls1";
068
069    protected SimpleContextBuilder contextBuilder = new SimpleContextBuilder();
070
071    protected boolean useJXLS1() {
072        return Framework.getService(ConfigurationService.class).isBooleanTrue(USE_JXLS1_CONFIG_PROP);
073    }
074
075    @Override
076    public Blob renderTemplate(TemplateBasedDocument templateBasedDocument, String templateName) throws IOException {
077
078        Blob sourceTemplateBlob = getSourceTemplateBlob(templateBasedDocument, templateName);
079        List<TemplateInput> params = templateBasedDocument.getParams(templateName);
080
081        DocumentModel doc = templateBasedDocument.getAdaptedDoc();
082        Map<String, Object> ctx = contextBuilder.build(doc, templateName);
083
084        JXLSBindingResolver resolver = new JXLSBindingResolver();
085
086        resolver.resolve(params, ctx, templateBasedDocument);
087
088        File workingDir = getWorkingDir();
089        File generated = new File(workingDir, "JXLSresult-" + System.currentTimeMillis());
090        generated.createNewFile();
091
092        File input = new File(workingDir, "JXLSInput-" + System.currentTimeMillis());
093        input.createNewFile();
094
095        sourceTemplateBlob.transferTo(input);
096
097        if (useJXLS1()) {
098            XLSTransformer transformer = new XLSTransformer();
099            configureTransformer(transformer);
100            try {
101                transformer.transformXLS(input.getAbsolutePath(), ctx, generated.getAbsolutePath());
102            } catch (InvalidFormatException | ParsePropertyException e) {
103                throw new NuxeoException(e);
104            }
105        } else {
106            try (InputStream is = new BufferedInputStream(new FileInputStream(input));
107                    OutputStream os = new BufferedOutputStream(new FileOutputStream(generated))) {
108                JxlsHelper.getInstance().processTemplate(is, os, new Context(ctx));
109            } catch (IllegalStateException | IOException e) {
110                throw new NuxeoException(e);
111            }
112        }
113
114        input.delete();
115
116        Blob newBlob = Blobs.createBlob(generated);
117
118        String templateFileName = sourceTemplateBlob.getFilename();
119
120        // set the output file name
121        String targetFileExt = FileUtils.getFileExtension(templateFileName);
122        String targetFileName = FileUtils.getFileNameNoExt(templateBasedDocument.getAdaptedDoc().getTitle());
123        targetFileName = targetFileName + "." + targetFileExt;
124        newBlob.setFilename(targetFileName);
125        MimetypeRegistry mimetypeRegistry = Framework.getService(MimetypeRegistry.class);
126        newBlob.setMimeType(mimetypeRegistry.getMimetypeFromExtension(targetFileExt));
127
128        // mark the file for automatic deletion on GC
129        Framework.trackFile(generated, newBlob);
130        return newBlob;
131
132    }
133
134    protected void configureTransformer(XLSTransformer transformer) {
135        // NOP but subclass may use this to register a CellProcessor or a
136        // RowProcessor
137    }
138
139    @Override
140    public List<TemplateInput> getInitialParametersDefinition(Blob blob) {
141        return new ArrayList<>();
142    }
143
144}