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:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
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.
24 package org.collectionspace.services.report.nuxeo;
27 import java.io.FileInputStream;
28 import java.io.FileNotFoundException;
29 import java.sql.Connection;
30 import java.sql.SQLException;
31 import java.util.HashMap;
32 import java.util.List;
34 import javax.naming.NamingException;
35 import javax.ws.rs.WebApplicationException;
36 import javax.ws.rs.core.Response;
38 import net.sf.jasperreports.engine.JRException;
39 import net.sf.jasperreports.engine.JasperExportManager;
40 import net.sf.jasperreports.engine.JasperFillManager;
41 import net.sf.jasperreports.engine.JasperPrint;
43 import org.collectionspace.services.ReportJAXBSchema;
44 import org.collectionspace.services.report.ReportResource;
45 import org.collectionspace.services.report.ReportsCommon;
46 import org.collectionspace.services.client.PoxPayloadIn;
47 import org.collectionspace.services.client.PoxPayloadOut;
48 import org.collectionspace.services.common.ResourceMap;
49 import org.collectionspace.services.common.ServiceMain;
50 import org.collectionspace.services.common.ServiceMessages;
51 import org.collectionspace.services.common.config.ConfigReader;
52 import org.collectionspace.services.common.context.ServiceContext;
53 import org.collectionspace.services.common.document.BadRequestException;
54 import org.collectionspace.services.common.document.DocumentException;
55 import org.collectionspace.services.common.document.DocumentWrapper;
56 import org.collectionspace.services.common.invocable.Invocable;
57 import org.collectionspace.services.common.invocable.InvocationContext;
58 import org.collectionspace.services.common.storage.JDBCTools;
59 import org.collectionspace.services.jaxb.InvocableJAXBSchema;
60 import org.collectionspace.services.nuxeo.client.java.DocHandlerBase;
61 import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
62 import org.nuxeo.ecm.core.api.DocumentModel;
63 import org.nuxeo.ecm.core.api.model.PropertyException;
64 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
69 * ReportDocumentModelHandler
71 * $LastChangedRevision: $
74 public class ReportDocumentModelHandler extends DocHandlerBase<ReportsCommon> {
75 private final Logger logger = LoggerFactory.getLogger(ReportDocumentModelHandler.class);
76 private static String REPOSITORY_NAME = JDBCTools.NUXEO_REPOSITORY_NAME;
77 private static String REPORTS_FOLDER = "reports";
78 private static String CSID_LIST_SEPARATOR = ",";
80 private static String REPORTS_STD_CSID_PARAM = "csid";
81 private static String REPORTS_STD_GROUPCSID_PARAM = "groupcsid";
82 private static String REPORTS_STD_CSIDLIST_PARAM = "csidlist";
83 private static String REPORTS_STD_TENANTID_PARAM = "tenantid";
85 public Response invokeReport(
86 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
88 InvocationContext invContext) throws Exception {
89 RepositoryInstance repoSession = null;
90 boolean releaseRepoSession = false;
92 String invocationMode = invContext.getMode();
93 String modeProperty = null;
94 HashMap<String, Object> params = new HashMap<String, Object>();
95 params.put(REPORTS_STD_TENANTID_PARAM, ctx.getTenantId());
96 boolean checkDocType = true;
97 if(Invocable.INVOCATION_MODE_SINGLE.equalsIgnoreCase(invocationMode)) {
98 modeProperty = InvocableJAXBSchema.SUPPORTS_SINGLE_DOC;
99 params.put(REPORTS_STD_CSID_PARAM, invContext.getSingleCSID());
100 } else if(Invocable.INVOCATION_MODE_LIST.equalsIgnoreCase(invocationMode)) {
101 modeProperty = InvocableJAXBSchema.SUPPORTS_DOC_LIST;
102 List<String> csids = null;
103 InvocationContext.ListCSIDs listThing = invContext.getListCSIDs();
104 if(listThing!=null) {
105 csids = listThing.getCsid();
107 if(csids==null||csids.isEmpty()){
108 throw new BadRequestException(
109 "ReportResource: Report invoked in list mode, with no csids in list." );
111 StringBuilder sb = new StringBuilder();
112 boolean first = true;
113 for(String csidItem : csids) {
117 sb.append(CSID_LIST_SEPARATOR);
120 params.put(REPORTS_STD_CSIDLIST_PARAM, sb.toString());
121 } else if(Invocable.INVOCATION_MODE_GROUP.equalsIgnoreCase(invocationMode)) {
122 modeProperty = InvocableJAXBSchema.SUPPORTS_GROUP;
123 params.put(REPORTS_STD_GROUPCSID_PARAM, invContext.getGroupCSID());
124 } else if(Invocable.INVOCATION_MODE_NO_CONTEXT.equalsIgnoreCase(invocationMode)) {
125 modeProperty = InvocableJAXBSchema.SUPPORTS_NO_CONTEXT;
126 checkDocType = false;
128 throw new BadRequestException("ReportResource: unknown Invocation Mode: "
132 RepositoryJavaClientImpl repoClient = (RepositoryJavaClientImpl)this.getRepositoryClient(ctx);
133 repoSession = this.getRepositorySession();
134 if (repoSession == null) {
135 repoSession = repoClient.getRepositorySession();
136 releaseRepoSession = true;
139 String reportFileName = null;
140 // Get properties from the batch docModel, and release the session
142 DocumentWrapper<DocumentModel> wrapper = repoClient.getDoc(repoSession, ctx, csid);
143 DocumentModel docModel = wrapper.getWrappedObject();
144 Boolean supports = (Boolean)docModel.getPropertyValue(modeProperty);
145 if(supports == null || !supports) {
146 throw new BadRequestException(
147 "ReportResource: This Report does not support Invocation Mode: "
151 List<String> forDocTypeList =
152 (List<String>)docModel.getPropertyValue(InvocableJAXBSchema.FOR_DOC_TYPES);
153 if(forDocTypeList==null
154 || !forDocTypeList.contains(invContext.getDocType())) {
155 throw new BadRequestException(
156 "ReportResource: Invoked with unsupported document type: "
157 +invContext.getDocType());
160 reportFileName = (String)docModel.getPropertyValue(ReportJAXBSchema.FILENAME);
161 } catch (PropertyException pe) {
162 if (logger.isDebugEnabled()) {
163 logger.debug("Property exception getting batch values: ", pe);
166 } catch (DocumentException de) {
167 if (logger.isDebugEnabled()) {
168 logger.debug("Problem getting batch doc: ", de);
171 } catch (Exception e) {
172 if (logger.isDebugEnabled()) {
173 logger.debug("Caught exception ", e);
175 throw new DocumentException(e);
177 if (releaseRepoSession && repoSession != null) {
178 repoClient.releaseRepositorySession(repoSession);
181 return buildReportResponse(csid, params, reportFileName);
185 private Response buildReportResponse(String reportCSID, HashMap<String, Object> params, String reportFileName)
187 Connection conn = null;
188 Response response = null;
190 String fullPath = ServiceMain.getInstance().getServerRootDir() +
191 File.separator + ConfigReader.CSPACE_DIR_NAME +
192 File.separator + REPORTS_FOLDER +
193 // File.separator + tenantName +
194 File.separator + reportFileName;
195 conn = getConnection();
197 if (logger.isTraceEnabled()) {
198 logger.trace("ReportResource for Report csid=" + reportCSID
199 +" opening report file: "+fullPath);
201 FileInputStream fileStream = new FileInputStream(fullPath);
204 JasperPrint jasperprint = JasperFillManager.fillReport(fileStream, params,conn);
205 // export report to pdf and build a response with the bytes
206 byte[] pdfasbytes = JasperExportManager.exportReportToPdf(jasperprint);
208 // Need to set response type for what is requested...
209 response = Response.ok(pdfasbytes, "application/pdf").build();
212 } catch (SQLException sqle) {
213 // SQLExceptions can be chained. We have at least one exception, so
214 // set up a loop to make sure we let the user know about all of them
215 // if there happens to be more than one.
216 if (logger.isDebugEnabled()) {
217 SQLException tempException = sqle;
218 while (null != tempException) {
219 logger.debug("SQL Exception: " + sqle.getLocalizedMessage());
221 // loop to the next exception
222 tempException = tempException.getNextException();
225 response = Response.status(
226 Response.Status.INTERNAL_SERVER_ERROR).entity(
227 "Invoke failed (SQL problem) on Report csid=" + reportCSID).type("text/plain").build();
228 throw new WebApplicationException(response);
229 } catch (JRException jre) {
230 if (logger.isDebugEnabled()) {
231 logger.debug("JR Exception: " + jre.getLocalizedMessage() + " Cause: "+jre.getCause());
233 response = Response.status(
234 Response.Status.INTERNAL_SERVER_ERROR).entity(
235 "Invoke failed (Jasper problem) on Report csid=" + reportCSID).type("text/plain").build();
236 throw new WebApplicationException(response);
237 } catch (FileNotFoundException fnfe) {
238 if (logger.isDebugEnabled()) {
239 logger.debug("FileNotFoundException: " + fnfe.getLocalizedMessage());
241 response = Response.status(
242 Response.Status.INTERNAL_SERVER_ERROR).entity(
243 "Invoke failed (SQL problem) on Report csid=" + reportCSID).type("text/plain").build();
244 throw new WebApplicationException(response);
249 } catch (SQLException sqle) {
250 // SQLExceptions can be chained. We have at least one exception, so
251 // set up a loop to make sure we let the user know about all of them
252 // if there happens to be more than one.
253 if (logger.isDebugEnabled()) {
254 logger.debug("SQL Exception closing connection: "
255 + sqle.getLocalizedMessage());
257 } catch (Exception e) {
258 if (logger.isDebugEnabled()) {
259 logger.debug("Exception closing connection", e);
266 private Connection getConnection() throws NamingException, SQLException {
267 return JDBCTools.getConnection(REPOSITORY_NAME);