KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jacorb > notification > util > AbstractObjectPool


1 package org.jacorb.notification.util;
2
3 /*
4  * JacORB - a free Java ORB
5  *
6  * Copyright (C) 1999-2004 Gerald Brose
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the Free
20  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */

23
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.LinkedList JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Set JavaDoc;
31
32 import org.apache.avalon.framework.configuration.Configurable;
33 import org.apache.avalon.framework.configuration.Configuration;
34 import org.apache.avalon.framework.configuration.ConfigurationException;
35 import org.apache.avalon.framework.logger.Logger;
36 import org.jacorb.notification.interfaces.Disposable;
37
38 import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
39
40 /**
41  * Abstract Base Class for Simple Pooling Mechanism. Subclasses must at least implement the method
42  * newInstance. To use a Object call lendObject. After use the Object must be returned with
43  * returnObject(Object). An Object must not be used after it has been returned to its pool!
44  *
45  * This class needs a two phase initialization: configure MUST be invoked before an instance can be used.
46  *
47  * @author Alphonse Bendt
48  * @version $Id: AbstractObjectPool.java,v 1.18 2005/04/17 17:17:34 alphonse.bendt Exp $
49  */

50
51 public abstract class AbstractObjectPool implements Runnable JavaDoc, Configurable
52 {
53     public static final boolean DEBUG = false;
54
55     /**
56      * time the cleaner thread sleeps between two cleanups
57      */

58     public static final long SLEEP = 5000L;
59
60     public static final int LOWER_WATERMARK_DEFAULT = 5;
61
62     public static final int SIZE_INCREASE_DEFAULT = 3;
63
64     public static final int INITIAL_SIZE_DEFAULT = 10;
65
66     public static final int MAXIMUM_WATERMARK_DEFAULT = 20;
67
68     public static final int MAXIMUM_SIZE_DEFAULT = 0;
69
70     /**
71      * non synchronized as all accessing methods are synchronized.
72      */

73     private static final List JavaDoc sPoolsToLookAfter = new ArrayList JavaDoc();
74
75     private static AbstractObjectPool[] asArray;
76
77     private static boolean modified = true;
78
79     private final static AbstractObjectPool[] ARRAY_TEMPLATE = new AbstractObjectPool[0];
80
81     static Thread JavaDoc sCleanerThread;
82
83     static final Logger sLogger_ = LogUtil.getLogger(AbstractObjectPool.class.getName());
84
85     private static ListCleaner sListCleaner;
86
87     private static boolean sUseListCleaner = true;
88
89     static AbstractObjectPool[] getAllPools()
90     {
91         synchronized (sPoolsToLookAfter)
92         {
93             if (modified)
94             {
95                 asArray = (AbstractObjectPool[]) sPoolsToLookAfter.toArray(ARRAY_TEMPLATE);
96                 modified = false;
97             }
98         }
99         return asArray;
100     }
101
102     private static void registerPool(AbstractObjectPool pool)
103     {
104         synchronized (sPoolsToLookAfter)
105         {
106             sPoolsToLookAfter.add(pool);
107             modified = true;
108             startListCleaner();
109         }
110     }
111
112     private static void deregisterPool(AbstractObjectPool pool)
113     {
114         synchronized (sPoolsToLookAfter)
115         {
116             sPoolsToLookAfter.remove(pool);
117             modified = true;
118             if (sPoolsToLookAfter.isEmpty())
119             {
120                 // this cleans up the asArray_ array for the GC.
121
getAllPools();
122
123                 stopListCleaner();
124             }
125         }
126     }
127
128     private static class ListCleaner extends Thread JavaDoc
129     {
130         private SynchronizedBoolean active_ = new SynchronizedBoolean(true);
131
132         public void setInactive()
133         {
134             active_.set(false);
135
136             interrupt();
137         }
138
139         private void ensureIsActive() throws InterruptedException JavaDoc
140         {
141             if (!active_.get())
142             {
143                 throw new InterruptedException JavaDoc();
144             }
145         }
146
147         public void run()
148         {
149             try
150             {
151                 while (active_.get())
152                 {
153                     try
154                     {
155                         runLoop();
156                     } catch (InterruptedException JavaDoc e)
157                     {
158                         sLogger_.info("PoolCleaner was interrupted");
159                     } catch (Exception JavaDoc e)
160                     {
161                         sLogger_.error("Error cleaning Pool", e);
162                     }
163                 }
164             } finally
165             {
166                 synchronized (AbstractObjectPool.class)
167                 {
168                     sCleanerThread = null;
169                 }
170             }
171         }
172
173         private void runLoop() throws InterruptedException JavaDoc
174         {
175             while (true)
176             {
177                 try
178                 {
179                     sleep(SLEEP);
180                 } catch (InterruptedException JavaDoc ie)
181                 {
182                     // ignore here.
183
// ensureIsActive is called below to see if this Thread should
184
// still be active.
185
}
186
187                 ensureIsActive();
188
189                 Runnable JavaDoc[] poolsToCheck = getAllPools();
190
191                 for (int x = 0; x < poolsToCheck.length; ++x)
192                 {
193                     try
194                     {
195                         poolsToCheck[x].run();
196                     } catch (Throwable JavaDoc t)
197                     {
198                         // should not happen
199
sLogger_.error("Error cleaning up Pool", t);
200                     }
201                 }
202             }
203         }
204     }
205
206     private static ListCleaner getListCleaner()
207     {
208         synchronized (AbstractObjectPool.class)
209         {
210             if (sListCleaner == null)
211             {
212                 sListCleaner = new ListCleaner();
213             }
214             return sListCleaner;
215         }
216     }
217
218     private static void stopListCleaner()
219     {
220         synchronized (AbstractObjectPool.class)
221         {
222             if (sCleanerThread != null)
223             {
224                 sListCleaner.setInactive();
225             }
226         }
227     }
228
229     private static void startListCleaner()
230     {
231         synchronized (AbstractObjectPool.class)
232         {
233             if (sCleanerThread == null && sUseListCleaner )
234             {
235                 sCleanerThread = new Thread JavaDoc(getListCleaner());
236
237                 sCleanerThread.setName("ObjectPoolCleaner");
238                 sCleanerThread.setPriority(Thread.MIN_PRIORITY + 1);
239                 sCleanerThread.setDaemon(true);
240                 sCleanerThread.start();
241             }
242         }
243     }
244
245     private final String JavaDoc name_;
246
247     private final DisposableManager disposeHooks_ = new DisposableManager();
248
249     private final LinkedList JavaDoc pool_;
250
251     private boolean isInitialized_;
252
253     /**
254      * Set that contains all objects that were created by this pool and are in use. Problems occured
255      * as access to this member used to be non-synchronized see
256      * news://news.gmane.org:119/200406041629.48096.Farrell_John_W@cat.com
257      */

258     private final Set JavaDoc active_ = Collections.synchronizedSet(new WeakHashSet());
259
260     /**
261      * lower watermark. if pool size is below that value, create sizeIncrease_ new elements.
262      */

263     private int lowerWatermark_;
264
265     /**
266      * how many instances should the pool maximal keep. instances that are returned to a pool which
267      * size is greater than maxWatermark_ are discarded and left for the Garbage Collector.
268      */

269     private int maxWatermark_;
270
271     /**
272      * how many instances should be created if pool size falls below lowerWatermark_.
273      */

274     private int sizeIncrease_;
275
276     /**
277      * how many instances should be created at startup of the pool.
278      */

279     private int initialSize_;
280
281     private int maximumSize_;
282
283     protected final Logger logger_ = LogUtil.getLogger(getClass().getName());
284
285     protected Configuration config_;
286
287     public void configure(Configuration conf)
288     {
289         config_ = conf;
290         
291         init();
292     }
293
294     protected AbstractObjectPool(String JavaDoc name)
295     {
296         this(name, LOWER_WATERMARK_DEFAULT, SIZE_INCREASE_DEFAULT, INITIAL_SIZE_DEFAULT,
297                 MAXIMUM_WATERMARK_DEFAULT, MAXIMUM_SIZE_DEFAULT);
298     }
299
300     protected AbstractObjectPool(String JavaDoc name, int lowerWatermark, int sizeincrease,
301             int initialsize, int maxWatermark, int maximumSize)
302     {
303         if (maximumSize > 0 && initialsize > maximumSize)
304         {
305             throw new IllegalArgumentException JavaDoc("InitialSize: " + initialsize
306                     + " may not be larger than MaximumSize: " + maximumSize);
307         }
308
309         name_ = name;
310         pool_ = new LinkedList JavaDoc();
311         lowerWatermark_ = lowerWatermark;
312         sizeIncrease_ = sizeincrease;
313         initialSize_ = initialsize;
314         maxWatermark_ = maxWatermark;
315         maximumSize_ = maximumSize;
316     }
317
318     public void addDisposeHook(Disposable d)
319     {
320         disposeHooks_.addDisposable(d);
321     }
322
323     public void run()
324     {
325         final int maxToBeCreated;
326
327         synchronized (pool_)
328         {
329             if (pool_.size() > lowerWatermark_)
330             {
331                 return;
332             }
333
334             maxToBeCreated = getNumberOfCreationsAllowed();
335         }
336
337         final int sizeIncrease = Math.min(sizeIncrease_, maxToBeCreated);
338
339         if (sizeIncrease > 0)
340         {
341             List JavaDoc os = new ArrayList JavaDoc(sizeIncrease);
342
343             for (int x = 0; x < sizeIncrease; ++x)
344             {
345                 Object JavaDoc _i = createInstance();
346
347                 os.add(_i);
348             }
349
350             synchronized (pool_)
351             {
352                 pool_.addAll(os);
353             }
354         }
355     }
356
357     /**
358      * check the number of instances that are allowed to be created.
359      *
360      * @pre lock pool_ must be held.
361      */

362     private int getNumberOfCreationsAllowed()
363     {
364         final int maxToBeCreated;
365
366         if (maximumSize_ > 0)
367         {
368             maxToBeCreated = maximumSize_ - active_.size() - pool_.size();
369         }
370         else
371         {
372             maxToBeCreated = Integer.MAX_VALUE;
373         }
374
375         return maxToBeCreated;
376     }
377
378     private Object JavaDoc createInstance()
379     {
380         Object JavaDoc _i = newInstance();
381
382         return _i;
383     }
384
385     /**
386      * Initialize this Pool. An initial Number of Objects is created. Cleanup Thread is started.
387      */

388     private void init()
389     {
390         registerPool(this);
391         
392         synchronized (pool_)
393         {
394             if (isInitialized_)
395             {
396                 throw new IllegalStateException JavaDoc("Already Initialized");
397             }
398
399             for (int x = 0; x < initialSize_; ++x)
400             {
401                 Object JavaDoc _i = createInstance();
402
403                 pool_.add(_i);
404             }
405
406             isInitialized_ = true;
407         }
408     }
409
410     /**
411      * Release this Pool.
412      */

413     public void dispose()
414     {
415         deregisterPool(this);
416         disposeCollection(pool_);
417         pool_.clear();
418         disposeCollection(active_);
419         active_.clear();
420
421         disposeHooks_.dispose();
422     }
423
424     private void disposeCollection(Collection JavaDoc c)
425     {
426         Iterator JavaDoc i = c.iterator();
427
428         while (i.hasNext())
429         {
430             Object JavaDoc o = i.next();
431
432             try
433             {
434                 Disposable disposable = (Disposable) o;
435
436                 try
437                 {
438                     ((AbstractPoolable) o).setObjectPool(null);
439                 } catch (ClassCastException JavaDoc e)
440                 {
441                     // ignored
442
}
443
444                 disposable.dispose();
445             } catch (ClassCastException JavaDoc e)
446             {
447                 // ignored
448
}
449         }
450     }
451
452     /**
453      * lend an object from the pool.
454      */

455     public Object JavaDoc lendObject()
456     {
457         checkIsInitialized();
458
459         Object JavaDoc _ret = null;
460
461         synchronized (pool_)
462         {
463             if (!pool_.isEmpty())
464             {
465                 _ret = pool_.removeFirst();
466             }
467
468             if (_ret == null)
469             {
470                 while (!isCreationAllowed())
471                 {
472                     poolIsEmpty();
473                 }
474             }
475         }
476
477         if (_ret == null)
478         {
479             _ret = createInstance();
480         }
481
482         try
483         {
484             ((Configurable) _ret).configure(this.config_);
485         } catch (ClassCastException JavaDoc cce)
486         {
487             // no worries, just don't configure
488
} catch (ConfigurationException ce)
489         {
490             throw new RuntimeException JavaDoc("Could not configure instance");
491         }
492
493         activateObject(_ret);
494         active_.add(_ret);
495
496         return _ret;
497     }
498
499     /**
500      *
501      */

502     private void checkIsInitialized()
503     {
504         synchronized (pool_)
505         {
506             if (!isInitialized_)
507             {
508                 throw new IllegalStateException JavaDoc("Not initialized");
509             }
510         }
511     }
512
513     /**
514      * check if it is allowed to create more instances.
515      *
516      * @pre lock pool_ must be held.
517      */

518     private boolean isCreationAllowed()
519     {
520         return getNumberOfCreationsAllowed() > 0;
521     }
522
523     /**
524      *
525      */

526     private void poolIsEmpty()
527     {
528         throw new RuntimeException JavaDoc(name_ + ": No more Elements allowed. " + getInfo());
529     }
530
531     /**
532      * return an Object to the pool.
533      */

534     public void returnObject(Object JavaDoc o)
535     {
536         checkIsInitialized();
537
538         if (active_.remove(o))
539         {
540             passivateObject(o);
541
542             if (pool_.size() < maxWatermark_)
543             {
544                 synchronized (pool_)
545                 {
546                     pool_.add(o);
547                     pool_.notifyAll();
548                 }
549             }
550             else
551             {
552                 destroyObject(o);
553             }
554         }
555         else
556         {
557             throw new RuntimeException JavaDoc("Object " + o + " was not created here");
558         }
559     }
560
561     public String JavaDoc toString()
562     {
563         return name_ + " " + getInfo();
564     }
565
566     private String JavaDoc getInfo()
567     {
568         return "Active=" + active_.size() + " Pooled=" + pool_.size() + " MaximumSize="
569                 + ((maximumSize_ > 0) ? Integer.toString(maximumSize_) : "unlimited");
570     }
571
572     /**
573      * This method is called by the Pool to create a new Instance. Subclasses must override
574      * appropiately .
575      */

576     public abstract Object JavaDoc newInstance();
577
578     /**
579      * Is called after Object is returned to pool. No Op.
580      */

581     public void passivateObject(Object JavaDoc o)
582     {
583         // No Op
584
}
585
586     /**
587      * Is called before Object is returned to Client (lendObject). No Op
588      */

589     public void activateObject(Object JavaDoc o)
590     {
591         // No Op
592
}
593
594     /**
595      * Is called if Pool is full and returned Object is discarded. No Op.
596      */

597     public void destroyObject(Object JavaDoc o)
598     {
599         // No Op
600
}
601 }
Popular Tags