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 3525 2007-10-16 11:43:48Z tmorgner $ 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 } 210 211 /** 212 * Marks the given worker as available. 213 * 214 * @param worker the worker which was available. 215 */ 216 public synchronized void workerAvailable (final Worker worker) 217 { 218 for (int i = 0; i < workers.length; i++) 219 { 220 if (workers[i] == worker) 221 { 222 synchronized (this) 223 { 224 workersAvailable = true; 225 this.notifyAll(); 226 } 227 return; 228 } 229 } 230 } 231 232 /** 233 * Finishes all worker of this pool. 234 */ 235 public void finishAll () 236 { 237 for (int i = 0; i < workers.length; i++) 238 { 239 if (workers[i] != null) 240 { 241 workers[i].finish(); 242 } 243 } 244 } 245 }