001/*
002 * (C) Copyright 2006-20011 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.ecm.platform.reporting.jaxrs;
020
021import java.io.File;
022import java.io.FileInputStream;
023import java.io.FileOutputStream;
024import java.io.IOException;
025import java.io.OutputStream;
026import java.io.UnsupportedEncodingException;
027import java.net.URLEncoder;
028import java.util.ArrayList;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033import javax.servlet.http.HttpSession;
034import javax.ws.rs.GET;
035import javax.ws.rs.POST;
036import javax.ws.rs.PathParam;
037import javax.ws.rs.Produces;
038import javax.ws.rs.QueryParam;
039import javax.ws.rs.core.MediaType;
040import javax.ws.rs.core.Response;
041
042import org.eclipse.birt.report.engine.api.HTMLRenderOption;
043import org.eclipse.birt.report.engine.api.HTMLServerImageHandler;
044import org.eclipse.birt.report.engine.api.PDFRenderOption;
045import org.nuxeo.common.utils.Path;
046import org.nuxeo.ecm.core.api.NuxeoException;
047import org.nuxeo.ecm.platform.reporting.api.ReportInstance;
048import org.nuxeo.ecm.platform.reporting.report.ReportParameter;
049import org.nuxeo.ecm.webengine.WebEngine;
050import org.nuxeo.ecm.webengine.forms.FormData;
051import org.nuxeo.ecm.webengine.model.WebObject;
052import org.nuxeo.ecm.webengine.model.impl.DefaultObject;
053
054/**
055 * JAX-RS Resource to represent a {@link ReportInstance}. Provides html and PDF views
056 *
057 * @author Tiry (tdelprat@nuxeo.com)
058 */
059@WebObject(type = "report")
060public class ReportResource extends DefaultObject {
061
062    protected static final String USER_PARAMS_NAME = "birtUserParams";
063
064    protected ReportInstance report;
065
066    @Override
067    protected void initialize(Object... args) {
068        report = (ReportInstance) args[0];
069    }
070
071    @GET
072    @Produces("text/html")
073    public String doGet() {
074        return report.getModel().getReportName();
075    }
076
077    protected String getReportKey() {
078        return report.getDoc().getId() + "-" + getContext().getUserSession().getPrincipal().getName();
079    }
080
081    protected String buildTmpPath(String key) {
082        String dirPath = new Path(System.getProperty("java.io.tmpdir")).append("birt-" + key).toString();
083        File baseDir = new File(dirPath);
084        if (baseDir.exists()) {
085            return dirPath;
086        }
087        baseDir.mkdir();
088        File imagesDir = new File(dirPath + "/images");
089        imagesDir.mkdir();
090
091        return dirPath;
092    }
093
094    @GET
095    @javax.ws.rs.Path("images/{key}/{name}")
096    public Object getImage(@PathParam("key") String key, @PathParam("name") String name) throws IOException {
097
098        String tmpPath = buildTmpPath(key);
099        File imageFile = new File(tmpPath + "/images/" + name);
100        return Response.ok(new FileInputStream(imageFile)).build();
101    }
102
103    @GET
104    @Produces("text/html")
105    @javax.ws.rs.Path("editParams")
106    public Object editParams(@QueryParam("target") String target, @QueryParam("errors") String errors) throws IOException {
107        HttpSession session = WebEngine.getActiveContext().getRequest().getSession();
108        @SuppressWarnings("unchecked")
109        Map<String, Object> userParams = (Map<String, Object>) session.getAttribute(USER_PARAMS_NAME);
110
111        List<ReportParameter> params = report.getReportUserParameters();
112        fillReportParameters(params, userParams);
113        markReportParametersInError(params, errors);
114        return getView("editParams").arg("params", params).arg("target", target);
115    }
116
117    protected void fillReportParameters(List<ReportParameter> reportParameters, Map<String, Object> userParams) {
118        if (userParams != null) {
119            for (ReportParameter p : reportParameters) {
120                if (userParams.containsKey(p.getName())) {
121                    p.setObjectValue(userParams.get(p.getName()));
122                }
123            }
124        }
125    }
126
127    protected void markReportParametersInError(List<ReportParameter> reportParameters, String errors) {
128        if (errors != null) {
129            String[] errs = errors.split(",");
130            for (String err : errs) {
131                if (!err.isEmpty()) {
132                    for (ReportParameter p : reportParameters) {
133                        if (p.getName().equals(err)) {
134                            p.setObjectValue(null);
135                            p.setError(true);
136                            break;
137                        }
138                    }
139                }
140            }
141        }
142    }
143
144    protected void readParams(Map<String, Object> userParams, List<String> paramsInError) throws IOException {
145        List<ReportParameter> params = report.getReportUserParameters();
146        if (params.size() > 0) {
147            FormData data = getContext().getForm();
148            if (data != null) {
149                for (ReportParameter param : params) {
150                    String name = param.getName();
151                    if (data.getString(name) != null) {
152                        String strValue = data.getString(name);
153
154                        if (param.setAndValidateValue(strValue)) {
155                            Object value = param.getObjectValue();
156                            userParams.put(name, value);
157                        } else {
158                            paramsInError.add(name);
159                        }
160                    } else if (!userParams.containsKey(name)) {
161                        paramsInError.add(name);
162                    }
163                }
164            }
165        }
166    }
167
168    @POST
169    @Produces("text/html")
170    @javax.ws.rs.Path("html")
171    public Object editAndRenderHtml() throws IOException {
172        return html(false);
173    }
174
175    protected Object validateInput(Map<String, Object> userParams, String target) throws IOException {
176        HttpSession session = WebEngine.getActiveContext().getRequest().getSession();
177        @SuppressWarnings("unchecked")
178        Map<String, Object> savedUserParams = (Map<String, Object>) session.getAttribute(USER_PARAMS_NAME);
179        if (savedUserParams != null) {
180            userParams.putAll(savedUserParams);
181        }
182
183        List<String> errors = new ArrayList<String>();
184        readParams(userParams, errors);
185        saveUserParameters(userParams);
186
187        if (!errors.isEmpty()) {
188            String errorList = "";
189            for (String err : errors) {
190                errorList = errorList + err + ",";
191            }
192            try {
193                errorList = URLEncoder.encode(errorList, "UTF-8");
194            } catch (UnsupportedEncodingException e) {
195                throw new NuxeoException(e);
196            }
197            return redirect(getPath() + "/editParams?target=" + target + "&errors=" + errorList);
198        }
199        return null;
200    }
201
202    @GET
203    @Produces("text/html")
204    @javax.ws.rs.Path("html")
205    public Object html(@QueryParam("forceFormDisplay") boolean forceFormDisplay) throws IOException {
206        Map<String, Object> userParams = new HashMap<String, Object>();
207        Object validationError = validateInput(userParams, "html");
208
209        if (validationError != null) {
210            return validationError;
211        }
212
213        if (forceFormDisplay) {
214            return redirect(getPath() + "/editParams?target=html");
215        }
216
217        String key = getReportKey();
218        String tmpPath = buildTmpPath(key);
219        File reportFile = new File(tmpPath + "/report");
220        OutputStream out = new FileOutputStream(reportFile);
221
222        HTMLRenderOption options = new HTMLRenderOption();
223        options.setImageHandler(new HTMLServerImageHandler());
224        options.setOutputFormat(HTMLRenderOption.OUTPUT_FORMAT_HTML);
225        options.setOutputStream(out);
226        options.setBaseImageURL("images/" + key);
227        options.setImageDirectory(tmpPath + "/images");
228
229        report.render(options, userParams);
230        return Response.ok(new FileInputStream(reportFile), MediaType.TEXT_HTML).build();
231    }
232
233    protected void saveUserParameters(Map<String, Object> userParams) {
234        HttpSession session = WebEngine.getActiveContext().getRequest().getSession();
235        session.setAttribute(USER_PARAMS_NAME, userParams);
236    }
237
238    @POST
239    @Produces("application/pdf")
240    @javax.ws.rs.Path("pdf")
241    public Object editAndRenderPdf() throws IOException {
242        return pdf(false);
243    }
244
245    @GET
246    @Produces("application/pdf")
247    @javax.ws.rs.Path("pdf")
248    public Object pdf(@QueryParam("forceFormDisplay") boolean forceDisplayForm) throws IOException {
249        Map<String, Object> userParams = new HashMap<String, Object>();
250        Object validationError = validateInput(userParams, "pdf");
251
252        if (validationError != null) {
253            return validationError;
254        }
255
256        if (forceDisplayForm) {
257            return redirect(getPath() + "/editParams?target=pdf");
258        }
259
260        String key = getReportKey();
261        String tmpPath = buildTmpPath(key);
262        File reportFile = new File(tmpPath + "/report");
263        OutputStream out = new FileOutputStream(reportFile);
264
265        PDFRenderOption options = new PDFRenderOption();
266        options.setImageHandler(new HTMLServerImageHandler());
267        options.setOutputFormat(PDFRenderOption.OUTPUT_FORMAT_PDF);
268        options.setOutputStream(out);
269
270        report.render(options, userParams);
271        return Response.ok(new FileInputStream(reportFile), MediaType.APPLICATION_OCTET_STREAM).header(
272                "Content-Disposition", "attachment;filename=" + key + ".pdf").build();
273    }
274
275    @GET
276    @Produces("text/html")
277    @javax.ws.rs.Path("clearParams")
278    public Object clearParams(@QueryParam("target") String target) {
279        HttpSession session = WebEngine.getActiveContext().getRequest().getSession();
280        session.removeAttribute(USER_PARAMS_NAME);
281        return redirect(getPath() + "/editParams?target=" + target);
282    }
283
284}