KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > util > pool > AbstractPool


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 //NOTE: Tabs are used instead of spaces for indentation.
25
// Make sure that your editor does not replace tabs with spaces.
26
// Set the tab length using your favourite editor to your
27
// visual preference.
28

29 /*
30  * Filename: AbstractPool.java
31  *
32  * Copyright 2000-2001 by iPlanet/Sun Microsystems, Inc.,
33  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
34  * All rights reserved.
35  *
36  * This software is the confidential and proprietary information
37  * of iPlanet/Sun Microsystems, Inc. ("Confidential Information").
38  * You shall not disclose such Confidential Information and shall
39  * use it only in accordance with the terms of the license
40  * agreement you entered into with iPlanet/Sun Microsystems.
41  */

42  
43 /**
44  * <BR> <I>$Source: /cvs/glassfish/appserv-commons/src/java/com/sun/enterprise/util/pool/AbstractPool.java,v $</I>
45  * @author $Author: tcfujii $
46  * @version $Revision: 1.3 $ $Date: 2005/12/25 04:12:26 $
47  */

48  
49
50 package com.sun.enterprise.util.pool;
51
52 import java.util.Collection JavaDoc;
53 import java.util.ArrayList JavaDoc;
54
55 import com.sun.enterprise.util.scheduler.PeriodicallyServicable;
56 import com.sun.enterprise.util.scheduler.PeriodicEventScheduler;
57
58 import com.sun.enterprise.util.ApproximateClock;
59 //Bug 4677074 begin
60
import java.util.logging.Logger JavaDoc;
61 import java.util.logging.Level JavaDoc;
62 import com.sun.logging.LogDomains;
63 //Bug 4677074 end
64

65 /**
66  * <p>Abstract pool provides the basic implementation of an object pool. The implementation
67  * uses a linked list to maintain a collection of (available) objects. If the pool is
68  * empty it simply creates one using the ObjectFactory instance. Subclasses can change
69  * this behaviour by overriding getObject(...) and returnObject(....) methods. This
70  * class provides basic support for synchronization, event notification, pool shutdown
71  * and pool object recycling. It also does some very basic bookkeeping like the
72  * number of objects created, number of threads waiting for object.
73  * <p> Subclasses can make use of these book-keeping data to provide complex pooling
74  * mechanism like LRU / MRU / Random. Also, note that AbstractPool does not have a
75  * notion of pool limit. It is upto to the derived classes to implement these features.
76  */

