]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
426014e4637fc61b78cfeaba05b66987e5f88959
[tmp/jakarta-migration.git] /
1 /**
2  *  This document is a part of the source code and related artifacts
3  *  for CollectionSpace, an open source collections management system
4  *  for museums and related institutions:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
18  *  Unless required by applicable law or agreed to in writing, software
19  *  distributed under the License is distributed on an "AS IS" BASIS,
20  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  *  See the License for the specific language governing permissions and
22  *  limitations under the License.
23  */
24 package org.collectionspace.services.report.nuxeo;
25
26 import java.io.ByteArrayOutputStream;
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileNotFoundException;
30 import java.sql.Connection;
31 import java.sql.SQLException;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35
36 import javax.ws.rs.core.MediaType;
37 import javax.ws.rs.core.Response.ResponseBuilder;
38
39 import javax.naming.NamingException;
40 import javax.ws.rs.WebApplicationException;
41 import javax.ws.rs.core.Response;
42
43 import net.sf.jasperreports.engine.JRException;
44 import net.sf.jasperreports.engine.JRExporter;
45 import net.sf.jasperreports.engine.JRExporterParameter;
46 import net.sf.jasperreports.engine.JRParameter;
47 import net.sf.jasperreports.engine.JasperExportManager;
48 import net.sf.jasperreports.engine.JasperFillManager;
49 import net.sf.jasperreports.engine.JasperPrint;
50 import net.sf.jasperreports.engine.export.JRCsvExporter;
51 import net.sf.jasperreports.engine.export.JRCsvExporterParameter;
52 import net.sf.jasperreports.engine.export.JRHtmlExporter;
53 import net.sf.jasperreports.engine.export.JRPdfExporter;
54 import net.sf.jasperreports.engine.export.JRXmlExporter;
55
56 import org.collectionspace.services.ReportJAXBSchema;
57 import org.collectionspace.services.report.ReportsCommon;
58 import org.collectionspace.services.client.PoxPayloadIn;
59 import org.collectionspace.services.client.PoxPayloadOut;
60 import org.collectionspace.services.client.ReportClient;
61 import org.collectionspace.services.common.ServiceMain;
62 import org.collectionspace.services.common.api.Tools;
63 import org.collectionspace.services.common.config.ConfigReader;
64 import org.collectionspace.services.common.context.ServiceContext;
65 import org.collectionspace.services.common.document.BadRequestException;
66 import org.collectionspace.services.common.document.DocumentException;
67 import org.collectionspace.services.common.document.DocumentWrapper;
68 import org.collectionspace.services.common.invocable.Invocable;
69 import org.collectionspace.services.common.invocable.InvocationContext;
70 import org.collectionspace.services.common.storage.JDBCTools;
71 import org.collectionspace.services.jaxb.InvocableJAXBSchema;
72 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
73 import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
74 import org.jfree.util.Log;
75 import org.nuxeo.ecm.core.api.DocumentModel;
76 import org.nuxeo.ecm.core.api.model.PropertyException;
77 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81 /**
82  * ReportDocumentModelHandler
83  *
84  * $LastChangedRevision: $
85  * $LastChangedDate: $
86  */
87 public class ReportDocumentModelHandler extends DocHandlerBase<ReportsCommon> {
88     private final Logger logger = LoggerFactory.getLogger(ReportDocumentModelHandler.class);
89     private static String REPORTS_FOLDER = "reports";
90     private static String CSID_LIST_SEPARATOR = ",";
91     
92     private static String REPORTS_STD_CSID_PARAM = "csid";
93     private static String REPORTS_STD_GROUPCSID_PARAM = "groupcsid";
94     private static String REPORTS_STD_CSIDLIST_PARAM = "csidlist";
95     private static String REPORTS_STD_TENANTID_PARAM = "tenantid";
96         
97         public Response invokeReport(
98                         ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
99                         String csid,
100                         InvocationContext invContext) throws Exception {
101                 RepositoryInstance repoSession = null;
102                 boolean releaseRepoSession = false;
103
104                 String invocationMode = invContext.getMode();
105                 String modeProperty = null;
106                 String outputMimeType = ReportClient.DEFAULT_REPORT_OUTPUT_MIME;
107                 HashMap<String, Object> params = new HashMap<String, Object>();
108                 params.put(REPORTS_STD_TENANTID_PARAM, ctx.getTenantId());
109                 boolean checkDocType = true;
110                 
111                 // Note we set before we put in the default ones, so they cannot override tenant or CSID.
112                 setParamsFromContext(params, invContext);
113                 
114                 if(Invocable.INVOCATION_MODE_SINGLE.equalsIgnoreCase(invocationMode)) {
115                         modeProperty = InvocableJAXBSchema.SUPPORTS_SINGLE_DOC;
116                 params.put(REPORTS_STD_CSID_PARAM, invContext.getSingleCSID());
117                 } else if(Invocable.INVOCATION_MODE_LIST.equalsIgnoreCase(invocationMode)) {
118                         modeProperty = InvocableJAXBSchema.SUPPORTS_DOC_LIST;
119                         List<String> csids = null;
120                         InvocationContext.ListCSIDs listThing = invContext.getListCSIDs();
121                                 if(listThing!=null) {
122                                         csids = listThing.getCsid();
123                                 }
124                                 if(csids==null||csids.isEmpty()){
125                                 throw new BadRequestException(
126                                                 "ReportResource: Report invoked in list mode, with no csids in list." );
127                                 }
128                                 StringBuilder sb = new StringBuilder();
129                                 boolean first = true;
130                                 for(String csidItem : csids) {
131                                         if(first)
132                                                 first = false;
133                                         else
134                                                 sb.append(CSID_LIST_SEPARATOR);
135                                         sb.append(csidItem);
136                                 }
137                 params.put(REPORTS_STD_CSIDLIST_PARAM, sb.toString());
138                 } else if(Invocable.INVOCATION_MODE_GROUP.equalsIgnoreCase(invocationMode)) {
139                         modeProperty = InvocableJAXBSchema.SUPPORTS_GROUP;
140                 params.put(REPORTS_STD_GROUPCSID_PARAM, invContext.getGroupCSID());
141                 } else if(Invocable.INVOCATION_MODE_NO_CONTEXT.equalsIgnoreCase(invocationMode)) {
142                         modeProperty = InvocableJAXBSchema.SUPPORTS_NO_CONTEXT;
143                         checkDocType = false;
144                 } else {
145                         throw new BadRequestException("ReportResource: unknown Invocation Mode: "
146                                 +invocationMode);
147                 }
148                 
149                 
150                 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
151                 repoSession = this.getRepositorySession();
152                 if (repoSession == null) {
153                         repoSession = repoClient.getRepositorySession(ctx);
154                         releaseRepoSession = true;
155                 }
156
157                 String reportFileName = null;
158                 // Get properties from the batch docModel, and release the session
159                 try {
160                         DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, csid);
161                         DocumentModel docModel = wrapper.getWrappedObject();
162                         Boolean supports = (Boolean)docModel.getPropertyValue(modeProperty);
163                         if(supports == null || !supports) {
164                                 throw new BadRequestException(
165                                                 "ReportResource: This Report does not support Invocation Mode: "
166                                         +invocationMode);
167                         }
168                 if(checkDocType) {
169                         List<String> forDocTypeList = 
170                                 (List<String>)docModel.getPropertyValue(InvocableJAXBSchema.FOR_DOC_TYPES);
171                         if(forDocTypeList==null
172                                         || !forDocTypeList.contains(invContext.getDocType())) {
173                                 throw new BadRequestException(
174                                                 "ReportResource: Invoked with unsupported document type: "
175                                                 +invContext.getDocType());
176                         }
177                 }
178                         reportFileName = (String)docModel.getPropertyValue(ReportJAXBSchema.FILENAME);
179                         String reportOutputMime = (String)docModel.getPropertyValue(ReportJAXBSchema.OUTPUT_MIME);
180                         if(!Tools.isEmpty(reportOutputMime)) {
181                                 outputMimeType = reportOutputMime;
182                         }
183                 } catch (PropertyException pe) {
184                         if (logger.isDebugEnabled()) {
185                                 logger.debug("Property exception getting batch values: ", pe);
186                         }
187                         throw pe;
188                 } catch (DocumentException de) {
189                         if (logger.isDebugEnabled()) {
190                                 logger.debug("Problem getting batch doc: ", de);
191                         }
192                         throw de;
193                 } catch (Exception e) {
194                         if (logger.isDebugEnabled()) {
195                                 logger.debug("Caught exception ", e);
196                         }
197                         throw new DocumentException(e);
198                 } finally {
199                         if (releaseRepoSession && repoSession != null) {
200                                 repoClient.releaseRepositorySession(ctx, repoSession);
201                         }
202                 }
203         return buildReportResponse(csid, params, reportFileName, outputMimeType);
204         }
205         
206         private void setParamsFromContext(Map<String, Object> params, InvocationContext invContext) {
207                 InvocationContext.Params icParams = invContext.getParams();
208                 if(icParams!= null) {
209                         List<InvocationContext.Params.Param> icParamList = icParams.getParam();
210                         if(icParamList != null) {
211                                 for(InvocationContext.Params.Param param:icParamList) {
212                                         String key = param.getKey();
213                                         String value = param.getValue();
214                                         if(!Tools.isEmpty(key) && !Tools.isEmpty(value)) {
215                                                 params.put(key, value);
216                                         }
217                                 }
218                         }
219                 }
220                 
221         }
222
223
224
225     private Response buildReportResponse(String reportCSID, 
226                 HashMap<String, Object> params, String reportFileName, String outputMimeType)
227                                 throws Exception {
228                 Connection conn = null;
229                 Response response = null;
230         try {
231                         String fullPath = ServiceMain.getInstance().getServerRootDir() +
232                                                                 File.separator + ConfigReader.CSPACE_DIR_NAME + 
233                                                                 File.separator + REPORTS_FOLDER +
234                                                                 // File.separator + tenantName +
235                                                                 File.separator + reportFileName;
236                         conn = getConnection();
237         
238             if (logger.isTraceEnabled()) {
239                 logger.trace("ReportResource for csid=" + reportCSID
240                                 +" output as "+outputMimeType+" using report file: "+fullPath);
241             }
242                         FileInputStream fileStream = new FileInputStream(fullPath);
243         
244                         // export report to pdf and build a response with the bytes
245                         //JasperExportManager.exportReportToPdf(jasperprint);
246                         
247                         // Report will be to a byte output array.
248                         ByteArrayOutputStream baos = new ByteArrayOutputStream();
249
250                         JRExporter exporter = null;
251                         // Strip extension from report filename.
252                         String outputFilename = reportFileName;
253                         // Strip extension from report filename.
254                         int idx = outputFilename.lastIndexOf("."); 
255                         if(idx>0)
256                                 outputFilename = outputFilename.substring(0, idx);
257                         // Strip any sub-dir from report filename.
258                         idx = outputFilename.lastIndexOf(File.separator); 
259                         if(idx>0)
260                                 outputFilename = outputFilename.substring(idx+1);
261                         if(outputMimeType.equals(MediaType.APPLICATION_XML)) {
262                                 params.put(JRParameter.IS_IGNORE_PAGINATION, Boolean.TRUE);
263                                 exporter = new JRXmlExporter();
264                                 outputFilename = outputFilename+".xml";
265                         } else if(outputMimeType.equals(MediaType.TEXT_HTML)) {
266                                 exporter = new JRHtmlExporter();
267                                 outputFilename = outputFilename+".html";
268                         } else if(outputMimeType.equals(ReportClient.PDF_MIME_TYPE)) {
269                                 exporter = new JRPdfExporter();
270                                 outputFilename = outputFilename+".pdf";
271                         } else if(outputMimeType.equals(ReportClient.CSV_MIME_TYPE)) {
272                                 params.put(JRParameter.IS_IGNORE_PAGINATION, Boolean.TRUE);
273                                 exporter = new JRCsvExporter();
274                                 exporter.setParameter(JRCsvExporterParameter.FIELD_DELIMITER, ",");
275                                 outputFilename = outputFilename+".csv";
276                         } else if(outputMimeType.equals(ReportClient.TSV_MIME_TYPE)) {
277                                 params.put(JRParameter.IS_IGNORE_PAGINATION, Boolean.TRUE);
278                                 exporter = new JRCsvExporter();
279                                 exporter.setParameter(JRCsvExporterParameter.FIELD_DELIMITER, "\t");
280                                 outputFilename = outputFilename+".csv";
281                         }
282                 // fill the report
283                         JasperPrint jasperPrint = JasperFillManager.fillReport(fileStream, params,conn);
284                                 
285                         exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
286                         exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
287                         exporter.exportReport();
288                         byte[] reportAsBytes = baos.toByteArray();
289
290                         // Need to set response type for what is requested...
291                         ResponseBuilder builder = Response.ok(reportAsBytes, outputMimeType);
292                         builder = builder.header("Content-Disposition","inline;filename=\""+outputFilename+"\"");
293                 response = builder.build();
294         
295                 return response;        
296         } catch (SQLException sqle) {
297             // SQLExceptions can be chained. We have at least one exception, so
298             // set up a loop to make sure we let the user know about all of them
299             // if there happens to be more than one.
300             if (logger.isDebugEnabled()) {
301                     SQLException tempException = sqle;
302                     while (null != tempException) {
303                                 logger.debug("SQL Exception: " + sqle.getLocalizedMessage());
304         
305                         // loop to the next exception
306                         tempException = tempException.getNextException();
307                     }
308             }
309             response = Response.status(
310                     Response.Status.INTERNAL_SERVER_ERROR).entity(
311                                 "Invoke failed (SQL problem) on Report csid=" + reportCSID).type("text/plain").build();
312             throw new WebApplicationException(response);
313         } catch (JRException jre) {
314             if (logger.isDebugEnabled()) {
315                 logger.debug("JR Exception: " + jre.getLocalizedMessage() + " Cause: "+jre.getCause());
316             }
317             response = Response.status(
318                     Response.Status.INTERNAL_SERVER_ERROR).entity(
319                                 "Invoke failed (Jasper problem) on Report csid=" + reportCSID).type("text/plain").build();
320             throw new WebApplicationException(response);
321         } catch (FileNotFoundException fnfe) {
322             if (logger.isDebugEnabled()) {
323                 logger.debug("FileNotFoundException: " + fnfe.getLocalizedMessage());
324             }
325             response = Response.status(
326                     Response.Status.INTERNAL_SERVER_ERROR).entity(
327                                 "Invoke failed (SQL problem) on Report csid=" + reportCSID).type("text/plain").build();
328             throw new WebApplicationException(response);
329                 } finally {
330                 if(conn!=null) {
331                         try {
332                         conn.close();
333                 } catch (SQLException sqle) {
334                     // SQLExceptions can be chained. We have at least one exception, so
335                     // set up a loop to make sure we let the user know about all of them
336                     // if there happens to be more than one.
337                     if (logger.isDebugEnabled()) {
338                                 logger.debug("SQL Exception closing connection: " 
339                                                 + sqle.getLocalizedMessage());
340                     }
341                 } catch (Exception e) {
342                     if (logger.isDebugEnabled()) {
343                         logger.debug("Exception closing connection", e);
344                     }
345                 }
346                 }
347         }
348     }
349
350     private Connection getConnection() throws NamingException, SQLException {
351         Connection result = null;
352         
353         ServiceContext ctx = this.getServiceContext();
354         try {
355                 String repositoryName = ctx.getRepositoryName();
356                 if (repositoryName != null && repositoryName.trim().isEmpty() == false) {
357                         result = JDBCTools.getConnection(JDBCTools.NUXEO_DATASOURCE_NAME, repositoryName);
358                 }
359                 } catch (Exception e) {
360                         Log.error(e);
361                         throw new NamingException();
362                 }
363         
364         return result;
365     }
366
367 }
368