KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > winstone > ObjectPool


1 /*
2  * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
3  * Distributed under the terms of either:
4  * - the common development and distribution license (CDDL), v1.0; or
5  * - the GNU Lesser General Public License, v2.1 or later
6  */

7 package winstone;
8
9 import java.io.IOException JavaDoc;
10 import java.net.Socket JavaDoc;
11 import java.util.ArrayList JavaDoc;
12 import java.util.Collection JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.Map JavaDoc;
16
17 /**
18  * Holds the object pooling code for Winstone. Presently this is only responses
19  * and requests, but may increase.
20  *
21  * @author <a HREF="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
22  * @version $Id: ObjectPool.java,v 1.8 2006/08/25 17:04:59 rickknowles Exp $
23  */

24 public class ObjectPool implements Runnable JavaDoc {
25     private static final long FLUSH_PERIOD = 60000L;
26     
27     private int STARTUP_REQUEST_HANDLERS_IN_POOL = 5;
28     private int MAX_IDLE_REQUEST_HANDLERS_IN_POOL = 50;
29     private int MAX_REQUEST_HANDLERS_IN_POOL = 1000;
30     private long RETRY_PERIOD = 1000;
31     private int START_REQUESTS_IN_POOL = 10;
32     private int MAX_REQUESTS_IN_POOL = 1000;
33     private int START_RESPONSES_IN_POOL = 10;
34     private int MAX_RESPONSES_IN_POOL = 1000;
35     private List JavaDoc unusedRequestHandlerThreads;
36     private List JavaDoc usedRequestHandlerThreads;
37     private List JavaDoc usedRequestPool;
38     private List JavaDoc unusedRequestPool;
39     private List JavaDoc usedResponsePool;
40     private List JavaDoc unusedResponsePool;
41     private Object JavaDoc requestHandlerSemaphore = new Boolean JavaDoc(true);
42     private Object JavaDoc requestPoolSemaphore = new Boolean JavaDoc(true);
43     private Object JavaDoc responsePoolSemaphore = new Boolean JavaDoc(true);
44     private int threadIndex = 0;
45     private boolean simulateModUniqueId;
46     private boolean saveSessions;
47
48     private Thread JavaDoc thread;
49     
50     /**
51      * Constructs an instance of the object pool, including handlers, requests
52      * and responses
53      */

54     public ObjectPool(Map JavaDoc args) throws IOException JavaDoc {
55         this.simulateModUniqueId = WebAppConfiguration.booleanArg(args, "simulateModUniqueId", false);
56         this.saveSessions = WebAppConfiguration.useSavedSessions(args);
57
58         // Build the initial pool of handler threads
59
this.unusedRequestHandlerThreads = new ArrayList JavaDoc();
60         this.usedRequestHandlerThreads = new ArrayList JavaDoc();
61
62         // Build the request/response pools
63
this.usedRequestPool = new ArrayList JavaDoc();
64         this.usedResponsePool = new ArrayList JavaDoc();
65         this.unusedRequestPool = new ArrayList JavaDoc();
66         this.unusedResponsePool = new ArrayList JavaDoc();
67
68         // Get handler pool options
69
if (args.get("handlerCountStartup") != null) {
70             STARTUP_REQUEST_HANDLERS_IN_POOL = Integer.parseInt((String JavaDoc) args
71                     .get("handlerCountStartup"));
72         }
73         if (args.get("handlerCountMax") != null) {
74             MAX_IDLE_REQUEST_HANDLERS_IN_POOL = Integer.parseInt((String JavaDoc) args
75                     .get("handlerCountMax"));
76         }
77         if (args.get("handlerCountMaxIdle") != null) {
78             MAX_IDLE_REQUEST_HANDLERS_IN_POOL = Integer.parseInt((String JavaDoc) args
79                     .get("handlerCountMaxIdle"));
80         }
81
82         // Start the base set of handler threads
83
for (int n = 0; n < STARTUP_REQUEST_HANDLERS_IN_POOL; n++) {
84             this.unusedRequestHandlerThreads
85                     .add(new RequestHandlerThread(this,
86                             this.threadIndex++, this.simulateModUniqueId,
87                             this.saveSessions));
88         }
89
90         // Initialise the request/response pools
91
for (int n = 0; n < START_REQUESTS_IN_POOL; n++) {
92             this.unusedRequestPool.add(new WinstoneRequest());
93         }
94         for (int n = 0; n < START_RESPONSES_IN_POOL; n++) {
95             this.unusedResponsePool.add(new WinstoneResponse());
96         }
97         
98         this.thread = new Thread JavaDoc(this, "WinstoneObjectPoolMgmt");
99         this.thread.setDaemon(true);
100         this.thread.start();
101     }
102
103     public void run() {
104         boolean interrupted = false;
105         while (!interrupted) {
106             try {
107                 Thread.sleep(FLUSH_PERIOD);
108                 removeUnusedRequestHandlers();
109             } catch (InterruptedException JavaDoc err) {
110                 interrupted = true;
111             }
112         }
113         this.thread = null;
114     }
115     
116     private void removeUnusedRequestHandlers() {
117         // Check max idle requestHandler count
118
synchronized (this.requestHandlerSemaphore) {
119             // If we have too many idle request handlers
120
while (this.unusedRequestHandlerThreads.size() > MAX_IDLE_REQUEST_HANDLERS_IN_POOL) {
121                 RequestHandlerThread rh = (RequestHandlerThread) this.unusedRequestHandlerThreads.get(0);
122                 rh.destroy();
123                 this.unusedRequestHandlerThreads.remove(rh);
124             }
125         }
126     }
127
128     public void destroy() {
129         synchronized (this.requestHandlerSemaphore) {
130             Collection JavaDoc usedHandlers = new ArrayList JavaDoc(this.usedRequestHandlerThreads);
131             for (Iterator JavaDoc i = usedHandlers.iterator(); i.hasNext();)
132                 releaseRequestHandler((RequestHandlerThread) i.next());
133             Collection JavaDoc unusedHandlers = new ArrayList JavaDoc(this.unusedRequestHandlerThreads);
134             for (Iterator JavaDoc i = unusedHandlers.iterator(); i.hasNext();)
135                 ((RequestHandlerThread) i.next()).destroy();
136             this.unusedRequestHandlerThreads.clear();
137         }
138         if (this.thread != null) {
139             this.thread.interrupt();
140         }
141     }
142
143     /**
144      * Once the socket request comes in, this method is called. It reserves a
145      * request handler, then delegates the socket to that class. When it
146      * finishes, the handler is released back into the pool.
147      */

148     public void handleRequest(Socket JavaDoc socket, Listener listener)
149             throws IOException JavaDoc, InterruptedException JavaDoc {
150         RequestHandlerThread rh = null;
151         synchronized (this.requestHandlerSemaphore) {
152             // If we have any spare, get it from the pool
153
if (this.unusedRequestHandlerThreads.size() > 0) {
154                 rh = (RequestHandlerThread) this.unusedRequestHandlerThreads.get(0);
155                 this.unusedRequestHandlerThreads.remove(rh);
156                 this.usedRequestHandlerThreads.add(rh);
157                 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
158                         "ObjectPool.UsingRHPoolThread", new String JavaDoc[] {
159                                 "" + this.usedRequestHandlerThreads.size(),
160                                 "" + this.unusedRequestHandlerThreads.size() });
161             }
162
163             // If we are out (and not over our limit), allocate a new one
164
else if (this.usedRequestHandlerThreads.size() < MAX_REQUEST_HANDLERS_IN_POOL) {
165                 rh = new RequestHandlerThread(this,
166                         this.threadIndex++, this.simulateModUniqueId,
167                         this.saveSessions);
168                 this.usedRequestHandlerThreads.add(rh);
169                 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
170                         "ObjectPool.NewRHPoolThread", new String JavaDoc[] {
171                                 "" + this.usedRequestHandlerThreads.size(),
172                                 "" + this.unusedRequestHandlerThreads.size() });
173             }
174
175             // otherwise throw fail message - we've blown our limit
176
else {
177                 // Possibly insert a second chance here ? Delay and one retry ?
178
// Remember to release the lock first
179
Logger.log(Logger.WARNING, Launcher.RESOURCES,
180                         "ObjectPool.NoRHPoolThreadsRetry");
181                 // socket.close();
182
// throw new UnavailableException("NoHandlersAvailable");
183
}
184         }
185
186         if (rh != null)
187             rh.commenceRequestHandling(socket, listener);
188         else {
189             // Sleep for a set period and try again from the pool
190
Thread.sleep(RETRY_PERIOD);
191
192             synchronized (this.requestHandlerSemaphore) {
193                 if (this.usedRequestHandlerThreads.size() < MAX_REQUEST_HANDLERS_IN_POOL) {
194                     rh = new RequestHandlerThread(this,
195                             this.threadIndex++, this.simulateModUniqueId,
196                             this.saveSessions);
197                     this.usedRequestHandlerThreads.add(rh);
198                     Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
199                             "ObjectPool.NewRHPoolThread", new String JavaDoc[] {
200                                     "" + this.usedRequestHandlerThreads.size(),
201                                     "" + this.unusedRequestHandlerThreads.size() });
202                 }
203             }
204             if (rh != null)
205                 rh.commenceRequestHandling(socket, listener);
206             else {
207                 Logger.log(Logger.WARNING, Launcher.RESOURCES,
208                         "ObjectPool.NoRHPoolThreads");
209                 socket.close();
210             }
211         }
212     }
213
214     /**
215      * Release the handler back into the pool
216      */

