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 java.util.concurrent.ExecutorService;
27 import java.util.concurrent.Executors;
28 import java.util.concurrent.ThreadFactory;
29 import java.util.concurrent.atomic.AtomicInteger;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33
34
35 /**
36  * @author Lucian Chirita (lucianc@users.sourceforge.net)
37  */

38 public class ThreadPoolSubreportRunnerFactory implements JRSubreportRunnerFactory
39 {
40     private static final Log log = LogFactory.getLog(ThreadPoolSubreportRunnerFactory.class);
41     
42     private static final String THREAD_POOL_KEY = "net.sf.jasperreports.engine.fill.JRThreadSubreportRunner.ThreadPool";
43
44     @Override
45     public JRSubreportRunner createSubreportRunner(JRFillSubreport fillSubreport, JRBaseFiller subreportFiller)
46     {
47         JRFillContext fillContext = subreportFiller.getFillContext();
48         ExecutorServiceDisposable executor = (ExecutorServiceDisposable) fillContext.getFillCache(THREAD_POOL_KEY);
49         if (executor == null)
50         {
51             ExecutorService threadExecutor = createThreadExecutor(fillContext);
52             executor = new ExecutorServiceDisposable(threadExecutor);
53             fillContext.setFillCache(THREAD_POOL_KEY, executor);
54         }
55
56         return new ThreadExecutorSubreportRunner(fillSubreport, subreportFiller, 
57                 executor.getExecutorService());
58     }
59
60     protected ExecutorService createThreadExecutor(JRFillContext fillContext)
61     {
62         SubreportsThreadFactory threadFactory = new SubreportsThreadFactory(fillContext);
63         ExecutorService threadExecutor = Executors.newCachedThreadPool(threadFactory);
64         if (log.isDebugEnabled())
65         {
66             log.debug("created subreports thread executor " + threadExecutor 
67                     + for " + fillContext.getMasterFiller().getJasperReport().getName());
68         }
69         return threadExecutor;
70     }
71     
72     protected static class ExecutorServiceDisposable implements JRFillContext.FillCacheDisposable
73     {
74         private final ExecutorService executorService;
75         
76         public ExecutorServiceDisposable(ExecutorService executorService)
77         {
78             this.executorService = executorService;
79         }
80         
81         public ExecutorService getExecutorService()
82         {
83             return executorService;
84         }
85
86         @Override
87         public void dispose()
88         {
89             if (log.isDebugEnabled())
90             {
91                 log.debug("shutting down " + executorService);
92             }
93             
94             executorService.shutdownNow();
95         }
96     }
97     
98     protected static class SubreportsThreadFactory implements ThreadFactory
99     {
100         private final JRFillContext fillContext;
101         private final AtomicInteger threadCount;
102         
103         public SubreportsThreadFactory(JRFillContext fillContext)
104         {
105             this.fillContext = fillContext;
106             this.threadCount = new AtomicInteger();
107         }
108
109         @Override
110         public Thread newThread(Runnable r)
111         {
112             String threadName = fillContext.getMasterFiller().getJasperReport().getName() 
113                     + " subreports #" + threadCount.incrementAndGet();
114             Thread thread = new Thread(r, threadName);
115             if (log.isDebugEnabled())
116             {
117                 log.debug("created thread " + thread);
118             }
119             return thread;
120         }
121         
122     }
123 }
124