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}