217     public void releaseRequestHandler(RequestHandlerThread rh) {
218         synchronized (this.requestHandlerSemaphore) {
219             this.usedRequestHandlerThreads.remove(rh);
220             this.unusedRequestHandlerThreads.add(rh);
221             Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
222                     "ObjectPool.ReleasingRHPoolThread", new String JavaDoc[] {
223                             "" + this.usedRequestHandlerThreads.size(),
224                             "" + this.unusedRequestHandlerThreads.size() });
225         }
226     }
227
228     /**
229      * An attempt at pooling request objects for reuse.
230      */

231     public WinstoneRequest getRequestFromPool() throws IOException JavaDoc {
232         WinstoneRequest req = null;
233         synchronized (this.requestPoolSemaphore) {
234             // If we have any spare, get it from the pool
235
if (this.unusedRequestPool.size() > 0) {
236                 req = (WinstoneRequest) this.unusedRequestPool.get(0);
237                 this.unusedRequestPool.remove(req);
238                 this.usedRequestPool.add(req);
239                 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
240                         "ObjectPool.UsingRequestFromPool", ""
241                                 + this.unusedRequestPool.size());
242             }
243             // If we are out, allocate a new one
244
else if (this.usedRequestPool.size() < MAX_REQUESTS_IN_POOL) {
245                 req = new WinstoneRequest();
246                 this.usedRequestPool.add(req);
247                 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
248                         "ObjectPool.NewRequestForPool", ""
249                                 + this.usedRequestPool.size());
250             } else
251                 throw new WinstoneException(Launcher.RESOURCES
252                         .getString("ObjectPool.PoolRequestLimitExceeded"));
253         }
254         return req;
255     }
256
257     public void releaseRequestToPool(WinstoneRequest req) {
258         req.cleanUp();
259         synchronized (this.requestPoolSemaphore) {
260             this.usedRequestPool.remove(req);
261             this.unusedRequestPool.add(req);
262             Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
263                     "ObjectPool.RequestReleased", ""
264                             + this.unusedRequestPool.size());
265         }
266     }
267
268     /**
269      * An attempt at pooling request objects for reuse.
270      */