77 public abstract class AbstractPool
78     implements Pool
79 {
80 //Bug 4677074 begin
81
static Logger JavaDoc _logger=LogDomains.getLogger(LogDomains.UTIL_LOGGER);
82 //Bug 4677074 end
83
protected boolean bDebug=false;
84     protected Collection JavaDoc collection;
85     protected ArrayList JavaDoc listeners;
86     protected ObjectFactory factory = null;
87     protected int waitCount = 0;
88     protected int createdCount = 0;
89
90     protected Object JavaDoc onHold = null;
91     protected Object JavaDoc closed = null;
92     
93     protected static ApproximateClock _clock = new ApproximateClock(15000);
94     protected PeriodicEventScheduler scheduler;
95     
96     
97     protected AbstractPool() {
98         scheduler = PeriodicEventScheduler.getInstance();
99     }
100     
101     
102     /**
103      * Get an object. Application can use pool.getObject() to get an object
104      * instead of using new XXX().
105      * @param canWait Must be true if the calling thread is willing to wait for infinite time
106      * to get an object, false if the calling thread does not want to wait at all.
107      * @exception Throws InterruptedException if the thread was interrupted while waiting
108      */

109     public Object JavaDoc getObject(boolean canWait, Object JavaDoc param)
110         throws InterruptedException JavaDoc, PoolException
111     {
112         Object JavaDoc object;
113
114         if (closed != null) {
115             throw new PoolException("Pool closed. Cannot obtain object");
116         }
117         
118         synchronized (collection) {
119             while (true) {
120                 if (collection.size() > 0) {
121                     if ( (object = checkout(param)) != null) {
122                         return object;
123                     }
124                 } else if (canCreate()) {
125                     createdCount++;
126                     break;
127                 }
128                     
129                 if (canWait) {
130                     try {
131                         waitCount++;
132                         beforeWait(param);
133                         collection.wait();
134                         afterNotify(param);
135                         waitCount--;
136                     } catch (InterruptedException JavaDoc inEx) {
137                         throw new RequestInterruptedException("InterruptedException", inEx);
138                     }
139                 } else {
140                     return null;
141                 }
142             }
143         }
144             
145         try {
146             object = factory.create(param);
147         } catch (PoolException poolEx) {
148             synchronized (collection) {
149                 createdCount--;
150             }
151             throw poolEx;
152         }
153         afterCreate(object);
154                     
155         return object;
156     }
157     
158     /**
159      * Get an object. Application can use pool.getObject() to get an object
160      * instead of using new XXX(). The method throws TimedoutException
161      * if an object could not be returned in 'waitForMillis' millisecond.
162      * @param waitFor the amount of time the thread is willing to wait.
163      * @exception Throws InterruptedException if the thread was interrupted while waiting
164      * @exception Throws TimedoutException if an object could not be obtained from the pool
165      * within the specified time.
166      */

167     public Object JavaDoc getObject(long waitFor, Object JavaDoc param)
168         throws InterruptedException JavaDoc, PoolException
169     {
170
171         if (closed != null) {
172             throw new PoolException("Pool closed. Cannot obtain object");
173         }
174         
175         long now = _clock.getTime();
176         long timeLeft = waitFor;
177         long startTime = now;
178         Object JavaDoc object;
179         synchronized (collection) {
180             while (true) {
181                 if (collection.size() > 0) {
182                     if ( (object = checkout(param)) != null) {
183                         return object;
184                     }
185                 } else if (canCreate()) {
186                     createdCount++;
187                     break;
188                 }
189                 
190                 if (timeLeft > 0) {
191                     try {
192                         waitCount++;
193                         beforeWait(param);
194                         collection.wait();
195                         afterNotify(param);
196                         waitCount--;
197                     } catch (InterruptedException JavaDoc inEx) {
198                         throw new RequestInterruptedException("InterruptedException", inEx);
199                     }
200                 } else {
201                     return null;
202                 }
203                 now = _clock.getTime();
204                 timeLeft = now - startTime;
205                 startTime = now;
206             }
207         }
208         
209         try {
210             object = factory.create(param);
211         } catch (PoolException poolEx) {
212             synchronized (collection) {
213                 createdCount--;
214             }
215             throw poolEx;
216         }
217         afterCreate(object);
218
219         return object;
220     }
221
222     /**
223      * Return an object back to the pool. An object that is obtained through
224      * getObject() must always be returned back to the pool using either
225      * returnObject(obj) or through destroyObject(obj).
226      */

227     public void returnObject(Object JavaDoc object) {
228         synchronized (collection) {
229             if (closed != null) {
230                 if (waitCount == 0) {
231                     destroyObject(object);
232                     return;
233                 }
234             }
235             
236             checkin(object);
237             if (waitCount > 0) {
238                 collection.notify();
239             }
240         }
241     }
242
243     /**
244      * Destroys an Object. Note that applications should not ignore the reference
245      * to the object that they got from getObject(). An object that is obtained through
246      * getObject() must always be returned back to the pool using either
247      * returnObject(obj) or through destroyObject(obj). This method tells that the
248      * object should be destroyed and cannot be reused.
249      */

250     public void destroyObject(Object JavaDoc object) {
251         beforeDestroy(object);
252         factory.destroy(object);
253         synchronized (collection) {
254             createdCount--;
255             if (waitCount > 0) {
256                 collection.notify();
257             }
258         }
259     }
260     
261     /**
262      * Notification when an object is put back into the pool (checkin).
263      * @param The object to be returned back to the pool.
264      * @return Any non null value can be returned to signal that the object
265      * was indeed added to the pool. This class always adds the object to the
266      * pool (at the end of the collection), it returns non-null value.
267      * Subclasses can override this behaviour.
268      */

269     protected abstract Object JavaDoc checkin(Object JavaDoc object);
270                 
271     /**
272      * Notification when an object is given out from the pool (checout).
273      * @return The object that has to be returned to the application. A null
274      * value must be returned if no object can be returned to the application. Since this
275      * class always returns the last node from the collection, it returns non-null value.
276      * Subclasses can override this behaviour.
277      */

278     protected abstract Object JavaDoc checkout(Object JavaDoc param);
279                 
280     
281     /**
282     * Add a PoolListener
283     * @param listener The pool listener
284     */

285     public boolean addPoolListener(PoolListener listener) {
286         synchronized (this) {
287             if (listeners == null) {
288                 listeners = new ArrayList JavaDoc();
289                 listeners.add(listener);
290                 return true;
291             }
292             
293             if (listeners.indexOf(listener) == -1) {
294                 listeners.add(listener);
295                 return true;
296             } else {
297                 return false;
298             }
299         }
300     }
301
302     
303     /**
304     * Add a PoolListener
305     * @param listener The pool listener
306     */

307     public boolean removePoolListener(PoolListener listener) {
308         synchronized (this) {
309             if (listeners == null) {
310                 return false;
311             } else {
312                 return listeners.remove(listener);
313             }
314         }
315     }
316     
317     
318     protected abstract boolean canCreate();
319     
320     /**
321     * Preload the pool with objects.
322     * @param count the number of objects to be added.
323     */

324     public void preload(int count) {
325         if (count <= 0) {
326             return;
327         }
328         
329         ArrayList JavaDoc tempList = new ArrayList JavaDoc(count);
330         for (int i=0; i<count; i++) {
331             try {
332                 tempList.add(factory.create(null));
333             } catch (PoolException poolEx) {
334                 
335             }
336         }
337
338         count = tempList.size();
339         synchronized (collection) {
340             for (int i=0; i<count; i++) {
341                 checkin(tempList.get(i));
342             }
343             createdCount += count;
344         }
345 //Bug 4677074 if(bDebug) System.out.println("After preload(" + count + "): Size: " + collection.size());
346
//Bug 4677074 begin
347
if(com.sun.enterprise.util.logging.Debug.enabled) _logger.log(Level.FINE,"After preload(" + count + "): Size: " + collection.size());
348 //Bug 4677074 end
349
}
350     
351     public int size() {
352         return collection.size();
353     }
354     
355     /**
356     * Destroy the available objects in the pool.
357     */

358     public int destroyPoolObjects() {
359         return destroyPoolObjects(collection.size());
360     }
361     
362     /**
363     * Destroy 'count' available objects in the pool.
364     */

365     public int destroyPoolObjects(int count) {
366         if (count <= 0) {
367             return 0;
368         }
369         
370         Object JavaDoc[] array = collection.toArray();
371         ArrayList JavaDoc arrayList = null;
372         synchronized (collection) {
373             if (count > collection.size()) {
374                 count = collection.size();
375             }
376             arrayList = new ArrayList JavaDoc(count);
377             for (int i=0; i<count; i++) {
378                 arrayList.add(checkout(null));
379             }
380             count = arrayList.size();
381             createdCount -= count;
382         }
383         
384         for (int i=0; i<count; i++) {
385             factory.destroy(arrayList.get(i));
386         }
387         return count;
388     }
389     
390     /**
391     * Closes the current pool. No further getObject(....)s are allowed, while
392     * returnObject() and destroyObjects() are allowed.
393     */

394     public void close() {
395         //first clean up all objects
396
onClose();
397         synchronized (collection) {
398             closed = "__Closed__";
399             int diff = collection.size() - this.waitCount;
400             destroyPoolObjects(diff);
401             //We do not need to change the factory as all fresh getObject()
402
// requests are blocked well before the synchronized access to the
403
// collection (or pool).
404
//this.factory = new ClosedObjectFactory(this.factory);
405
}
406     }
407     
408     
409     /**
410      * Test if the pool is closed or not
411      * @return True if the pool is closed, false if not.
412      */

413     public boolean isClosed() {
414         return (closed != null);
415     }
416     
417     //Event Notification
418

419     /**
420      * Called after an object is created using factory.create(....)
421      * @param The created object.
422      */

423     public void afterCreate(Object JavaDoc object) {
424         if (listeners != null) {
425             int size = listeners.size();
426             for (int i=0; i<size; i++) {
427                 ((PoolListener) listeners.get(i)).afterCreate(object);
428             }
429         }
430     }
431        
432     /**
433      * Called before an object is destroyed using factory.destroy(object)
434      * @param The object to be destroyed.
435      */

436     public void beforeDestroy(Object JavaDoc object) {
437         if (listeners != null) {
438             int size = listeners.size();
439             for (int i=0; i<size; i++) {
440                 ((PoolListener) listeners.get(i)).beforeDestroy(object);
441             }
442         }
443     }
444        
445     /**
446      * Called by the thread that is about to wait.
447      */

448     public void beforeWait(Object JavaDoc object) {
449         if (listeners != null) {
450             int size = listeners.size();
451             for (int i=0; i<size; i++) {
452                 ((PoolListener) listeners.get(i)).beforeWait(object);
453             }
454         }
455     }
456        
457     /**
458      * Called by the thread that has been notified.
459      */

460     public void afterNotify(Object JavaDoc object) {
461         if (listeners != null) {
462             int size = listeners.size();
463             for (int i=0; i<size; i++) {
464                 ((PoolListener) listeners.get(i)).afterNotify(object);
465             }
466         }
467     }
468    
469     /**
470      * Called when the pool is closed.
471      */

472     public void onClose() {
473         if (listeners != null) {
474             int size = listeners.size();
475             for (int i=0; i<size; i++) {
476                 ((PoolListener) listeners.get(i)).onClose();
477             }
478         }
479     }
480    
481    
482    
483 }
484
Popular Tags