KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > ejb > containers > 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 /**
25  * <BR> <I>$Source: /cvs/glassfish/appserv-core/src/java/com/sun/ejb/containers/util/pool/AbstractPool.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.ArrayList JavaDoc;
34 import java.util.logging.*;
35
36 import com.sun.enterprise.util.Utility;
37 import com.sun.ejb.containers.ContainerFactoryImpl;
38 import com.sun.logging.*;
39
40 /**
41  * <p>Abstract pool provides the basic implementation of an object pool.
42  * The implementation uses a linked list to maintain a list of (available)
43  * objects. If the pool is empty it simply creates one using the ObjectFactory
44  * instance. Subclasses can change this behaviour by overriding getObject(...)
45  * and returnObject(....) methods. This class provides basic support for
46  * synchronization, event notification, pool shutdown and pool object
47  * recycling. It also does some very basic bookkeeping like the
48  * number of objects created, number of threads waiting for object.
49  * <p> Subclasses can make use of these book-keeping data to provide complex
50  * pooling mechanism like LRU / MRU / Random. Also, note that AbstractPool
51  * does not have a notion of pool limit. It is upto to the derived classes
52  * to implement these features.
53  */

54 public abstract class AbstractPool
55     implements Pool, com.sun.ejb.spi.stats.EJBPoolStatsProvider
56 {
57
58     protected static Logger _logger;
59     static
60     {
61         _logger=LogDomains.getLogger(LogDomains.EJB_LOGGER);
62     }
63
64     protected ArrayList JavaDoc list;
65     protected ObjectFactory factory = null;
66     protected int waitCount = 0;
67     protected int createdCount = 0;
68
69     protected int steadyPoolSize;
70     protected int resizeQuantity = 1;
71     protected int maxPoolSize = Integer.MAX_VALUE;
72     protected long maxWaitTimeInMillis;
73     protected int idleTimeoutInSeconds;
74
75
76     private AbstractPoolTimerTask poolTimerTask;
77
78     // class loader used as context class loader for asynchronous operations
79
protected ClassLoader JavaDoc containerClassLoader;
80
81     protected int destroyedCount = 0;
82     protected int poolSuccess = 0;
83     protected String JavaDoc poolName;
84     protected int poolReturned = 0;
85
86     protected String JavaDoc configData;
87
88     protected AbstractPool() {
89     }
90
91     protected AbstractPool(ObjectFactory factory, int steadyPoolSize,
92        int resizeQuantity, int maxPoolsize, long maxWaitTimeInMillis,
93                            int idleTimeoutInSeconds, ClassLoader JavaDoc loader) {
94         initializePool(factory, steadyPoolSize, resizeQuantity, maxPoolsize,
95                        maxWaitTimeInMillis, idleTimeoutInSeconds, loader);
96     }
97
98     protected void initializePool(ObjectFactory factory, int steadyPoolSize,
99         int resizeQuantity, int maxPoolsize, long maxWaitTimeInMillis,
100         int idleTimeoutInSeconds, ClassLoader JavaDoc loader) {
101
102         list = new ArrayList JavaDoc();
103         
104         this.factory = factory;
105         this.steadyPoolSize = steadyPoolSize;
106         this.resizeQuantity = resizeQuantity;
107         this.maxPoolSize = maxPoolsize;
108         this.maxWaitTimeInMillis = maxWaitTimeInMillis;
109         this.idleTimeoutInSeconds = idleTimeoutInSeconds;
110         
111         if (steadyPoolSize > 0) {
112             for (int i=0; i<steadyPoolSize; i++) {
113                 list.add(factory.create(null));
114                 createdCount++;
115             }
116         }
117         
118         this.containerClassLoader = loader;
119         
120         if (this.idleTimeoutInSeconds > 0) {
121             try {
122                 this.poolTimerTask = new AbstractPoolTimerTask();
123                 ContainerFactoryImpl.getTimer().scheduleAtFixedRate
124                     (poolTimerTask, idleTimeoutInSeconds*1000,
125                      idleTimeoutInSeconds*1000);
126             } catch (Throwable JavaDoc th) {
127                 _logger.log(Level.WARNING,
128                     "[AbstractPool]: Could not add AbstractPoolTimerTask" +
129                     " ... Continuing anyway...");
130             }
131         }
132     }
133     
134
135     public void setContainerClassLoader(ClassLoader JavaDoc loader) {
136         this.containerClassLoader = loader;
137     }
138     
139     /**
140      * Get an object. Application can use pool.getObject() to get an object
141      * instead of using new XXX().
142      * @param canWait Must be true if the calling thread is willing to
143      * wait for infinite time to get an object, false if the calling thread
144      * does not want to wait at all.
145      *
146      */

147     public Object JavaDoc getObject(boolean canWait, Object JavaDoc param)
148         throws PoolException
149     {
150         return getObject(param);
151     }
152
153     public Object JavaDoc getObject(long maxWaitTime, Object JavaDoc param)
154         throws PoolException
155     {
156         return getObject(param);
157     }
158
159     public Object JavaDoc getObject(Object JavaDoc param)
160         throws PoolException
161     {
162         long t1=0, totalWaitTime = 0;
163         int size;
164
165         synchronized (list) {
166             while (true) {
167                 if ((size = list.size()) > 0) {
168                     poolSuccess++;
169                     return list.remove(size-1);
170                 } else if ((createdCount - destroyedCount) < maxPoolSize) {
171                     createdCount++; //hope that everything will be OK.
172
break;
173                 }
174                     
175                 if (maxWaitTimeInMillis >= 0) {
176                     waitCount++;
177                     t1 = System.currentTimeMillis();
178                     try {
179                         _logger.log(Level.FINE, "[AbstractPool]: Waiting on" +
180                                     " the pool to get a bean instance...");
181                         list.wait(maxWaitTimeInMillis);
182                     } catch (InterruptedException JavaDoc inEx) {
183                         throw new PoolException("Thread interrupted.", inEx);
184                     }
185                     waitCount--;
186                     totalWaitTime += System.currentTimeMillis() - t1;
187                     if ((size = list.size()) > 0) {
188                         poolSuccess++;
189                         return list.remove(size-1);
190                     } else if (maxWaitTimeInMillis == 0) {
191                         // nothing special to do in this case
192
} else if (totalWaitTime >= maxWaitTimeInMillis) {
193                         throw new PoolException("Pool Instance not obtained" +
194                            " within given time interval.");
195                     }
196                 } else {
197                     throw new PoolException("Pool Instance not obtained" +
198                                             " within given time interval.");
199                 }
200             }
201         }
202             
203         try {
204             return factory.create(param);
205         } catch (Exception JavaDoc poolEx) {
206             synchronized (list) {
207                 createdCount--;
208             }
209             throw new RuntimeException JavaDoc("Caught Exception when trying " +
210                                        "to create pool Object ", poolEx);
211         }
212     }
213     
214     /**
215      * Return an object back to the pool. An object that is obtained through
216      * getObject() must always be returned back to the pool using either
217      * returnObject(obj) or through destroyObject(obj).
218      */

219     public void returnObject(Object JavaDoc object) {
220         synchronized (list) {
221             list.add(object);
222             poolReturned++;
223             if (waitCount > 0) {
224                 list.notify();
225             }
226         }
227     }
228
229     /**
230      * Destroys an Object. Note that applications should not ignore the
231      * reference to the object that they got from getObject(). An object
232      * that is obtained through getObject() must always be returned back to
233      * the pool using either returnObject(obj) or through destroyObject(obj).
234      * This method tells that the object should be destroyed and cannot
235      * be reused.
236      */

237     public void destroyObject(Object JavaDoc object) {
238         synchronized (list) {
239             destroyedCount++;
240             if (waitCount > 0) {
241                 list.notify();
242             }
243         }
244         try {
245             factory.destroy(object);
246         } catch (Exception JavaDoc ex) {
247             _logger.log(Level.FINE, "Exception in destroyObject()", ex);
248         }
249     }
250     
251     /**
252     * Preload the pool with objects.
253     * @param count the number of objects to be added.
254     */

255     protected void preload(int count) {
256         
257         synchronized (list) {
258             for (int i=0; i<count; i++) {
259                 try {
260                     list.add(factory.create(null));
261                     createdCount++;
262                 } catch (PoolException poolEx) {
263                     _logger.log(Level.FINE, "Exception in preload()", poolEx);
264                 }
265             }
266         }
267     }
268     
269     /**
270     * Close the pool
271     */

272     public void close() {
273         synchronized (list) {
274             if (poolTimerTask != null) {
275                 try {
276                     poolTimerTask.cancel();
277                     _logger.log(Level.WARNING,
278                                 "[AbstractPool]: Cancelled pool timer task "
279                                 + " at: " + (new java.util.Date JavaDoc()));
280                 } catch (Throwable JavaDoc th) {
281                     //Can safely ignore this!!
282
}
283             }
284             _logger.log(Level.FINE,"[AbstractPool]: Destroying "
285                         + list.size() + " beans from the pool...");
286
287             // since we're calling into ejb code, we need to set context
288
// class loader
289
ClassLoader JavaDoc origLoader =
290                 Utility.setContextClassLoader(containerClassLoader);
291
292             Object JavaDoc[] array = list.toArray();
293             for (int i=0; i<array.length; i++) {
294                 try {
295                     destroyedCount++;
296                     try {
297                         factory.destroy(array[i]);
298                     } catch (Throwable JavaDoc th) {
299                         _logger.log(Level.FINE, "Exception in destroy()", th);
300                     }
301                 } catch (Throwable JavaDoc th) {
302                     _logger.log(Level.WARNING,
303                         "[AbstractPool]: Error while destroying: " + th);
304                 }
305             }
306             _logger.log(Level.FINE,"[AbstractPool]: Pool closed....");
307             list = new ArrayList JavaDoc();
308
309             Utility.setContextClassLoader(origLoader);
310         }
311         
312
313         // helps garbage collection
314
this.list = null;
315         this.factory = null;
316         this.poolTimerTask = null;
317         this.containerClassLoader = null;
318         
319     }
320
321     protected void remove(int count) {
322         ArrayList JavaDoc removeList = new ArrayList JavaDoc();
323         synchronized (list) {
324             int size = list.size();
325             for (int i=0; (i<count) && (size > 0); i++) {
326                 removeList.add(list.remove(--size));
327                 destroyedCount++;
328             }
329             
330             list.notifyAll();
331         }
332         
333         for (int i=removeList.size()-1; i >= 0; i--) {
334             factory.destroy(removeList.remove(i));
335             try {
336                 factory.destroy(removeList.remove(i));
337             } catch (Throwable JavaDoc th) {
338                 _logger.log(Level.FINE, "Exception in destroy()", th);
339             }
340         }
341     }
342
343     protected abstract void removeIdleObjects();
344     
345     private class AbstractPoolTimerTask
346         extends java.util.TimerTask JavaDoc
347     {
348         Object JavaDoc lock;
349         
350         AbstractPoolTimerTask() {}
351         
352         AbstractPoolTimerTask(Object JavaDoc lock) {
353             this.lock = lock;
354         }
355         
356         public void run() {
357             //We need to set the context class loader for this (deamon)thread!!
358
final Thread JavaDoc currentThread = Thread.currentThread();
359             final ClassLoader JavaDoc previousClassLoader =
360                 currentThread.getContextClassLoader();
361             final ClassLoader JavaDoc ctxClassLoader = containerClassLoader;
362             
363             try {
364                 
365                 java.security.AccessController.doPrivileged(
366                     new java.security.PrivilegedAction JavaDoc() {
367                     public java.lang.Object JavaDoc run() {
368                         currentThread.setContextClassLoader(ctxClassLoader);
369                         return null;
370                     }
371                 });
372                 
373                 try {
374                     if (list.size() > steadyPoolSize) {
375                         _logger.log(Level.FINE,"[AbstractPool]: Removing idle "
376                             + " objects from pool. Current Size: "
377                             + list.size() + "/" + steadyPoolSize
378                             + ". Time: " + (new java.util.Date JavaDoc()));
379                         removeIdleObjects();
380                     }
381                 } catch (Throwable JavaDoc th) {
382                     //removeIdleObjects would have logged the error
383
}
384
385                 java.security.AccessController.doPrivileged(
386                     new java.security.PrivilegedAction JavaDoc() {
387                     public java.lang.Object JavaDoc run() {
388                       currentThread.setContextClassLoader(previousClassLoader);
389                       return null;
390                     }
391                 });
392             } catch (Throwable JavaDoc th) {
393                 _logger.log(Level.FINE, "Exception in run()", th);
394             }
395         }
396     }
397
398     /**************** For Monitoring ***********************/
399     /*******************************************************/
400     
401     public int getCreatedCount() {
402         return createdCount;
403     }
404     
405     public int getDestroyedCount() {
406         return destroyedCount;
407     }
408     
409     public int getPoolSuccess() {
410         return poolSuccess;
411     }
412     
413     public int getSize() {
414         return list.size();
415     }
416     
417     public int getWaitCount() {
418         return waitCount;
419     }
420     
421     public int getSteadyPoolSize() {
422         return steadyPoolSize;
423     }
424     
425     public int getResizeQuantity() {
426         return resizeQuantity;
427     }
428     
429     public int getMaxPoolSize() {
430         return maxPoolSize;
431     }
432     
433     public long getMaxWaitTimeInMillis() {
434         return maxWaitTimeInMillis;
435     }
436     
437     public int getIdleTimeoutInSeconds() {
438         return idleTimeoutInSeconds;
439     }
440
441     public void setConfigData(String JavaDoc configData) {
442     this.configData = configData;
443     }
444
445
446     //Methods on EJBPoolStatsProvider
447
public void appendStats(StringBuffer JavaDoc sbuf) {
448     sbuf.append("[Pool: ")
449         .append("SZ=").append(list.size()).append("; ")
450         .append("CC=").append(createdCount).append("; ")
451         .append("DC=").append(destroyedCount).append("; ")
452         .append("WC=").append(waitCount).append("; ")
453         .append("MSG=0");
454     if (configData != null) {
455         sbuf.append(configData);
456     }
457     sbuf.append("]");
458     }
459
460     public int getJmsMaxMessagesLoad() {
461     return 0;
462     }
463
464     public int getNumBeansInPool() {
465     return list.size();
466     }
467
468     public int getNumThreadsWaiting() {
469     return waitCount;
470     }
471
472     public int getTotalBeansCreated() {
473     return createdCount;
474     }
475
476     public int getTotalBeansDestroyed() {
477     return destroyedCount;
478     }
479
480     public String JavaDoc getAllMonitoredAttrbuteValues() {
481         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
482         synchronized (list) {
483             sbuf.append("createdCount=").append(createdCount).append(";")
484                 .append("destroyedCount=").append(destroyedCount).append(";")
485                 .append("waitCount=").append(waitCount).append(";")
486                 .append("size=").append(list.size()).append(";");
487         }
488         sbuf.append("maxPoolSize=").append(maxPoolSize).append(";");
489         return sbuf.toString();
490     }
491     
492     public String JavaDoc getAllAttrValues() {
493         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
494         if(null != poolName)
495             sbuf.append(":").append(poolName);
496         else
497             sbuf.append(":POOL");
498
499         sbuf.append("[FP=").append(poolSuccess).append(",")
500             .append("TC=").append(createdCount).append(",")
501             .append("TD=").append(destroyedCount).append(",")
502             .append("PR=").append(poolReturned).append(",")
503             .append("TW=").append(waitCount).append(",")
504             .append("CS=").append(list.size()).append(",")
505             .append("MS=").append(maxPoolSize);
506     
507         return sbuf.toString();
508     }
509 }
510
Popular Tags