271     public WinstoneResponse getResponseFromPool() throws IOException JavaDoc {
272         WinstoneResponse rsp = null;
273         synchronized (this.responsePoolSemaphore) {
274             // If we have any spare, get it from the pool
275
if (this.unusedResponsePool.size() > 0) {
276                 rsp = (WinstoneResponse) this.unusedResponsePool.get(0);
277                 this.unusedResponsePool.remove(rsp);
278                 this.usedResponsePool.add(rsp);
279                 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
280                         "ObjectPool.UsingResponseFromPool", ""
281                                 + this.unusedResponsePool.size());
282             }
283             // If we are out, allocate a new one
284
else if (this.usedResponsePool.size() < MAX_RESPONSES_IN_POOL) {
285                 rsp = new WinstoneResponse();
286                 this.usedResponsePool.add(rsp);
287                 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
288                         "ObjectPool.NewResponseForPool", ""
289                                 + this.usedResponsePool.size());
290             } else
291                 throw new WinstoneException(Launcher.RESOURCES
292                         .getString("ObjectPool.PoolResponseLimitExceeded"));
293         }
294         return rsp;
295     }
296
297     public void releaseResponseToPool(WinstoneResponse rsp) {
298         rsp.cleanUp();
299         synchronized (this.responsePoolSemaphore) {
300             this.usedResponsePool.remove(rsp);
301             this.unusedResponsePool.add(rsp);
302             Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
303                     "ObjectPool.ResponseReleased", ""
304                             + this.unusedResponsePool.size());
305         }
306     }
307
308 }
309
Popular Tags