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