KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > ejb > containers > util > pool > NonBlockingPool


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 /**
25  * <BR> <I>$Source: /cvs/glassfish/appserv-core/src/java/com/sun/ejb/containers/util/pool/NonBlockingPool.java,v $</I>
26  * @author $Author: tcfujii $
27  * @version $Revision: 1.3 $ $Date: 2005/12/25 04:13:35 $
28  */

29  
30
31 package com.sun.ejb.containers.util.pool;
32
33 import java.util.*;
34
35 import com.sun.ejb.containers.ContainerFactoryImpl;
36 import java.util.logging.*;
37 import java.util.TimerTask JavaDoc;
38 import com.sun.logging.*;
39
40 import com.sun.enterprise.util.Utility;
41 import com.sun.ejb.containers.EJBContextImpl;
42
43 import com.sun.enterprise.util.threadpool.Servicable;
44 import com.sun.ejb.containers.util.ContainerWorkPool;
45
46 /**
47  * <p>NonBlockingPool pool provides the basic implementation of an object
48  * pool. The implementation uses a linked list to maintain a list of
49  * (available) objects. If the pool is empty it simply creates one using the
50  * ObjectFactory instance. Subclasses can change this behaviour by overriding
51  * getObject(...) and returnObject(....) methods. This class provides basic
52  * support for synchronization, event notification, pool shutdown
53  * and pool object recycling. It also does some very basic bookkeeping like the
54  * number of objects created, number of threads waiting for object.
55  * <p> Subclasses can make use of these book-keeping data to provide complex
56  * pooling mechanism like LRU / MRU / Random. Also, note that AbstractPool
57  * does not have a notion of pool limit. It is upto to the derived classes
58  * to implement these features.
59  *
60  */

