001 /**
002 * ========================================
003 * JFreeReport : a free Java report library
004 * ========================================
005 *
006 * Project Info: http://reporting.pentaho.org/
007 *
008 * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009 *
010 * This library is free software; you can redistribute it and/or modify it under the terms
011 * of the GNU Lesser General Public License as published by the Free Software Foundation;
012 * either 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, but WITHOUT ANY WARRANTY;
015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016 * See the GNU Lesser General Public License for more details.
017 *
018 * You should have received a copy of the GNU Lesser General Public License along with this
019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020 * Boston, MA 02111-1307, USA.
021 *
022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023 * in the United States and other countries.]
024 *
025 * ------------
026 * $Id: WorkerPool.java,v 1.8 2007/04/01 18:49:34 taqua Exp $
027 * ------------
028 * (C) Copyright 2000-2005, by Object Refinery Limited.
029 * (C) Copyright 2005-2007, by Pentaho Corporation.
030 */
031
032 package org.jfree.report.util;
033
034 /**
035 * A simple static workpool. Worker threads are created when necessary.
036 *
037 * @author Thomas Morgner
038 */
039 public class WorkerPool
040 {
041 /**
042 * The worker array.
043 */
044 private Worker[] workers;
045 /**
046 * A flag indicating whether idle workers are available.
047 */
048 private boolean workersAvailable;
049 /**
050 * the name prefix for all workers of this pool.
051 */
052 private String namePrefix;
053
054 /**
055 * Creates a new worker pool with the default size of 10 workers and the default name.
056 */
057 public WorkerPool ()
058 {
059 this(10);
060 }
061
062 /**
063 * Creates a new workerpool with the given number of workers and the default name.
064 *
065 * @param size the maximum number of workers available.
066 */
067 public WorkerPool (final int size)
068 {
069 this(size, "WorkerPool-worker");
070 }
071
072 /**
073 * Creates a new worker pool for the given number of workers and with the given name
074 * prefix.
075 *
076 * @param size the size of the worker pool.
077 * @param namePrefix the name prefix for all created workers.
078 */
079 public WorkerPool (final int size, final String namePrefix)
080 {
081 if (size <= 0)
082 {
083 throw new IllegalArgumentException("Size must be > 0");
084 }
085 workers = new Worker[size];
086 workersAvailable = true;
087 this.namePrefix = namePrefix;
088 }
089
090 /**
091 * Checks, whether workers are available.
092 *
093 * @return true, if at least one worker is idle, false otherwise.
094 */
095 public synchronized boolean isWorkerAvailable ()
096 {
097 return workersAvailable;
098 }
099
100 /**
101 * Updates the workersAvailable flag after a worker was assigned.
102 */
103 private void updateWorkersAvailable ()
104 {
105 for (int i = 0; i < workers.length; i++)
106 {
107 if (workers[i] == null)
108 {
109 workersAvailable = true;
110 return;
111 }
112 if (workers[i].isAvailable() == true)
113 {
114 workersAvailable = true;
115 return;
116 }
117 }
118 workersAvailable = false;
119 }
120
121 /**
122 * Waits until a worker will be available.
123 */
124 private synchronized void waitForWorkerAvailable ()
125 {
126 while (isWorkerAvailable() == false)
127 {
128 try
129 {
130 // remove lock
131 this.wait(5000);
132 }
133 catch (InterruptedException ie)
134 {
135 // ignored
136 }
137 }
138 }
139
140 /**
141 * Returns a workerhandle for the given workload. This method will wait until an idle
142 * worker is found.
143 *
144 * @param r the workload for the worker
145 * @return a handle to the worker.
146 */
147 public synchronized WorkerHandle getWorkerForWorkload (final Runnable r)
148 {
149 waitForWorkerAvailable();
150
151 int emptySlot = -1;
152 for (int i = 0; i < workers.length; i++)
153 {
154 if (workers[i] == null)
155 {
156 // in the first run, try to avoid to create new threads...
157 // reuse the already available threads
158 if (emptySlot == -1)
159 {
160 emptySlot = i;
161 }
162 continue;
163 }
164 if (workers[i].isAvailable() == true)
165 {
166 workers[i].setWorkload(r);
167 updateWorkersAvailable();
168 return new WorkerHandle(workers[i]);
169 }
170 }
171 if (emptySlot != -1)
172 {
173 workers[emptySlot] = new Worker();
174 workers[emptySlot].setName(namePrefix + "-" + emptySlot);
175 workers[emptySlot].setWorkerPool(this);
176 workers[emptySlot].setWorkload(r);
177 updateWorkersAvailable();
178 return new WorkerHandle(workers[emptySlot]);
179 }
180 throw new IllegalStateException
181 ("At this point, a worker should already have been assigned.");
182 }
183
184 /**
185 * Marks the given worker as finished. The worker will be removed from the list of the
186 * available workers.
187 *
188 * @param worker the worker which was finished.
189 */
190 public void workerFinished (final Worker worker)
191 {
192 if (worker.isFinish() == false)
193 {
194 throw new IllegalArgumentException("This worker is not in the finish state.");
195 }
196 for (int i = 0; i < workers.length; i++)
197 {
198 if (workers[i] == worker)
199 {
200 synchronized (this)
201 {
202 workers[i] = null;
203 workersAvailable = true;
204 this.notifyAll();
205 }
206 return;
207 }
208 }
209 return;
210 }
211
212 /**
213 * Marks the given worker as available.
214 *
215 * @param worker the worker which was available.
216 */
217 public synchronized void workerAvailable (final Worker worker)
218 {
219 for (int i = 0; i < workers.length; i++)
220 {
221 if (workers[i] == worker)
222 {
223 synchronized (this)
224 {
225 workersAvailable = true;
226 this.notifyAll();
227 }
228 return;
229 }
230 }
231 return;
232 }
233
234 /**
235 * Finishes all worker of this pool.
236 */
237 public void finishAll ()
238 {
239 for (int i = 0; i < workers.length; i++)
240 {
241 if (workers[i] != null)
242 {
243 workers[i].finish();
244 }
245 }
246 }
247 }