1 /*
2  * JasperReports - Free Java Reporting Library.
3  * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
4  * http://www.jaspersoft.com
5  *
6  * Unless you have purchased a commercial license agreement from Jaspersoft,
7  * the following license terms apply:
8  *
9  * This program is part of JasperReports.
10  *
11  * JasperReports is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * JasperReports is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
23  */

24 package net.sf.jasperreports.engine.fill;
25
26 import net.sf.jasperreports.engine.JRException;
27 import net.sf.jasperreports.engine.JRRuntimeException;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32
33 /**
34  * @author Lucian Chirita (lucianc@users.sourceforge.net)
35  */

36 public abstract class AbstractThreadSubreportRunner extends JRSubreportRunnable implements JRSubreportRunner
37 {
38     
39     private static final Log log = LogFactory.getLog(AbstractThreadSubreportRunner.class);
40     public static final String EXCEPTION_MESSAGE_KEY_THREAD_REPORT_RUNNER_WAIT_ERROR = "fill.thread.report.runner.wait.error";
41     public static final String EXCEPTION_MESSAGE_KEY_THREAD_SUBREPORT_RUNNER_WAIT_ERROR = "fill.thread.subreport.runner.wait.error";
42
43     protected final JRBaseFiller subreportFiller;
44     
45     public AbstractThreadSubreportRunner(JRFillSubreport fillSubreport, JRBaseFiller subreportFiller)
46     {
47         super(fillSubreport);
48         this.subreportFiller = subreportFiller;
49     }
50
51     @Override
52     public JRSubreportRunResult start()
53     {
54         doStart();
55         return waitResult();
56     }
57
58     protected abstract void doStart();
59
60     @Override
61     public JRSubreportRunResult resume()
62     {
63         if (log.isDebugEnabled())
64         {
65             log.debug("Fill " + subreportFiller.fillerId + ": notifying to continue");
66         }
67         
68         //notifing the subreport fill thread that it can continue on the next page
69         subreportFiller.notifyAll();
70
71         return waitResult();
72     }
73
74     protected JRSubreportRunResult waitResult()
75     {
76         if (log.isDebugEnabled())
77         {
78             log.debug("Fill " + subreportFiller.fillerId + ": waiting for fill result");
79         }
80
81         try
82         {
83             // waiting for the subreport fill thread to fill the current page
84             subreportFiller.wait(); // FIXME maybe this is useless since you cannot enter 
85                                     // the synchornized bloc if the subreport filler hasn't 
86                                     // finished the page and passed to the wait state.
87         }
88         catch (InterruptedException e)
89         {
90             if (subreportFiller.fillContext.isCanceled())
91             {
92                 // only debug when cancel was requested
93                 if (log.isDebugEnabled())
94                 {
95                     log.debug("Fill " + subreportFiller.fillerId + ": exception", e);
96                 }
97             }
98             else
99             {
100                 if (log.isErrorEnabled())
101                 {
102                     log.error("Fill " + subreportFiller.fillerId + ": exception", e);
103                 }
104             }
105             
106             throw 
107                 new JRRuntimeException(
108                     EXCEPTION_MESSAGE_KEY_THREAD_REPORT_RUNNER_WAIT_ERROR,
109                     (Object[])null,
110                     e);
111         }
112         
113         if (log.isDebugEnabled())
114         {
115             log.debug("Fill " + subreportFiller.fillerId + ": notified of fill result");
116         }
117         
118         return runResult();
119     }
120     
121     @Override
122     public void cancel() throws JRException
123     {
124         if (log.isDebugEnabled())
125         {
126             log.debug("Fill " + subreportFiller.fillerId + ": notifying to continue on cancel");
127         }
128
129         // notifying the subreport filling thread that it can continue.
130         // it will stop anyway when trying to fill the current band
131         subreportFiller.notifyAll();
132
133         if (isRunning())
134         {
135             if (log.isDebugEnabled())
136             {
137                 log.debug("Fill " + subreportFiller.fillerId + ": still running, waiting");
138             }
139             
140             try
141             {
142                 //waits until the master filler notifies it that can continue with the next page
143                 subreportFiller.wait();
144             }
145             catch(InterruptedException e)
146             {
147                 if (log.isErrorEnabled())
148                 {
149                     log.error("Fill " + subreportFiller.fillerId + ": exception", e);
150                 }
151                 
152                 throw 
153                     new JRException(
154                         EXCEPTION_MESSAGE_KEY_THREAD_SUBREPORT_RUNNER_WAIT_ERROR,
155                         null,
156                         e);
157             }
158             
159             if (log.isDebugEnabled())
160             {
161                 log.debug("Fill " + subreportFiller.fillerId + ": wait ended");
162             }
163         }
164     }
165
166     @Override
167     public void suspend() throws JRException
168     {
169         if (log.isDebugEnabled())
170         {
171             log.debug("Fill " + subreportFiller.fillerId + ": notifying on suspend");
172         }
173         
174         //signals to the master filler that is has finished the page
175         subreportFiller.notifyAll();
176         
177         if (log.isDebugEnabled())
178         {
179             log.debug("Fill " + subreportFiller.fillerId + ": waiting to continue");
180         }
181
182         try
183         {
184             //waits until the master filler notifies it that can continue with the next page
185             subreportFiller.wait();
186         }
187         catch(InterruptedException e)
188         {
189             if (subreportFiller.fillContext.isCanceled() || subreportFiller.isDeliberatelyInterrupted())
190             {
191                 // only log a debug message if cancel was requested
192                 if (log.isDebugEnabled())
193                 {
194                     log.debug("Fill " + subreportFiller.fillerId + ": exception", e);
195                 }
196             }
197             else
198             {
199                 if (log.isErrorEnabled())
200                 {
201                     log.error("Fill " + subreportFiller.fillerId + ": exception", e);
202                 }
203             }
204             
205             throw 
206                 new JRException(
207                     EXCEPTION_MESSAGE_KEY_THREAD_SUBREPORT_RUNNER_WAIT_ERROR,
208                     null,
209                     e);
210         }
211         
212         if (log.isDebugEnabled())
213         {
214             log.debug("Fill " + subreportFiller.fillerId + ": notified to continue");
215         }
216     }
217
218     @Override
219     public void run()
220     {
221         super.run();
222
223         if (log.isDebugEnabled())
224         {
225             log.debug("Fill " + subreportFiller.fillerId + ": notifying of completion");
226         }
227
228         synchronized (subreportFiller)
229         {
230             //main filler notified that the subreport has finished
231             subreportFiller.notifyAll();
232         }
233
234 /*
235         if (error != null)
236         {
237             synchronized (subreportFiller)
238             {
239                 //if an exception occured then we should notify the main filler that we have finished the subreport
240                 subreportFiller.notifyAll();
241             }
242         }
243         */

244     }
245
246     @Override
247     public void abort()
248     {
249         if (subreportFiller.fillingThread != null)
250         {
251             if (log.isDebugEnabled())
252             {
253                 log.debug("Interrupting subfiller thread " + subreportFiller.fillingThread);
254             }
255
256             subreportFiller.fillingThread.interrupt();
257         }
258     }
259 }
260