61
62
63 public class NonBlockingPool
64     extends AbstractPool
65 {
66
67     private String JavaDoc poolName;
68     private TimerTask JavaDoc poolTimerTask;
69     protected boolean addedResizeTask = false;
70     protected boolean addedIdleBeanWork = false;
71     protected boolean inResizing = false;
72     private boolean maintainSteadySize = false;
73     
74     private int resizeTaskCount;
75     private int timerTaskCount;
76
77     protected NonBlockingPool() {
78     }
79
80     public NonBlockingPool(String JavaDoc poolName, ObjectFactory factory,
81         int steadyPoolSize, int resizeQuantity,
82         int maxPoolSize, int idleTimeoutInSeconds,
83         ClassLoader JavaDoc loader)
84     {
85         this.poolName = poolName;
86         initializePool(factory, steadyPoolSize, resizeQuantity, maxPoolSize,
87                        idleTimeoutInSeconds, loader);
88     }
89
90     protected void initializePool(ObjectFactory factory, int steadyPoolSize,
91         int resizeQuantity, int maxPoolSize, int idleTimeoutInSeconds,
92         ClassLoader JavaDoc loader)
93     {
94         list = new ArrayList();
95         
96         this.factory = factory;
97         this.steadyPoolSize = (steadyPoolSize <= 0) ? 0 : steadyPoolSize;
98         this.resizeQuantity = (resizeQuantity <= 0) ? 0 : resizeQuantity;
99         this.maxPoolSize = (maxPoolSize <= 0)
100             ? Integer.MAX_VALUE : maxPoolSize;
101         this.steadyPoolSize = (this.steadyPoolSize > this.maxPoolSize)
102             ? this.maxPoolSize : this.steadyPoolSize;
103         this.idleTimeoutInSeconds =
104             (idleTimeoutInSeconds <= 0) ? 0 : idleTimeoutInSeconds;
105         
106         this.containerClassLoader = loader;
107         
108         this.maintainSteadySize = (this.steadyPoolSize > 0);
109         if ((this.idleTimeoutInSeconds > 0) && (this.resizeQuantity > 0)) {
110             try {
111                 this.poolTimerTask = new PoolResizeTimerTask();
112                 ContainerFactoryImpl.getTimer().scheduleAtFixedRate
113                     (poolTimerTask, idleTimeoutInSeconds*1000,
114                      idleTimeoutInSeconds*1000);
115                 if(_logger.isLoggable(Level.FINE)) {
116                     _logger.log(Level.FINE,
117                       "[Pool-" + poolName + "]: Added PoolResizeTimerTask...");
118                 }
119             } catch (Throwable JavaDoc th) {
120                 _logger.log(Level.WARNING,"[Pool-" +
121                             poolName + "]: Could not add"
122                             + " PoolTimerTask. Continuing anyway...", th);
123             }
124         }
125     }
126     
127
128     public void setContainerClassLoader(ClassLoader JavaDoc loader) {
129         this.containerClassLoader = loader;
130     }
131     
132     /**
133      * Get an object. Application can use pool.getObject() to get an object
134      * instead of using new XXX().
135      * @param canWait Must be true if the calling thread is willing to
136      * wait for infinite time to get an object, false if the calling
137      * thread does not want to wait at all.
138      *
139      */

140     public Object JavaDoc getObject(boolean canWait, Object JavaDoc param)
141         throws PoolException
142     {
143         return getObject(param);
144     }
145
146     public Object JavaDoc getObject(long maxWaitTime, Object JavaDoc param)
147         throws PoolException
148     {
149         return getObject(param);
150     }
151
152     public Object JavaDoc getObject(Object JavaDoc param)
153     {
154         boolean toAddResizeTask = false;
155         Object JavaDoc obj = null;
156         synchronized (list) {
157             int size = list.size();
158             if (size > steadyPoolSize) {
159                 poolSuccess++;
160                 return list.remove(size-1);
161             } else if (size > 0) {
162                 poolSuccess++;
163                 if ((maintainSteadySize) && (addedResizeTask == false)) {
164                     toAddResizeTask = addedResizeTask = true;
165                     obj = list.remove(size-1);
166                 } else {
167                     return list.remove(size-1);
168                 }
169             } else {
170                 if ((maintainSteadySize) && (addedResizeTask == false)) {
171                     toAddResizeTask = addedResizeTask = true;
172                 }
173                 createdCount++; //hope that everything will be OK.
174
}
175         }
176         
177         if (toAddResizeTask) {
178             addResizeTaskForImmediateExecution();
179         }
180         
181         if (obj != null) {
182             return obj;
183         }
184         
185         try {
186             return factory.create(param);
187         } catch (RuntimeException JavaDoc th) {
188             synchronized (list) {
189                 createdCount--;
190             }
191             throw th;
192         }
193     }
194     
195     private void addResizeTaskForImmediateExecution() {
196         try {
197             ReSizeWork work = new ReSizeWork();
198             ContainerWorkPool.addLast(work);
199             if(_logger.isLoggable(Level.FINE)) {
200                 _logger.log(Level.FINE,
201                      "[Pool-" + poolName + "]: Added PoolResizeTimerTask...");
202             }
203             resizeTaskCount++;
204         } catch (Exception JavaDoc ex) {
205             synchronized (list) {
206                 addedResizeTask = false;
207             }
208             if(_logger.isLoggable(Level.WARNING)) {
209                 _logger.log(Level.WARNING,
210                             "[Pool-"+poolName+"]: Cannot perform "
211                             + " pool resize task", ex);
212             }
213         }
214     }
215
216     /**
217      * Return an object back to the pool. An object that is obtained through
218      * getObject() must always be returned back to the pool using either
219      * returnObject(obj) or through destroyObject(obj).
220      */

221     public void returnObject(Object JavaDoc object) {
222         synchronized (list) {
223             if (list.size() < maxPoolSize) {
224                 list.add(object);
225                 return;
226             } else {
227                 destroyedCount++;
228             }
229         }
230         
231         try {
232             factory.destroy(object);
233         } catch (Exception JavaDoc ex) {
234             _logger.log(Level.FINE, "exception in returnObj", ex);
235         }
236     }
237
238     /**
239      * Destroys an Object. Note that applications should not ignore
240      * the reference to the object that they got from getObject(). An object
241      * that is obtained through getObject() must always be returned back to
242      * the pool using either returnObject(obj) or through destroyObject(obj).
243      * This method tells that the object should be destroyed and cannot
244      * be reused.
245      */

246     public void destroyObject(Object JavaDoc object) {
247         synchronized (list) {
248             destroyedCount++;
249         }
250         
251         try {
252             factory.destroy(object);
253         } catch (Exception JavaDoc ex) {
254             _logger.log(Level.FINE, "exception in destroyObject", ex);
255         }
256     }
257     
258     /**
259     * Preload the pool with objects.
260     * @param count the number of objects to be added.
261     */

262     protected void preload(int count) {
263         
264         ArrayList instances = new ArrayList(count);
265         try {
266             for (int i=0; i<count; i++) {
267                 instances.add(factory.create(null));
268             }
269         } catch (Exception JavaDoc ex) {
270             //Need not throw this exception up since we are pre-populating
271
}
272
273         int sz = instances.size();
274         if (sz == 0) {
275             return;
276         }
277         synchronized (list) {
278             for (int i=0; i<sz; i++) {
279                 list.add(instances.get(i));
280             }
281             createdCount += sz;
282         }
283     }
284
285     /**
286     * Prepopulate the pool with objects.
287     * @param count the number of objects to be added.
288     */

289     public void prepopulate(int count) {
290         this.steadyPoolSize = (count <= 0) ? 0 : count;
291         this.steadyPoolSize = (this.steadyPoolSize > this.maxPoolSize)
292             ? this.maxPoolSize : this.steadyPoolSize;
293     
294         if (this.steadyPoolSize > 0) {
295             preload(this.steadyPoolSize);
296         }
297             
298     }
299  
300     /**
301     * Close the pool
302     */

303     public void close() {
304         synchronized (list) {
305             if (poolTimerTask != null) {
306                 try {
307                     poolTimerTask.cancel();
308                     if(_logger.isLoggable(Level.FINE)) {
309                         _logger.log(Level.FINE,
310                             "[Pool-"+poolName+"]: Cancelled pool timer task "
311                                     + " at: " + (new java.util.Date JavaDoc()));
312                     }
313                 } catch (Throwable JavaDoc th) {
314                     //Can safely ignore this!!
315
}
316             }
317     
318             if(_logger.isLoggable(Level.FINE)) {
319                 _logger.log(Level.FINE,"[Pool-"+poolName+"]: Destroying "
320                             + list.size() + " beans from the pool...");
321             }
322     
323             // since we're calling into ejb code, we need to set context
324
// class loader
325
ClassLoader JavaDoc origLoader =
326                 Utility.setContextClassLoader(containerClassLoader);
327
328             Object JavaDoc[] array = list.toArray();
329             for (int i=0; i<array.length; i++) {
330                 try {
331                     destroyedCount++;
332                     try {
333                         factory.destroy(array[i]);
334                     } catch (Throwable JavaDoc th) {
335                         _logger.log(Level.FINE, "exception in close", th);
336                     }
337                 } catch (Throwable JavaDoc th) {
338                     _logger.log(Level.WARNING,
339                         "[Pool-"+poolName+"]: Error while destroying", th);
340                 }
341             }
342             if(_logger.isLoggable(Level.FINE)) {
343                 _logger.log(Level.FINE,"Pool-"+poolName+"]: Pool closed....");
344             }
345             list.clear();
346
347             Utility.setContextClassLoader(origLoader);
348         }
349
350         // helps garbage collection
351
this.list = null;
352         this.factory = null;
353         this.poolTimerTask = null;
354         this.containerClassLoader = null;
355         
356     }
357
358     protected void remove(int count) {
359         ArrayList removeList = new ArrayList();
360         synchronized (list) {
361             int size = list.size();
362             for (int i=0; (i<count) && (size > 0); i++) {
363                 removeList.add(list.remove(--size));
364                 destroyedCount++;
365             }
366         }
367         
368         int sz = removeList.size();
369         for (int i=0; i<sz; i++) {
370             try {
371                 factory.destroy(removeList.get(i));
372             } catch (Throwable JavaDoc th) {
373                 _logger.log(Level.FINE, "exception in remove", th);
374             }
375         }
376     }
377
378     protected void removeIdleObjects() {
379     }
380     
381     protected void doResize() {
382         
383         //We need to set the context class loader for this (deamon) thread!!
384
final Thread JavaDoc currentThread = Thread.currentThread();
385         final ClassLoader JavaDoc previousClassLoader =
386             currentThread.getContextClassLoader();
387         final ClassLoader JavaDoc ctxClassLoader = containerClassLoader;
388     
389         long startTime = 0;
390         boolean enteredResizeBlock = false;
391         try {
392             
393             java.security.AccessController.doPrivileged(
394                 new java.security.PrivilegedAction JavaDoc() {
395                 public java.lang.Object JavaDoc run() {
396                     currentThread.setContextClassLoader(ctxClassLoader);
397                     return null;
398                 }
399             });
400
401             if(_logger.isLoggable(Level.FINE)) {
402                 _logger.log(Level.FINE,
403                     "[Pool-"+poolName+"]: Resize started at: "
404                   + (new java.util.Date JavaDoc())+" steadyPoolSize ::"+steadyPoolSize
405                   + " resizeQuantity ::"+resizeQuantity+" maxPoolSize ::" +
406                   maxPoolSize );
407             }
408             startTime = System.currentTimeMillis();
409
410             ArrayList removeList = new ArrayList();
411             int populateCount = 0;
412             synchronized (list) {
413                 if (inResizing == true) {
414                     return;
415                 }
416
417                 enteredResizeBlock = true;
418                 inResizing = true;
419                 
420                 int curSize = list.size();
421
422                 if (curSize > steadyPoolSize) {
423
424                     //possible to reduce pool size....
425
if ((idleTimeoutInSeconds <= 0) ||
426                         (resizeQuantity <= 0)) {
427                         return;
428                     }
429                     int victimCount =
430                         (curSize > (steadyPoolSize + resizeQuantity) )
431                         ? resizeQuantity : (curSize - steadyPoolSize);
432                     long allowedIdleTime = System.currentTimeMillis() -
433                         idleTimeoutInSeconds*1000;
434                     if(_logger.isLoggable(Level.FINE)) {
435                         _logger.log(Level.FINE,
436                                     "[Pool-"+poolName+"]: Resize:: reducing "
437                                     + " pool size by: " + victimCount);
438                     }
439                     for (int i=0; i<victimCount; i++) {
440                         //removeList.add(list.remove(--curSize));
441
//destroyedCount++;
442
EJBContextImpl ctx = (EJBContextImpl) list.get(0);
443                         if (ctx.getLastTimeUsed() <= allowedIdleTime) {
444                             removeList.add(list.remove(0));
445                             destroyedCount++;
446                         } else {
447                             break;
448                         }
449                     }
450                 } else if (curSize < steadyPoolSize) {
451
452                     //Need to populate....
453
if (maintainSteadySize == false) {
454                         return;
455                     }
456
457                     if (resizeQuantity <= 0) {
458                         populateCount = steadyPoolSize - curSize;
459                     } else {
460                         while ((curSize + populateCount) < steadyPoolSize) {
461                             populateCount += resizeQuantity;
462                         }
463                         if ((curSize + populateCount) > maxPoolSize) {
464                             populateCount -= (curSize + populateCount) - maxPoolSize;
465                         }
466                     }
467                 }
468             }
469             
470             if (removeList.size() > 0) {
471                 int sz = removeList.size();
472                 for (int i=0; i<sz; i++) {
473                     try {
474                         factory.destroy(removeList.get(i));
475                     } catch (Throwable JavaDoc th) {
476                         _logger.log(Level.FINE, "exception in doResize", th);
477                     }
478                 }
479             }
480
481             if (populateCount > 0) {
482                 //preload adds items inside a sync block....
483

484                 if(_logger.isLoggable(Level.FINE)) {
485                     _logger.log(Level.FINE,
486                             "[Pool-"+poolName+"]: Attempting to preload "
487                             + populateCount + " beans. CurSize/MaxPoolSize: "
488                             + list.size() + "/" + maxPoolSize);
489                 }
490
491                 preload(populateCount);
492
493                 if(_logger.isLoggable(Level.FINE)) {
494                     _logger.log(Level.FINE,
495                             "[Pool-"+poolName+"]: After preload "
496                             + "CurSize/MaxPoolSize: "
497                             + list.size() + "/" + maxPoolSize);
498                 }
499             }
500             
501             
502         } catch (Throwable JavaDoc th) {
503             _logger.log(Level.WARNING,
504                         "[Pool-"+poolName+"]: Exception during reSize", th);
505
506         } finally {
507             
508             if (enteredResizeBlock) {
509                 synchronized (list) {
510                     inResizing = false;
511                 }
512             }
513             
514             java.security.AccessController.doPrivileged(
515                 new java.security.PrivilegedAction JavaDoc() {
516                 public java.lang.Object JavaDoc run() {
517                     currentThread.setContextClassLoader(previousClassLoader);
518                     return null;
519                 }
520             });
521         }
522
523         long endTime = System.currentTimeMillis();
524         if(_logger.isLoggable(Level.FINE)) {
525             _logger.log(Level.FINE,
526                 "[Pool-"+poolName+"]: Resize completed at: "
527                 + (new java.util.Date JavaDoc()) + "; after reSize: " +
528                 getAllAttrValues());
529             _logger.log(Level.FINE, "[Pool-"+poolName+"]: Resize took: "
530                         + ((endTime-startTime)/1000.0) + " seconds.");
531         }
532     }
533
534     public String JavaDoc getAllAttrValues() {
535         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc("[Pool-"+poolName+"] ");
536         sbuf.append("CC=").append(createdCount).append("; ")
537             .append("DC=").append(destroyedCount).append("; ")
538             .append("CS=").append(list.size()).append("; ")
539             .append("SS=").append(steadyPoolSize).append("; ")
540             .append("MS=").append(maxPoolSize).append(";");
541         return sbuf.toString();
542     }
543
544     private class ReSizeWork
545         implements Servicable
546     {
547         public void prolog() {
548         }
549         
550         public void service() {
551             run();
552         }
553         
554         public void epilog() {
555         }
556
557         public void run() {
558             try {
559                 doResize();
560             } catch (Exception JavaDoc ex) {
561                 _logger.log(Level.WARNING,
562                     "[Pool-"+poolName+"]: Exception during reSize", ex);
563             } finally {
564                 synchronized (list) {
565                     addedResizeTask = false;
566                 }
567             }
568         }
569     }
570
571     private class IdleBeanWork
572         implements Servicable
573     {
574         public void prolog() {
575         }
576         
577         public void service() {
578             run();
579         }
580         
581         public void epilog() {
582         }
583         
584         public void run() {
585             try {
586                 doResize();
587             } catch (Exception JavaDoc ex) {
588             } finally {
589                 addedIdleBeanWork = false;
590             }
591         }
592     }
593
594     private class PoolResizeTimerTask
595         extends java.util.TimerTask JavaDoc
596     {
597         Object JavaDoc lock;
598         
599         PoolResizeTimerTask() {}
600         
601         PoolResizeTimerTask(Object JavaDoc lock) {
602             this.lock = lock;
603         }
604         
605         public void run() {
606             
607             try {
608                 if (addedIdleBeanWork == true) {
609                     return;
610                 }
611                 IdleBeanWork work = new IdleBeanWork();
612                 ContainerWorkPool.addLast(work);
613                 addedIdleBeanWork = true;
614             } catch (Exception JavaDoc ex) {
615                 _logger.log(Level.WARNING,
616                             "[Pool-"+poolName+"]: Cannot perform "
617                             + " pool idle bean cleanup", ex);
618             }
619     
620         }
621     } // End of class PoolResizeTimerTask
622

623 }
624
Popular Tags