001: /*
002: * XAPool: Open Source XA JDBC Pool
003: * Copyright (C) 2003 Objectweb.org
004: * Initial Developer: Lutris Technologies Inc.
005: * Contact: xapool-public@lists.debian-sf.objectweb.org
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
020: * USA
021: */
022: package org.enhydra.jdbc.pool;
023:
024: import java.util.Hashtable;
025: import java.util.Enumeration;
026: import java.util.Vector;
027:
028: import org.enhydra.jdbc.core.JdbcThreadFactory;
029: import org.enhydra.jdbc.util.Logger;
030:
031: /**
032: * GenericPool is the main class of the Pool. It works with any kind of object
033: * that's implement PoolHelper (must provide specific operation on the specific
034: * object) Objects stored in hashtables are GenerationObject object. These
035: * objects allow to store multiples things in them, in particular, the
036: * generation number to identify the generation of an object.
037: */
038: public class GenericPool {
039: private long lifeTime; // lifetime of an object in the pool
040:
041: private Hashtable locked, unlocked;
042:
043: // two hashtables, to stock objects in use and free objects
044: private Vector hitList; // holds expired objects until they are killed.
045:
046: private JdbcThreadFactory threadFactory; // thread factory
047:
048: private int minSize; // minimum size of the pool, set to 0
049:
050: private int maxSize; // maximum size of the pool, if set to 0 : unlimited
051:
052: private PoolHelper poolHelper; // object type
053:
054: private int count; // count the number of object in the pool
055:
056: private boolean gc; // gc system call
057:
058: private boolean debug; // debug flag
059:
060: private long deadLockMaxWait;
061:
062: // time to wait before deadlock (return exception)
063: private long deadLockRetryWait; // time to wait before 2 try of loop
064:
065: private Logger log;
066:
067: /**
068: * checking level object 0 = no special checking 1 = just a check on an
069: * object 2 = test the object 3 = just a check on an object (for all the
070: * objects) 4 = test the object (for all the objects)
071: */
072: private int checkLevelObject = 1;
073:
074: protected Thread keeper; // thread to clean up dead objects
075:
076: protected PoolKeeper poolKeeper;
077:
078: private long sleepTime; // sleeptime for the pool keeper
079:
080: /**
081: * Generation number. When an error occurs, all objects of the same
082: * generation or earlier are dropped.
083: */
084: protected int generation = 1;
085:
086: // Total lifetime the object can exist
087: private long maxLifeTime;
088:
089: // Default Total time the object can be exist.
090: // Default = 0 : can live forever.
091: public static final long DEFAULT_MAXLIFETIME = 0;
092:
093: // Default values
094: public static final long DEFAULT_EXPIRATION = 600000; // 10 minutes
095:
096: // public static final long DEFAULT_EXPIRATION = 30000; // 30 secondes
097: public static final long DEFAULT_SLEEPTIME = 300000; // 5 minutes
098:
099: public static final int DEFAULT_MINSIZE = 2; // 2 objects
100:
101: public static final int DEFAULT_MAXSIZE = 50; // 50 objects
102:
103: public static final int DEFAULT_DEADLOCKMAXWAIT = 300000; // 5 minutes
104:
105: public static final int DEFAULT_DEADLOCKRETRYWAIT = 10000; // 10 seconds
106:
107: /**
108: * Creates an GenericPool with the default params.
109: */
110: public GenericPool(PoolHelper helper) {
111: this (helper, DEFAULT_MINSIZE, DEFAULT_MAXSIZE,
112: DEFAULT_EXPIRATION, DEFAULT_SLEEPTIME,
113: DEFAULT_MAXLIFETIME);
114: }
115:
116: public GenericPool(PoolHelper helper, int initSize) {
117: this (helper, DEFAULT_MINSIZE, initSize, DEFAULT_EXPIRATION,
118: DEFAULT_SLEEPTIME, DEFAULT_MAXLIFETIME);
119: }
120:
121: /**
122: * Constructor, set the two hashtables and set by default the other values
123: */
124: public GenericPool(PoolHelper helper, int minSize, int maxSize,
125: long lifeTime, long sleepTime, long maxLifeTime) {
126: this .threadFactory = null;
127: this .lifeTime = lifeTime;
128: this .maxLifeTime = maxLifeTime;
129: this .minSize = minSize;
130: this .maxSize = maxSize;
131: this .poolHelper = helper;
132: // helper is the type of the object (interface)
133: this .sleepTime = sleepTime;
134: this .checkLevelObject = 0;
135: this .deadLockMaxWait = DEFAULT_DEADLOCKMAXWAIT;
136: this .deadLockRetryWait = DEFAULT_DEADLOCKRETRYWAIT;
137: }
138:
139: /**
140: * Start method, to initialize independant values of the pool
141: */
142: public synchronized void start() {
143: locked = new Hashtable(); // create locked objects pool
144: unlocked = new Hashtable(); // create unlocked objects pool
145: hitList = new Vector();
146: count = 0; // 0 element to start
147: gc = false; // do not actions concerning garbage collector
148: long now = System.currentTimeMillis(); // current time
149:
150: // to obtain to the beginning minSize objects in the pool
151: for (int i = 0; i < minSize; i++) { // count have to be equal to minSize
152: try {
153: GenerationObject genObject = poolHelper.create();
154: unlocked.put(genObject, new Long(now));
155: // put it in the unlocked pool
156: } catch (Exception e) {
157: log.error("Error Exception in GenericPool:start " + e);
158: }
159: ++count; // there is one more element in the pool
160: }
161:
162: // keeper removes dead or useless objects
163: if (threadFactory != null) {
164: try {
165: this .poolKeeper = new PoolKeeper(sleepTime, this );
166: this .keeper = threadFactory.getThread(poolKeeper);
167: } catch (Exception e) {
168: throw new IllegalStateException(e.getMessage());
169: }
170: } else {
171: // keep a handle to the poolkeeper so we can destroy it later
172: this .poolKeeper = new PoolKeeper(sleepTime, this );
173: this .keeper = new Thread(poolKeeper);
174:
175: }
176: keeper.start();
177: // start the thread to verify element in the pool(unlocked)
178: log.debug("GenericPool:start pool started");
179: }
180:
181: /*
182: * Returns object from the pool or creates a connection outside
183: * synchronization to prevent hanging.
184: */
185: private Object getFromPool(String user, String password)
186: throws Exception {
187:
188: long now = System.currentTimeMillis(); // current time to compare
189: if (getUnlockedObjectCount() > 0) {
190: // now, we have to return an object to the user
191: GenerationObject o = null;
192: Object realObject = null;
193: Long life = null;
194:
195: Enumeration e = unlocked.keys(); // then take them
196: while (e.hasMoreElements()) { // for each objects ...
197: synchronized (this ) {
198:
199: // Ensure that there are object in the unlocked
200: // collection
201: if (getUnlockedObjectCount() == 0)
202: break;
203:
204: o = (GenerationObject) e.nextElement();
205: life = (Long) unlocked.get(o);
206: if (life == null) {
207: // Fix for #303462; note that this fixes the problem, but Enumeration's on Hashtable's
208: // are by definition somewhat unpredictable; a more robust fix may be in order
209: log
210: .debug("GenericPool:getFromPool fix for #303462 encountered");
211: continue;
212: }
213:
214: unlocked.remove(o);
215: // In any case the object will be removed.
216: // Prevents others accessing the object while we are
217: // not synchronized.
218: realObject = o.getObj();
219: }
220:
221: // Verify that the life object is valid
222: if (life == null)
223: break;
224:
225: // first, verify if the object is not dead (lifetime)
226: if (life == null
227: || (now - life.longValue()) > lifeTime
228: || (maxLifeTime > 0 && (now - o.getCreated()) > maxLifeTime)) {
229:
230: // object has expired
231: log
232: .debug("GenericPool:getFromPool an object has expired");
233: removeUnlockedObject(o);
234: } else {
235: log
236: .debug("GenericPool:getFromPool check the owner of the connection");
237: if (checkOwner(o, user, password)) {
238: log
239: .debug("GenericPool:getFromPool owner is verified");
240: // second, verification of the object if needed
241: if ((checkLevelObject == 0)
242: || ((checkLevelObject == 1) && poolHelper
243: .checkThisObject(realObject))
244: || ((checkLevelObject == 2) && poolHelper
245: .testThisObject(realObject))) {
246:
247: locked.put(o, new Long(now));
248: // put it in the locked pool
249: log
250: .debug("GenericPool:getFromPool return an object (after verification if needed)");
251: return (o.getObj()); // return this element
252: } else { // object failed validation
253: // System.out.println("removeUnlockedObject="+realObject);
254: log
255: .debug("GenericPool:getFromPool kill an object from the pool");
256: removeUnlockedObject(o);
257: }
258:
259: } else
260: log
261: .debug("GenericPool:getFromPool owner is FALSE");
262: }
263: }
264: } // if getUnlockedObjectCount() > 0
265:
266: // if no objects available, create a new one
267: boolean create = false;
268: synchronized (this ) {
269: if (count < maxSize) {
270: create = true;
271: count++; // assume we can create a connection.
272: }
273: }
274: if (create) {
275: // System.out.println("on doit creer une connection");
276: // if number of pooled object is < max size of the pool
277: log
278: .debug("GenericPool:getFromPool no objects available, create a new one");
279: try {
280: // System.out.println("on doit creer une connection CREATE");
281: GenerationObject genObject = poolHelper.create(user,
282: password);
283: // System.out.println("nouvel objet="+genObject.getObj());
284: // System.out.println("on doit creer une connection PUT");
285: locked.put(genObject, new Long(now));
286: // put it in the locked pool
287: return (genObject.getObj()); // and return this element
288: } catch (Exception excp) {
289: synchronized (this ) {
290: count--; // our assumption failed. rollback.
291: }
292:
293: log
294: .error("GenericPool:getFromPool Error Exception in GenericPool:getFromPool");
295: // cney: rethrow exception thrown by create
296: throw excp;
297: }
298: }
299:
300: return null;
301: }
302:
303: public synchronized boolean checkOwner(GenerationObject genObject,
304: String user, String password) {
305: return equals(user, genObject.getUser())
306: && equals(password, genObject.getPassword());
307: }
308:
309: JdbcThreadFactory getThreadFactory() {
310: return threadFactory;
311: }
312:
313: void setThreadFactory(JdbcThreadFactory tf) {
314: threadFactory = tf;
315: }
316:
317: private boolean equals(String a, String b) {
318: if (a == null)
319: return (b == null);
320: if (b == null)
321: return (a == null);
322: return a.equals(b);
323: }
324:
325: /**
326: * return pooled object
327: */
328: public Object checkOut(String user, String password)
329: throws Exception {
330: log.debug("GenericPool:checkOut an object");
331: long now = System.currentTimeMillis(); // current time to compare
332: GenerationObject o;
333: Enumeration e;
334: Object realObject;
335: log.debug("GenericPool:checkOut UnlockedObjectCount="
336: + getUnlockedObjectCount());
337: log.debug("GenericPool:checkOut LockedObjectCount="
338: + getLockedObjectCount());
339: log.debug("GenericPool:checkOut count=" + count + " maxSize="
340: + maxSize);
341:
342: if (getUnlockedObjectCount() > 0) {
343: // if there are objects in the unlocked pool
344: if ((checkLevelObject == 3) || (checkLevelObject == 4)) { // need
345: // to
346: // verify
347: // all
348: // the
349: // objects
350:
351: e = unlocked.keys();
352: while (e.hasMoreElements()) {
353: o = (GenerationObject) e.nextElement();
354: realObject = o.getObj(); // take the current object
355: // first, verify if the object is not dead (lifetime)
356: Long life = (Long) unlocked.get(o);
357: if (life == null
358: || (now - life.longValue()) > lifeTime
359: || (maxLifeTime > 0 && (now - o
360: .getCreated()) > maxLifeTime)) {
361:
362: // object has expired
363: log
364: .debug("GenericPool:checkOut an object has expired");
365: removeUnlockedObject(o);
366: // minimumObject(user, password);
367: // build object in the pool if it is lesser than minSize
368: } else {
369: log
370: .debug("GenericPool:checkOut check the owner of the connection");
371: if (checkOwner(o, user, password)) {
372: if (((checkLevelObject == 3) && !poolHelper
373: .checkThisObject(realObject))
374: || ((checkLevelObject == 4) && !poolHelper
375: .testThisObject(realObject))) {
376: log
377: .debug("GenericPool:checkOut remove object checkLevelObject="
378: + checkLevelObject);
379: removeUnlockedObject(o);
380: // minimumObject(user, password);
381: // build object in the pool if it is lesser than
382: // minSize
383: }
384: }
385: }
386: }
387: }
388:
389: }
390:
391: int currentWait = 0;
392:
393: Object obj = getFromPool(user, password);
394: while ((obj == null) && (currentWait < getDeadLockMaxWait())) {
395: log.info("GenericPool:checkOut waiting for an object :"
396: + this .poolHelper.toString());
397: try {
398: synchronized (this ) {
399: wait(getDeadLockRetryWait());
400: }
401: } catch (InterruptedException excp) {
402: log
403: .error("GenericPool:checkOut ERROR Failed while waiting for an object: "
404: + excp);
405: }
406: currentWait += getDeadLockRetryWait();
407: obj = getFromPool(user, password);
408: }
409:
410: if (obj == null)
411: throw new Exception(
412: "GenericPool:checkOut ERROR impossible to obtain a new object from the pool");
413:
414: return obj;
415: }
416:
417: synchronized public void minimumObject() {
418: minimumObject(null, null);
419: }
420:
421: synchronized public void minimumObject(String user, String password) {
422: log
423: .debug("GenericPool:minimumObject create object if there are less than minSize objects in the pool count ="
424: + count);
425: if ((count < minSize) && (unlocked != null)) { // if pool has less than
426: // minSize elements
427: long now = System.currentTimeMillis(); // current time
428:
429: for (int i = count; i < minSize; i++) { // count have to be equal to
430: // minSize
431: try {
432: GenerationObject genObject;
433: if ((user != null) && (password != null))
434: genObject = poolHelper.create();
435: else
436: genObject = poolHelper.create(user, password);
437: unlocked.put(genObject, new Long(now));
438: // put it in the unlocked pool
439: } catch (Exception e) {
440: log
441: .error("GenericPool:minimumObject Error Exception in GenericPool:minimumObject");
442: }
443: }
444: log.debug("GenericPool:minimumObject count=" + count
445: + " Unlocked=" + this .getUnlockedObjectCount()
446: + " locked=" + this .getLockedObjectCount());
447:
448: count = minSize; // pool has now minSize element
449: }
450: }
451:
452: /**
453: * remove object from locked pool
454: */
455: public synchronized void checkIn(Object o) {
456: log.debug("GenericPool:checkIn return an object to the pool");
457:
458: for (Enumeration enumeration = locked.keys(); enumeration
459: .hasMoreElements();) { // for
460: // each
461: // object
462: // of
463: GenerationObject obj = (GenerationObject) enumeration
464: .nextElement();
465: // the locked pool
466:
467: if (obj.getObj().equals(o)) {
468: locked.remove(obj); // remove the object from the locked pool
469: unlocked.put(obj, new Long(System.currentTimeMillis()));
470:
471: // we have to verify if the generation of the object is still
472: // valid
473: int genObj = obj.getGeneration(); // get the generation number
474:
475: // if the generation number of the object is not valid, test the
476: // object
477: if (generation > genObj) {
478: if (!poolHelper.checkThisObject(obj.getObj()))
479: // if the object is not valid
480: removeUnlockedObject(obj);
481:
482: }
483: notifyAll();
484: }
485: }
486:
487: if (count > maxSize) {
488: // if we have more than maxSize object in the pool
489: log
490: .info("GenericPool:checkIn more than maxSize object in the pool");
491: Enumeration enumeration = unlocked.keys(); // get the unlocked pool
492: for (int i = maxSize; i < count; i++) { // try to remove object from
493: // this pool
494: if (getUnlockedObjectCount() > 0) {
495: GenerationObject obj = (GenerationObject) enumeration
496: .nextElement();
497: removeUnlockedObject(obj);
498: }
499: }
500: // now, the size of the pool is changed
501: // NOTE : count number ca be greater than maxSize here, in case of
502: // there is no
503: // available object to delete in the unlocked pool
504: count = getUnlockedObjectCount() + getLockedObjectCount();
505: if (count > maxSize)
506: log
507: .warn("GenericPool:checkIn Be careful, the maximum size of the pool does not correspond"
508: + " to your data. When objects will be check in, the pool "
509: + "will decrease");
510: }
511:
512: }
513:
514: synchronized public void removeUnlockedObject(GenerationObject obj) {
515: --count;
516: notifyAll(); // there is room for new connections.
517: unlocked.remove(obj);
518: hitList.add(obj); // killing is done by the keeper thread.
519: }
520:
521: public void setDebug(boolean debug) {
522: this .debug = debug;
523: }
524:
525: public boolean isDebug() {
526: return debug;
527: }
528:
529: public synchronized void setMinSize(int min) throws Exception {
530: if (min < 0)
531: throw new Exception(
532: "GenericPool:setMinSize Minimum size of the pool can't be lesser than 0");
533: else if (min > maxSize)
534: throw new Exception(
535: "GenericPool:setMinSize Minimum size of the pool can't be greater than the maxSize ("
536: + maxSize + ")");
537: else {
538: this .minSize = min;
539: // minimumObject(); // build object in the pool if it is lesser than
540: // minSize
541: }
542:
543: }
544:
545: public synchronized void setMaxSize(int max) throws Exception {
546: if (max < 0)
547: throw new Exception(
548: "GenericPool:setMaxSize Maximum size of the pool can't be lesser than 0");
549: else if (max < minSize)
550: throw new Exception(
551: "GenericPool:setMaxSize Maximum size of the pool can't be lesser than the minSize ("
552: + minSize + ")");
553: else {
554: this .maxSize = max;
555: if (count > max) { // if pool has more than max element
556: log
557: .info("GenericPool:setMaxSize pool has more than max element");
558: // we try to remove element from the unlocked pool
559: Enumeration enumeration = unlocked.keys();
560: for (int i = max; i < count; i++) {
561: if (getUnlockedObjectCount() > 0) {
562: // if there is element in the unlocked pool
563: GenerationObject o = (GenerationObject) enumeration
564: .nextElement();
565: removeUnlockedObject(o);
566: }
567: }
568:
569: // new size is :
570: count = getUnlockedObjectCount()
571: + getLockedObjectCount();
572: // if there is still more than max element, the objects will be
573: // removed
574: // when the check in operation will be performed.
575: if (count > max)
576: log
577: .warn("GenericPool:setMaxSize Be careful, the maximum size of "
578: + "the pool does not correspond to your data. When objects "
579: + "will be check in, the pool will decrease");
580: }
581: }
582: }
583:
584: public void setLifeTime(long lifeTime) {
585: this .lifeTime = lifeTime;
586: }
587:
588: public void setSleepTime(long sleepTime) {
589: this .sleepTime = sleepTime;
590: }
591:
592: public void setGeneration(int generation) {
593: this .generation = generation;
594: log
595: .debug("GenericPool:setGeneration Be careful, it is very dangerous to change "
596: + "the generation number, many objects could be destroyed");
597: }
598:
599: public void setGC(boolean gc) {
600: this .gc = gc;
601: }
602:
603: /**
604: * level are accepted between 0 and 4
605: */
606: public void setCheckLevelObject(int level) {
607: if ((level > 0) && (level <= 4))
608: this .checkLevelObject = level;
609: }
610:
611: public void setDeadLockMaxWait(long deadLock) {
612: this .deadLockMaxWait = deadLock;
613: }
614:
615: public void setDeadLockRetryWait(long deadLockRetryWait) {
616: this .deadLockRetryWait = deadLockRetryWait;
617: }
618:
619: public int getMinSize() {
620: return minSize;
621: }
622:
623: public int getMaxSize() {
624: return maxSize;
625: }
626:
627: public long getLifeTime() {
628: return lifeTime;
629: }
630:
631: public boolean isGC() {
632: return gc;
633: }
634:
635: public int getCount() {
636: return count;
637: }
638:
639: public long getSleepTime() {
640: return sleepTime;
641: }
642:
643: public int getGeneration() {
644: return generation;
645: }
646:
647: public int getCheckLevelObject() {
648: return checkLevelObject;
649: }
650:
651: /**
652: * switch off the pool
653: */
654: public void stop() {
655: log.debug("GenericPool:stop start to stop the pool");
656: if ((getLockedObjectCount() != 0)
657: || (getUnlockedObjectCount() != 0)) {
658: expireAll(); // try to kill all the objects in the 2 pools
659: if (poolKeeper != null)
660: poolKeeper.stop(); // release the pool.
661: keeper.interrupt(); // and interrupt the pool keeper
662: locked.clear(); // clear the locked pool
663: unlocked.clear(); // clear the unlocked pool
664: locked = null;
665: unlocked = null;
666: count = 0; // there is no element in the pool
667: }
668: log.debug("GenericPool:stop pool stopped");
669: }
670:
671: /**
672: * returns the current number of objects that are locked
673: */
674: public int getLockedObjectCount() {
675: if (locked != null)
676: return locked.size();
677: else
678: return 0;
679: }
680:
681: /**
682: * returns the current number of objects that are unlocked
683: */
684: public int getUnlockedObjectCount() {
685: if (unlocked != null)
686: return unlocked.size();
687: else
688: return 0;
689: }
690:
691: public long getDeadLockMaxWait() {
692: return this .deadLockMaxWait;
693: }
694:
695: public long getDeadLockRetryWait() {
696: return this .deadLockRetryWait;
697: }
698:
699: /**
700: * returns information from the pool
701: */
702: public String toString() {
703: StringBuffer sb = new StringBuffer();
704: sb.append("GenericPool:\n");
705: sb.append(" num of element =<" + count + ">\n");
706: sb.append(" minSize =<" + minSize + ">\n");
707: sb.append(" maxSize =<" + maxSize + ">\n");
708: sb.append(" lifeTime =<" + lifeTime + ">\n");
709: sb.append(" ngeneration =<" + generation + ">\n");
710: sb.append(" maxLifeTime =<" + maxLifeTime + ">\n");
711: sb.append(" getLockedObjectCount() =<"
712: + getLockedObjectCount() + ">\n");
713: sb.append(" getUnlockedObjectCount() =<"
714: + getUnlockedObjectCount() + ">\n");
715: sb.append(" getDeadLockMaxWait() =<" + getDeadLockMaxWait()
716: + ">\n");
717: sb.append(" getDeadLockRetryWait() =<"
718: + getDeadLockRetryWait() + ">\n");
719:
720: if (unlocked != null) {
721: sb.append("Unlocked pool:\n");
722: Enumeration e = unlocked.keys();
723: while (e.hasMoreElements()) {
724: GenerationObject o = (GenerationObject) e.nextElement();
725: sb.append(o.getObj().toString());
726: }
727: }
728:
729: if (locked != null) {
730: sb.append("Locked pool:\n");
731: Enumeration e = unlocked.keys();
732: while (e.hasMoreElements()) {
733: GenerationObject o = (GenerationObject) e.nextElement();
734: sb.append(o.getObj().toString());
735: }
736: }
737: return sb.toString();
738: }
739:
740: /**
741: * Remove unusable objects from the pool, called by PoolKeeper Check the
742: * unlocked objects for expired members.
743: */
744: protected void cleanUp() {
745: // During shutdown, unlocked may be null.
746: synchronized (this ) {
747: if (unlocked == null)
748: return;
749: }
750: long now = System.currentTimeMillis(); // current time
751: synchronized (this ) {
752: for (Enumeration enumeration = unlocked.keys(); enumeration
753: .hasMoreElements();) { // for
754: // each
755: // object
756: // of
757: // the
758: GenerationObject o = (GenerationObject) enumeration
759: .nextElement();
760: // unlocked pool
761:
762: Long lasttouch = (Long) unlocked.get(o);
763: // birth day of the pool
764: if (lasttouch == null
765: || (now - lasttouch.longValue()) > lifeTime
766: || (maxLifeTime > 0 && (now - o.getCreated()) > maxLifeTime)) {
767: log.debug("GenericPool:cleanUp clean up the pool");
768: removeUnlockedObject(o);
769: }
770: }
771: }
772:
773: // Kill every object in the hit list. We do this outside synchronization
774: // in case it takes too long. Note that hitList only grows so this is
775: // a safe way to do this.
776: while (hitList.size() > 0) { // kill each object.
777: // this might take a while, lets do it outside synchronization.
778: GenerationObject obj = (GenerationObject) hitList.remove(0);
779: log.debug("GenericPool:cleanUp killing an object");
780: poolHelper.expire(obj.getObj()); // try to "kill" it
781: obj.killObject();
782: }
783:
784: if (isGC()) // if the pool is GCeable
785: System.gc(); // launch system call to clean up unused objects
786:
787: boolean resize = false;
788: // Lets keep the look outside synchronization as object creation
789: // may take a while.
790: synchronized (this ) {
791: resize = count < minSize;
792: }
793:
794: if (resize) {
795: // if there is less than minSize objects in the pool
796: log
797: .info("GenericPool:cleanUp less than minSize objects in the pool "
798: + "min="
799: + minSize
800: + " max="
801: + maxSize
802: + " count=" + count);
803: while (true) {
804: try {
805: GenerationObject genObject = poolHelper.create();
806: synchronized (this ) {
807: unlocked.put(genObject, new Long(now));
808: // put it in the unlocked pool
809: ++count; // there is one more element in the pool
810: notifyAll();
811:
812: if (count >= minSize)
813: break;
814: // we want to make the test inside sync but leave the
815: // loop
816: // outside sync.
817: }
818:
819: } catch (Exception e) {
820: log
821: .error("GenericPool:cleanUp Could not create new connections to fill pool size to minSize.");
822: break; // ADDED THE BREAK SO WE DON't GET AN ENDLESS LOOP WHEN THE DATABASE IS DOWN.
823: }
824: synchronized (this ) {
825: notifyAll();
826: }
827: }
828: log.info("GenericPool:cleanUp done " + "min=" + minSize
829: + " max=" + maxSize + " count=" + count);
830:
831: }
832: }
833:
834: /**
835: * close all object in the unlocked and locked structures
836: */
837: void expireAll() {
838: log
839: .debug("GenericPool:expireAll close all object in the unlocked and locked structures");
840: for (Enumeration enumeration = unlocked.keys(); enumeration
841: .hasMoreElements();) { // for
842: // each
843: // object
844: // of
845: GenerationObject o = (GenerationObject) enumeration
846: .nextElement();
847: // the unlocked pool
848: poolHelper.expire(o.getObj()); // try to "kill" the object
849: o.killObject();
850: o = null;
851: }
852: for (Enumeration enumeration = locked.keys(); enumeration
853: .hasMoreElements();) { // for
854: // each
855: // object
856: // of
857: GenerationObject o = (GenerationObject) enumeration
858: .nextElement();
859: // the locked pool
860: poolHelper.expire(o.getObj()); // try to "kill" the object
861: o.killObject();
862: o = null;
863: }
864: }
865:
866: /**
867: * Allows to verify if objects from the pool - for the o generation - are
868: * valid or not. (only for the unlocked pool, to avoid to allocate non-valid
869: * object
870: */
871: public void nextGeneration(Object obj) {
872: log.debug("GenericPool:nextGeneration");
873: int genObj = 0;
874: for (Enumeration enumeration = locked.keys(); enumeration
875: .hasMoreElements();) { // for
876: // each
877: // object
878: // of
879: GenerationObject o = (GenerationObject) enumeration
880: .nextElement();
881: // the locked pool
882:
883: if (o.getObj().equals(obj))
884: genObj = o.getGeneration(); // get the generation number
885: }
886:
887: for (Enumeration enumeration = unlocked.keys(); enumeration
888: .hasMoreElements();) { // for
889: // each
890: // object
891: // of
892: GenerationObject o = (GenerationObject) enumeration
893: .nextElement();
894: // the unlocked pool
895:
896: if (o.getGeneration() <= genObj) {
897: // all objects of the same generation
898: // or earlier are dropped
899: if (!poolHelper.checkThisObject(o.getObj()))
900: // if the object is not valid
901: removeUnlockedObject(o);
902:
903: }
904: }
905: ++this .generation; // now, we work with the next generation of object
906:
907: }
908:
909: /**
910: * removes an object for the locked pool, when an error has occurred
911: */
912: synchronized public void removeLockedObject(Object obj) {
913: log.debug("GenericPool:removeObject remove an object");
914: for (Enumeration enumeration = locked.keys(); enumeration
915: .hasMoreElements();) { // for
916: // each
917: // object
918: // of
919: GenerationObject o = (GenerationObject) enumeration
920: .nextElement();
921: // the locked pool
922: System.out.println("GenericPool:removeObject "
923: + o.toString() + " - " + obj.toString());
924:
925: if (o.getObj().equals(obj)) {
926: System.out
927: .println("GenericPool:removeObject remove found");
928: locked.remove(o); // remove the object from the locked pool
929: --count;
930: o.killObject();
931: o = null;
932: }
933: }
934: }
935:
936: /**
937: * removes an object for the locked pool, when an error has occurred
938: */
939: synchronized public void fullRemoveLockedObject(Object obj) {
940: log.debug("GenericPool:removeObject remove an object");
941: for (Enumeration enumeration = locked.keys(); enumeration
942: .hasMoreElements();) { // for
943: // each
944: // object
945: // of
946: GenerationObject o = (GenerationObject) enumeration
947: .nextElement();
948: // the locked pool
949: System.out.println("GenericPool:removeObject "
950: + o.toString() + " - " + obj.toString());
951:
952: if (o.equals(obj)) {
953:
954: System.out
955: .println("GenericPool:removeObject remove found");
956: poolHelper.expire(o.getObj()); // try to "kill" it
957:
958: locked.remove(o); // remove the object from the locked pool
959: --count;
960: o.killObject();
961: o = null;
962: }
963: }
964: }
965:
966: /**
967: * Outputs a log message to the log writer.
968: */
969: public void setLogger(Logger alog) {
970: log = alog;
971: }
972:
973: public Hashtable getLockedObject() {
974: return locked;
975:
976: }
977:
978: public Hashtable getUnlockedPool() {
979: return unlocked;
980: }
981:
982: public Hashtable getLockedPool() {
983: return locked;
984: }
985:
986: public void setMaxLifeTime(long maxlifeTime) {
987: this .maxLifeTime = maxlifeTime;
988: }
989:
990: public long getMaxLifeTime() {
991: return maxLifeTime;
992: }
993: }
|