View Javadoc

1   /*
2    * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/servlets/reports/AbstractReportServlet.java,v 1.3 2006/03/18 16:01:07 hkollmann Exp $
3    * $Revision: 1.3 $
4    * $Date: 2006/03/18 16:01:07 $
5    *
6    * DbForms - a Rapid Application Development Framework
7    * Copyright (C) 2001 Joachim Peer <joepeer@excite.com>
8    *
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public
11   * License as published by the Free Software Foundation; either
12   * version 2.1 of the License, or (at your option) any later version.
13   *
14   * This library is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22   */
23  
24  package org.dbforms.servlets.reports;
25  
26  
27  import org.apache.commons.lang.StringUtils;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  import org.dbforms.servlets.base.AbstractServletBase;
32  
33  import org.dbforms.config.DbFormsConfig;
34  import org.dbforms.config.DbFormsConfigRegistry;
35  import org.dbforms.config.ResultSetVector;
36  import org.dbforms.config.Table;
37  
38  import org.dbforms.event.AbstractWebEvent;
39  
40  import org.dbforms.taglib.DbFormTag;
41  
42  import org.dbforms.util.MessageResourcesInternal;
43  import org.dbforms.util.PageContextBuffer;
44  import org.dbforms.util.ParseUtil;
45  import org.dbforms.util.Util;
46  import org.dbforms.util.external.FileUtil;
47  
48  import java.io.IOException;
49  import java.io.PrintWriter;
50  
51  import java.util.Collection;
52  import java.util.Iterator;
53  import java.util.Vector;
54  
55  import javax.servlet.ServletContext;
56  import javax.servlet.ServletException;
57  import javax.servlet.ServletOutputStream;
58  import javax.servlet.http.HttpServletRequest;
59  import javax.servlet.http.HttpServletResponse;
60  import javax.servlet.jsp.PageContext;
61  
62  /***
63   * This is the abstract base class for generating reports.
64   * 
65   * @author Henner Kollmann
66   */
67  public abstract class AbstractReportServlet extends AbstractServletBase {
68  
69  	private static Log logCat = LogFactory.getLog(AbstractReportServlet.class
70  			.getName());
71  
72  	private static final String REPORTCONFIGDIR = "reportdirs";
73      private static final String REPORTNAMEPARAM = "reportname";
74  
75  	private String[] reportdirs;
76  
77  
78  	/***
79  	 * Initialize this servlet.
80  	 * 
81  	 * @exception ServletException
82  	 *                if we cannot configure ourselves correctly
83  	 */
84  	public void init() throws ServletException {
85  		super.init();
86        String value = getServletConfig().getInitParameter(REPORTCONFIGDIR);
87  		if (value == null) {
88  			value = "WEB-INF/reports/";
89  		}
90  		reportdirs = StringUtils.split(value, ',');
91  	}
92  
93  	/***
94  	 * generates a report.
95  	 * 
96  	 * @param reportFileFullName
97  	 *            filename of report to process reportHTTPServletRequest
98  	 *            generated by getReportFile! getReportFile should be called
99  	 *            before fetching data, so that error handling of report not
100 	 *            found e.g. could be processed first!
101 	 * @param dataSource
102 	 *            data for the report
103 	 * @param context
104 	 *            ServletContext
105 	 * @param request
106 	 *            HTTPServletRequest
107 	 * @param response
108 	 *            HTTPServletResponse
109 	 */
110 	protected abstract ReportWriter processReport(String reportFileFullName,
111 			AbstractJRDataSource dataSource, ServletContext context,
112 			HttpServletRequest request, HttpServletResponse response);
113 
114 	protected abstract String getReportFileExtension();
115 
116 	protected final void handleException(HttpServletRequest request,
117 			HttpServletResponse response, Exception e) {
118 		sendErrorMessage(request, response, MessageResourcesInternal
119 				.getMessage("dbforms.reports.exception", request.getLocale(),
120 						new String[] { e.getMessage() }));
121 	}
122 
123 	private final void handleNoData(HttpServletRequest request,
124 			HttpServletResponse response) {
125 		sendErrorMessage(request, response, MessageResourcesInternal
126 				.getMessage("dbforms.reports.nodata", request.getLocale()));
127 	}
128 
129 	private final void sendErrorMessage(HttpServletRequest request,
130 			HttpServletResponse response, String message) {
131 		try {
132 			Vector errors = (Vector) request.getAttribute("errors");
133 			
134 			// [20050302 fossato@pow2.com] errors vector can be null; for example if you set
135 			// into your html browser an URL string like:
136 			//
137 			// http://localhost:8080/myContext/reports/
138 			//
139 			// without specifying the name of the report to print;
140 			if (errors == null)
141 			{			 
142 			  errors = new Vector();
143 			}
144 			
145 			errors.add(new Exception(message));
146 						
147 			String fue = ParseUtil.getParameter(request, "source");
148 			String contextPath = request.getContextPath();
149 
150 			if (!Util.isNull(fue)) {
151 				fue = fue.substring(contextPath.length());
152 			}
153 
154 			if (Util.isNull(fue)) {
155 				sendErrorMessageText(response, message);
156 			} else {
157 				request.getRequestDispatcher(fue).forward(request, response);
158 			}
159 		} catch (Exception ex) {
160 			logCat.error("sendErrorMessage", ex);
161 			sendErrorMessageText(response, message);
162 		}
163 	}
164 
165 	protected void compileReport(ServletContext context,
166 			String reportFile) throws Exception {
167 	};
168 
169 	/***
170 	 * generates a report from request. Tries to get data from DbForms.
171 	 * 
172 	 * @param request
173 	 *            HTTPServletRequest
174 	 * @param response
175 	 *            HTTPServletResponse
176 	 */
177 	protected void process(HttpServletRequest request,
178 			HttpServletResponse response) {
179 		// create report name
180 		try {
181 			String reportFile = getReportFileFullName(request.getPathInfo(),
182 					getServletContext(), request, response);
183 
184 			if (!Util.isNull(reportFile)) {
185 				compileReport(getServletContext(), reportFile);
186 				AbstractJRDataSource dataSource = getDataForReport(request, response);
187 				if (!response.isCommitted()) {
188 					if (dataSource == null) {
189 						handleNoData(request, response);
190 					} else {
191 						ReportWriter res = processReport(reportFile,
192 								dataSource, getServletContext(), request,
193 								response);
194 						if (!response.isCommitted()) {
195 							if (res == null) {
196 								handleNoOutput(request, response);
197 							} else {
198 								processOutput(res, request, response);
199 							}
200 						}
201 					}
202 				}
203 			} 
204 		} catch (Exception e) {
205 			logCat.error("process", e);
206 			handleException(request, response, e);
207 		}
208 	}
209 
210 	private void processOutput(ReportWriter out, HttpServletRequest request,
211 			HttpServletResponse response) throws Exception {
212 		if ((out.data == null) && (out.data.size() == 0)) {
213 			handleNoOutput(request, response);
214 			return;
215 		}
216 		response.setHeader("Expires", "0");
217 		response.setHeader("Cache-Control",
218 				"must-revalidate, post-check=0, pre-check=0");
219 		response.setHeader("Pragma", "public");
220 		out.fileName = ParseUtil.getParameter(request, REPORTNAMEPARAM, out.fileName);
221         if (!Util.isNull(out.fileName)) {
222 			response.setHeader("Content-disposition", "inline; filename="
223 					+ out.fileName);
224 		}
225 		if (!Util.isNull(out.mimeType)) {
226 			response.setContentType(out.mimeType);
227 		}
228 		// Send the output stream to the client
229 		response.setContentLength(out.data.size());
230 		ServletOutputStream outputStream = response.getOutputStream();
231 		try {
232 			out.data.writeTo(outputStream);
233 			outputStream.flush();
234 		} finally {
235 			outputStream.close();
236 		}
237 	}
238 
239 	private String getReportFileFullName(String reportFileName,
240 			ServletContext context, HttpServletRequest request,
241 			HttpServletResponse response) {
242 		String reportFile = null;
243 		
244 		try {
245 			boolean found = false;
246 			for (int i = 0; i < reportdirs.length; i++) {
247 				reportFile = context
248 						.getRealPath(reportdirs[i] + reportFileName) ;
249 				String testName = reportFile  + getReportFileExtension();
250 				if (FileUtil.fileExists(testName)) {
251 					found = true;
252 					break;
253 				}
254 			}
255 			if (!found) {
256 				handleNoReport(request, response);
257 				reportFile = null;
258 			}
259 		} catch (Exception e) {
260 			handleException(request, response, e);
261 		}
262 
263 		return reportFile;
264 	}
265 
266 	private void handleNoReport(HttpServletRequest request,
267 			HttpServletResponse response) {
268 		sendErrorMessage(request, response, MessageResourcesInternal
269 				.getMessage("dbforms.reports.noreport", request.getLocale(),
270 						new String[] { request.getPathInfo() }));
271 	}
272 
273 	/***
274 	 * get a JRDataSource for report data. Source can be a Collection, an rsv,
275 	 * or dbform if session variable "jasper.input" is set, it must point to a
276 	 * Collection object if session variable "jasper.rsv" is set, it must point
277 	 * to a ResultSetVector object otherwise the enclosing dbform is used for
278 	 * data
279 	 * 
280 	 * @param context
281 	 * @param request
282 	 * @param response
283 	 * 
284 	 * @return
285 	 */
286 	private AbstractJRDataSource getDataForReport(HttpServletRequest request, HttpServletResponse response) {
287 		AbstractJRDataSource dataSource = null;
288 		Table table = null;
289 		ResultSetVector rsv = null;
290 
291 		try {
292 			// is the datasource a Collection ?
293 			Object input = request.getAttribute("jasper.input");
294 			if (input == null)
295 				input = request.getSession().getAttribute("jasper.input");
296 			if ((input != null) && (input instanceof Collection)) {
297 				Iterator iter = ((Collection) input).iterator();
298 				dataSource = new JRDataSourceIter(null, iter);
299 				return dataSource;
300 			}
301 
302 			// check if we are using a ResultSetVector passed by user
303 			rsv = (ResultSetVector) request.getAttribute("jasper.rsv");
304 			if (rsv == null)
305 				rsv = (ResultSetVector) request.getSession().getAttribute("jasper.rsv");
306 			if (rsv != null) {
307 				logCat.info("get resultsetvector rsv= " + rsv.size());
308 				if (rsv.size() == 0) {
309 					handleNoData(request, response);
310 				} else {
311 					dataSource = new JRDataSourceRSV(rsv.getAttributes(), rsv);
312 				}
313 				return dataSource;
314 			}
315 
316 			PageContext pageContext = new PageContextBuffer();
317 			pageContext
318 					.initialize(this, request, response, null, true, 0, true);
319 
320 			// Create form to get the resultsetvector
321 			AbstractWebEvent webEvent = (AbstractWebEvent) request.getAttribute("webEvent");
322 			table = webEvent.getTable();
323 
324 			if (table == null) {
325 				logCat.error("table==null");
326 			}
327 
328 			if ((webEvent != null) && (table != null) && (table.getId() != -1)) {
329 				// Generate DataSource for JasperReports from call to DbForm
330 				DbFormsConfig config = null;
331 
332 				try {
333 					config = DbFormsConfigRegistry.instance().lookup();
334 				} catch (Exception e) {
335 					logCat.error(e);
336 					throw new ServletException(e);
337 				}
338 
339 				String tableName = config.getTable(webEvent.getTable().getId())
340 						.getName();
341 
342 				// Simulate call to DbFormTag to get resultsetvector
343 				DbFormTag form = new DbFormTag();
344 				form.setPageContext(pageContext);
345 				form.setTableName(tableName);
346 
347 				String maxRows = ParseUtil
348 						.getParameter(request, "maxRows", "*");
349 				form.setMaxRows(maxRows);
350 				form.setFollowUp("");
351 				form.setAutoUpdate("false");
352 				String sqlFilter = ParseUtil.getParameter(request, "sqlFilter", ""); 
353 				form.setSqlFilter(sqlFilter);
354 
355 				// set the source attribute to the requestURI.
356 				// So the form will think that the source is equal to the target
357 				// and will use order constraints
358 				// Source must be saved and restored - we need it e.g. in error
359 				// processing again!
360 				String saveSource = (String) request.getAttribute("source");
361 				String refSource = request.getRequestURI();
362 
363 				if (request.getQueryString() != null) {
364 					refSource += ("?" + request.getQueryString());
365 				}
366 
367 				request.setAttribute("source", refSource);
368 				form.doStartTag();
369 				request.setAttribute("source", saveSource);
370 
371 				rsv = form.getResultSetVector();
372 				logCat.info("get resultsetvector rsv= " + rsv.size());
373 
374 				if (rsv.size() == 0) {
375 					handleNoData(request, response);
376 				} else {
377 					dataSource = new JRDataSourceRSV(rsv.getAttributes(), rsv);
378 				}
379 
380 				form.doFinally();
381 			}
382 		} catch (Exception e) {
383 			logCat.error(e);
384 		}
385 
386 		return dataSource;
387 	}
388 
389 	private void sendErrorMessageText(HttpServletResponse response,
390 			String message) {
391 		try {
392 			PrintWriter out = response.getWriter();
393 			response.setContentType("text/html");
394 			out.println("<html><body><h1>ERROR</h1><p>");
395 			out.println(message);
396 			out.println("</p></body></html>");
397 			out.flush();
398 			out.close();
399 		} catch (IOException ioe2) {
400 			logCat.error("sendErrorMessageText", ioe2);
401 		}
402 	}
403 
404 	private void handleNoOutput(HttpServletRequest request,
405 			HttpServletResponse response) {
406 		sendErrorMessage(request, response, MessageResourcesInternal
407 				.getMessage("dbforms.reports.nooutput", request.getLocale()));
408 	}
409 
410 }