001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2003 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064: package com.jcorporate.expresso.ext.controller;
065:
066: import com.jcorporate.expresso.core.controller.ControllerException;
067: import com.jcorporate.expresso.core.controller.ControllerRequest;
068: import com.jcorporate.expresso.core.controller.ControllerResponse;
069: import com.jcorporate.expresso.core.controller.ErrorCollection;
070: import com.jcorporate.expresso.core.controller.Input;
071: import com.jcorporate.expresso.core.controller.NonHandleableException;
072: import com.jcorporate.expresso.core.controller.ServletControllerRequest;
073: import com.jcorporate.expresso.core.controller.State;
074: import com.jcorporate.expresso.core.controller.Transition;
075: import com.jcorporate.expresso.core.db.DBException;
076: import com.jcorporate.expresso.core.dbobj.Schema;
077: import com.jcorporate.expresso.core.dbobj.SecuredDBObject;
078: import com.jcorporate.expresso.core.dbobj.ValidValue;
079: import com.jcorporate.expresso.ext.report.ExpressoReport;
080: import com.jcorporate.expresso.ext.report.MultiFormatReport;
081: import com.jcorporate.expresso.ext.report.ReportException;
082: import com.jcorporate.expresso.kernel.util.ClassLocator;
083: import com.jcorporate.expresso.services.dbobj.SchemaList;
084: import org.apache.log4j.Logger;
085:
086: import javax.servlet.http.HttpServletResponse;
087: import java.util.Iterator;
088: import java.util.Vector;
089:
090: /**
091: * Report server is a generic controller for dishing up reports. It does not
092: * have inherant Report security other than controller security. For
093: * additional features such as built-in JasperReports capabilities (and thus
094: * the ability to send output in CSV, XML, Excel, Html, or PDF formats], built
095: * in Report-by-report security and save on server features, consider
096: * JCorporate's eContent commercial content management framework. See <a
097: * href="http://www.jcorporate.com/econtent.html" target="_blank">
098: * http://www.jcorporate.com/econtent.html</a> for details.
099: * <p/>
100: * <p/>
101: * Todo items include saving the report to a file and then sending that file
102: * instead so that we can set the content length so items like the pdf files
103: * work work properly in IE.
104: * </p>
105: *
106: * @author Michael Rimov
107: */
108: public class ReportServer extends
109: com.jcorporate.expresso.core.controller.DBController {
110:
111: /**
112: * The Log4j Logger
113: */
114: public static final transient Logger log = Logger
115: .getLogger(ReportServer.class);
116:
117: /**
118: * Creates an instance of ReportServer. Call setRequestingUid() and
119: * setDataContext() before using.
120: *
121: * @throws ControllerException upon initialization Exception
122: * @see com.jcorporate.expresso.core.dbobj.SecuredDBObject#SecuredDBObject
123: */
124: public ReportServer() throws ControllerException {
125: super ();
126:
127: State s = new State("prompt", "Prompt");
128: this .addState(s);
129: this .setInitialState("prompt");
130:
131: s = new State("selectReport", "Select Report");
132: s.addRequiredParameter("SchemaClass");
133: this .addState(s);
134:
135: s = new State("setParameters", "Set Report Parameters");
136: s.addRequiredParameter("ReportClass");
137: s.addOptionalParameter("ReportCode");
138: this .addState(s);
139:
140: s = new State("processReport", "Process Report");
141: s.addRequiredParameter("ReportClass");
142: s.addOptionalParameter("ReportCode");
143: s.addOptionalParameter("ReportFormat");
144: this .addState(s);
145: }
146:
147: /**
148: * Override of Controller.getTitle() to provide a meaningful name to this
149: * controller
150: *
151: * @return java.lang.String
152: */
153: public String getTitle() {
154: return "Expresso Report Server";
155: }
156:
157: /**
158: * Instantiate an Expresso report based upon the 'ReportClass' parameter
159: * given in the ControllerRequest object
160: *
161: * @param request a ControllerRequest object with the 'ReportClass'
162: * parameter included.
163: * @return An ExpressoReport object fully instantiated
164: * @throws ControllerException upon instantiation exception
165: * @throws ClassNotFoundException for special handling by the calling
166: * object if the class was not found.
167: */
168: protected ExpressoReport instantiateReport(ControllerRequest request)
169: throws ControllerException, ClassNotFoundException {
170: String reportClass = request.getParameter("ReportClass");
171:
172: ExpressoReport report = null;
173:
174: try {
175: report = (ExpressoReport) ClassLocator.loadClass(
176: reportClass).newInstance();
177: } catch (IllegalAccessException ex) {
178: throw new ControllerException(
179: "No public default constructor found in class: "
180: + reportClass, ex);
181: } catch (InstantiationException ex) {
182: throw new ControllerException(
183: "Unable to construct new instance of object: "
184: + reportClass, ex);
185: } catch (ClassCastException ex) {
186: throw new ControllerException("Class Requested: "
187: + reportClass + " was not an Expresso Report", ex);
188: }
189:
190: return report;
191: }
192:
193: /**
194: * Process the actual report.
195: *
196: * @param request The <code>ControllerRequest</code> object handed to us by
197: * the framework.
198: * @param response The <code>ControllerResponse</code> object handed to us
199: * by the framework.
200: * @throws ControllerException upon error
201: * @throws NonHandleableException upon fatal error
202: */
203: protected void runProcessReportState(ControllerRequest request,
204: ControllerResponse response) throws ControllerException,
205: NonHandleableException {
206: try {
207: ExpressoReport report = instantiateReport(request);
208: java.util.Map paramMap = new java.util.HashMap(request
209: .getParameters());
210: report.setReportParameters(paramMap);
211: report.setDataContext(request.getDataContext());
212: report.setReportCode(request.getParameter("ReportCode"));
213:
214: if (report instanceof MultiFormatReport) {
215: ((MultiFormatReport) report).setReportFormat(request
216: .getParameter("ReportFormat"));
217: }
218:
219: if (!(request instanceof ServletControllerRequest)) {
220: response.addError("To run the report, report server "
221: + "must be run inside a Servlet environment");
222: transition("prompt", request, response);
223:
224: return;
225: }
226:
227: ServletControllerRequest scr = (ServletControllerRequest) request;
228: response.setCustomResponse(true);
229:
230: HttpServletResponse servResponse = scr
231: .getHttpServletResponse();
232:
233: servResponse.setHeader("Content-Disposition",
234: "inline;filename=" + "ExpressoReport."
235: + report.getReportFileExtension());
236:
237: servResponse.setContentType(report.getReportMimeType());
238:
239: java.io.OutputStream os = servResponse.getOutputStream();
240: report.printReport(os);
241:
242: return;
243: } catch (ClassNotFoundException ex) {
244: ErrorCollection errs = new ErrorCollection();
245: log.error("Error, class not found: ", ex);
246: errs.addError("Class specified not found");
247: response.saveErrors(errs);
248: transition("prompt", request, response);
249: } catch (ReportException ex) {
250: log.error("Report exception: ", ex);
251: throw new ControllerException("Error processing report", ex);
252: } catch (java.io.IOException ex) {
253: log.warn("IO Exception sending report", ex);
254: }
255: }
256:
257: /**
258: * Runs the Prompt state
259: *
260: * @param request The <code>ControllerRequest</code> object handed to us by
261: * the framework.
262: * @param response The <code>ControllerResponse</code> object handed to us
263: * by the framework.
264: * @throws ControllerException upon error
265: * @throws NonHandleableException upon fatal error
266: */
267: protected void runPromptState(ControllerRequest request,
268: ControllerResponse response) throws ControllerException,
269: NonHandleableException {
270: try {
271: /* ..and a schema */
272: Input chooseSchema = new Input();
273: chooseSchema.setLabel("Choose Schema");
274: chooseSchema.setName("SchemaClass");
275:
276: Vector v2 = new Vector(2);
277: v2.addElement(new ValidValue("com.jcorporate.expresso."
278: + "core.ExpressoSchema", "General"));
279:
280: SchemaList sl = new SchemaList(
281: SecuredDBObject.SYSTEM_ACCOUNT);
282: sl.setDataContext(request.getDataContext());
283:
284: SchemaList oneSchema = null;
285:
286: for (Iterator e = sl.searchAndRetrieveList("Descrip")
287: .iterator(); e.hasNext();) {
288: oneSchema = (SchemaList) e.next();
289: v2.addElement(new ValidValue(oneSchema
290: .getField("SchemaClass"), oneSchema
291: .getField("Descrip")));
292: }
293:
294: chooseSchema.setValidValues(v2);
295: response.addInput(chooseSchema);
296:
297: response.add(new Transition("selectReport", this ));
298: response.setTitle("Expresso Report Server");
299: } catch (DBException ex) {
300: log
301: .error(
302: "Database Error Prompting for Report Schemas",
303: ex);
304: throw new ControllerException("Database Access Error", ex);
305: }
306: }
307:
308: /**
309: * Runs the Prompt state
310: *
311: * @param request The <code>ControllerRequest</code> object handed to us by
312: * the framework.
313: * @param response The <code>ControllerResponse</code> object handed to us
314: * by the framework.
315: * @throws ControllerException upon error
316: * @throws NonHandleableException upon fatal error
317: */
318: protected void runSelectReportState(ControllerRequest request,
319: ControllerResponse response) throws ControllerException,
320: NonHandleableException {
321: ErrorCollection ec = request.getErrorCollection();
322:
323: if ((ec != null) && (ec.getErrorCount() > 0)) {
324: response.saveErrors(ec);
325: transition("prompt", request, response);
326:
327: return;
328: }
329:
330: try {
331: //Check that the schema is indeed installed.
332: SchemaList mySchema = new SchemaList(
333: SecuredDBObject.SYSTEM_ACCOUNT);
334: mySchema.setDataContext(request.getDataContext());
335:
336: String schemaClass = com.jcorporate.expresso.core.ExpressoSchema.class
337: .getName();
338: mySchema.setField("SchemaClass", request
339: .getParameter("SchemaClass"));
340:
341: if (mySchema.find()) {
342: schemaClass = request.getParameter("SchemaClass");
343: } else if (!com.jcorporate.expresso.core.ExpressoSchema.class
344: .getName().equals(
345: request.getParameter("SchemaClass"))) {
346: if (ec == null) {
347: ec = new ErrorCollection();
348: }
349:
350: ec.addError("Schema class: "
351: + request.getParameter("SchemaClass")
352: + " is not installed on this system");
353: response.saveErrors(ec);
354: transition("prompt", request, response);
355:
356: return;
357: }
358:
359: Schema schema = (Schema) ClassLocator
360: .loadClass(schemaClass).newInstance();
361: Vector v = schema.getReports();
362:
363: if ((v == null) || (v.size() == 0)) {
364: if (ec == null) {
365: ec = new ErrorCollection();
366: }
367:
368: ec
369: .addError("The requested schema doesn't have any reports defined");
370: response.saveErrors(ec);
371: transition("prompt", request, response);
372:
373: return;
374: }
375:
376: Vector vv = new Vector(v.size());
377:
378: for (Iterator i = v.iterator(); i.hasNext();) {
379: ExpressoReport oneReport = (ExpressoReport) i.next();
380: vv.add(new ValidValue(((Object) oneReport).getClass()
381: .getName(), oneReport.getTitle()));
382: }
383:
384: Input chooseReport = new Input("ReportClass",
385: "Report To Use");
386: chooseReport.setValidValues(vv);
387: response.add(chooseReport);
388:
389: Transition t = new Transition("process", "Continue", this
390: .getClass(), "setParameters");
391: response.add(t);
392: response.setTitle("Expresso Report Server");
393: } catch (DBException ex) {
394: throw new ControllerException("Database access error", ex);
395: } catch (ClassCastException ex) {
396: throw new ControllerException(
397: "Class loaded was not a schema", ex);
398: } catch (ClassNotFoundException ex) {
399: ErrorCollection errs = new ErrorCollection();
400: log.error("Error, class not found: ", ex);
401: errs.addError("Class specified not found");
402: response.saveErrors(errs);
403: transition("prompt", request, response);
404: } catch (IllegalAccessException ex) {
405: throw new ControllerException(
406: "No public default constructor found in class", ex);
407: } catch (InstantiationException ex) {
408: throw new ControllerException(
409: "Unable to construct new instance of object", ex);
410: }
411: }
412:
413: /**
414: * Selects the report output format, if it is a MultiFormatted Report, and
415: * if not, provide a few parameters.
416: *
417: * @param request The <code>ControllerRequest</code> object handed to us by
418: * the framework.
419: * @param response The <code>ControllerResponse</code> object handed to us
420: * by the framework.
421: * @throws ControllerException upon error
422: * @throws NonHandleableException upon fatal error
423: */
424: protected void runSetParametersState(ControllerRequest request,
425: ControllerResponse response) throws ControllerException,
426: NonHandleableException {
427: ErrorCollection ec = request.getErrorCollection();
428:
429: if ((ec != null) && (ec.getErrorCount() > 0)) {
430: response.saveErrors(ec);
431: transition("selectReport", request, response);
432:
433: return;
434: }
435:
436: try {
437: ExpressoReport report = this .instantiateReport(request);
438: String reportClass = ((Object) report).getClass().getName();
439:
440: java.util.List paramNames = report.getParameterNames();
441:
442: if ((paramNames != null) && (paramNames.size() > 0)) {
443: //List all parameters
444: for (Iterator i = paramNames.iterator(); i.hasNext();) {
445: String oneParamName = (String) i.next();
446: Input input = new Input(oneParamName, oneParamName);
447: input.setDefaultValue(report
448: .getDefaultValue(oneParamName));
449: response.add(input);
450: }
451: }
452:
453: Input reportCode = new Input("ReportCode", "Report Code");
454: response.add(reportCode);
455:
456: //Add the dropdowns for format type if available
457: if (report instanceof MultiFormatReport) {
458: java.util.List l = ((MultiFormatReport) report)
459: .getReportFormats();
460: Input reportFormats = new Input("ReportFormat",
461: "Select Output Format");
462: reportFormats.setValidValues(new Vector(l));
463: }
464:
465: Transition t = new Transition("prompt", "Start Again", this
466: .getClass(), "prompt");
467: response.add(t);
468: t = new Transition("process", "Process Report", this
469: .getClass(), "processReport");
470: t.addParam("ReportClass", reportClass);
471: response.add(t);
472: response.setTitle("Expresso Report Server");
473: } catch (ClassNotFoundException ex) {
474: ErrorCollection errs = new ErrorCollection();
475: log.error("Error, class not found: ", ex);
476: errs.addError("Class specified not found");
477: response.saveErrors(errs);
478: transition("prompt", request, response);
479: }
480: }
481: }
|