001: /*
002: * ============================================================================
003: * GNU Lesser General Public License
004: * ============================================================================
005: *
006: * JasperReports - Free Java report-generating library.
007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
022: *
023: * JasperSoft Corporation
024: * 303 Second Street, Suite 450 North
025: * San Francisco, CA 94107
026: * http://www.jaspersoft.com
027: */
028: package net.sf.jasperreports.engine.fill;
029:
030: import java.sql.Connection;
031: import java.util.ArrayList;
032: import java.util.Iterator;
033: import java.util.List;
034: import java.util.Map;
035:
036: import net.sf.jasperreports.engine.JRDataSource;
037: import net.sf.jasperreports.engine.JRException;
038: import net.sf.jasperreports.engine.JasperPrint;
039: import net.sf.jasperreports.engine.JasperReport;
040:
041: /**
042: * Class used to perform report filling asychronously.
043: * <p>
044: * An instance of this type can be used as a handle to an asychronous fill process.
045: * The main benefit of this method is that the filling process can be cancelled.
046: *
047: * @author Lucian Chirita (lucianc@users.sourceforge.net)
048: * @version $Id: AsynchronousFillHandle.java 1440 2006-10-19 09:01:06Z lucianc $
049: */
050: public class AsynchronousFillHandle {
051: protected final JasperReport jasperReport;
052: protected final Map parameters;
053: protected final JRDataSource dataSource;
054: protected final Connection conn;
055: protected final JRBaseFiller filler;
056: protected final List listeners;
057: protected Thread fillThread;
058: protected boolean started = false;
059: protected boolean running = false;
060: protected boolean cancelled = false;
061: protected final Object lock;
062:
063: protected Integer priority = null;
064:
065: protected String threadName;
066:
067: protected AsynchronousFillHandle(JasperReport jasperReport,
068: Map parameters, JRDataSource dataSource) throws JRException {
069: this (jasperReport, parameters, dataSource, null);
070: }
071:
072: protected AsynchronousFillHandle(JasperReport jasperReport,
073: Map parameters, Connection conn) throws JRException {
074: this (jasperReport, parameters, null, conn);
075: }
076:
077: protected AsynchronousFillHandle(JasperReport jasperReport,
078: Map parameters) throws JRException {
079: this (jasperReport, parameters, null, null);
080: }
081:
082: protected AsynchronousFillHandle(JasperReport jasperReport,
083: Map parameters, JRDataSource dataSource, Connection conn)
084: throws JRException {
085: this .jasperReport = jasperReport;
086: this .parameters = parameters;
087: this .dataSource = dataSource;
088: this .conn = conn;
089: this .filler = JRFiller.createFiller(jasperReport);
090: this .listeners = new ArrayList();
091: lock = this ;
092: }
093:
094: /**
095: * Adds a listener to the filling process.
096: *
097: * @param listener the listener to be added
098: */
099: public void addListener(AsynchronousFilllListener listener) {
100: listeners.add(listener);
101: }
102:
103: /**
104: * Removes a listener from the filling process.
105: *
106: * @param listener the listener to be removed
107: * @return <tt>true</tt> if the listener was found and removed
108: */
109: public boolean removeListener(AsynchronousFilllListener listener) {
110: return listeners.remove(listener);
111: }
112:
113: protected class ReportFiller implements Runnable {
114: public void run() {
115: synchronized (lock) {
116: running = true;
117: }
118:
119: try {
120: JasperPrint print;
121: if (conn != null) {
122: print = filler.fill(parameters, conn);
123: } else if (dataSource != null) {
124: print = filler.fill(parameters, dataSource);
125: } else {
126: print = filler.fill(parameters);
127: }
128:
129: notifyFinish(print);
130: } catch (Exception e) {
131: synchronized (lock) {
132: if (cancelled) {
133: notifyCancel();
134: } else {
135: notifyError(e);
136: }
137: }
138: } finally {
139: synchronized (lock) {
140: running = false;
141: }
142: }
143: }
144: }
145:
146: /**
147: * Starts the filling process asychronously.
148: * <p>
149: * The filling is launched on a new thread and the method exits
150: * after the thread is started.
151: * <p>
152: * When the filling finishes either in success or failure, the listeners
153: * are notified.
154: */
155: public void startFill() {
156: synchronized (lock) {
157: if (started) {
158: throw new IllegalStateException("Fill already started.");
159: }
160:
161: started = true;
162: }
163:
164: ReportFiller reportFiller = new ReportFiller();
165:
166: if (threadName == null) {
167: fillThread = new Thread(reportFiller);
168: } else {
169: fillThread = new Thread(reportFiller, threadName);
170: }
171:
172: if (priority != null) {
173: fillThread.setPriority(priority.intValue());
174: }
175:
176: fillThread.start();
177: }
178:
179: /**
180: * Cancels the fill started by the handle.
181: * <p>
182: * The method sends a cancel signal to the filling process.
183: * When the filling process will end, the listeners will be notified
184: * that the filling has been cancelled.
185: *
186: * @throws JRException
187: */
188: public void cancellFill() throws JRException {
189: synchronized (lock) {
190: if (!running) {
191: throw new IllegalStateException("Fill not running.");
192: }
193:
194: filler.cancelFill();
195: cancelled = true;
196: }
197: }
198:
199: protected void notifyFinish(JasperPrint print) {
200: for (Iterator i = listeners.iterator(); i.hasNext();) {
201: AsynchronousFilllListener listener = (AsynchronousFilllListener) i
202: .next();
203: listener.reportFinished(print);
204: }
205: }
206:
207: protected void notifyCancel() {
208: for (Iterator i = listeners.iterator(); i.hasNext();) {
209: AsynchronousFilllListener listener = (AsynchronousFilllListener) i
210: .next();
211: listener.reportCancelled();
212: }
213: }
214:
215: protected void notifyError(Throwable e) {
216: for (Iterator i = listeners.iterator(); i.hasNext();) {
217: AsynchronousFilllListener listener = (AsynchronousFilllListener) i
218: .next();
219: listener.reportFillError(e);
220: }
221: }
222:
223: /**
224: * Creates an asychronous filling handle.
225: *
226: * @param jasperReport the report
227: * @param parameters the parameter map
228: * @param dataSource the data source
229: * @return the handle
230: * @throws JRException
231: */
232: public static AsynchronousFillHandle createHandle(
233: JasperReport jasperReport, Map parameters,
234: JRDataSource dataSource) throws JRException {
235: AsynchronousFillHandle filler = new AsynchronousFillHandle(
236: jasperReport, parameters, dataSource);
237:
238: return filler;
239: }
240:
241: /**
242: * Creates an asychronous filling handle.
243: *
244: * @param jasperReport the report
245: * @param parameters the parameter map
246: * @param conn the connection
247: * @return the handle
248: * @throws JRException
249: */
250: public static AsynchronousFillHandle createHandle(
251: JasperReport jasperReport, Map parameters, Connection conn)
252: throws JRException {
253: AsynchronousFillHandle filler = new AsynchronousFillHandle(
254: jasperReport, parameters, conn);
255:
256: return filler;
257: }
258:
259: /**
260: * Creates an asychronous filling handle.
261: *
262: * @param jasperReport the report
263: * @param parameters the parameter map
264: * @return the handle
265: * @throws JRException
266: */
267: public static AsynchronousFillHandle createHandle(
268: JasperReport jasperReport, Map parameters)
269: throws JRException {
270: AsynchronousFillHandle filler = new AsynchronousFillHandle(
271: jasperReport, parameters);
272:
273: return filler;
274: }
275:
276: /**
277: * Sets the priority of the filler thread.
278: *
279: * @param priority the filler thread priority.
280: * @see Thread#setPriority(int)
281: */
282: public void setPriority(int priority) {
283: synchronized (lock) {
284: this .priority = new Integer(priority);
285: if (fillThread != null) {
286: fillThread.setPriority(priority);
287: }
288: }
289: }
290:
291: /**
292: * Sets the name of the filler thread.
293: *
294: * @param name the filler thread name.
295: * @see Thread#setName(java.lang.String)
296: */
297: public void setThreadName(String name) {
298: synchronized (lock) {
299: this.threadName = name;
300: if (fillThread != null) {
301: fillThread.setName(name);
302: }
303: }
304: }
305: }
|