Source Code Cross Referenced for ObjectPool.java in  » Database-JDBC-Connection-Pool » DBPool » snaq » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database JDBC Connection Pool » DBPool » snaq.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:        	DBPool - JDBC Connection Pool Manager
003:        	Copyright (c) Giles Winstanley
004:         */
005:        package snaq.util;
006:
007:        import java.io.*;
008:        import java.text.*;
009:        import java.util.*;
010:
011:        /**
012:         * Base class for a pool system implementation.
013:         * This class provides all the base functionality required and can be easily
014:         * extended to provide pooling support for many different types of object.
015:         * <p>New objects are retrieved on demand according to specified limits,
016:         * and the pool can also ensure an object's validity before returning it.
017:         * The limits which can be set for a pool include the number of items to be
018:         * held in the pool, and the maximum number to ever be created.
019:         * <p>The pool will try to maintain <tt>poolSize</tt> items open and ready
020:         * for use (unless that number has not yet been created), but if expiry is
021:         * enabled this number will reduce if the items are not used frequently.
022:         * If <tt>maxSize</tt> is specified then the pool will never create more
023:         * than this number of items, and another can only be obtained from the pool
024:         * if it is handed back by another client.
025:         * <p><tt>ObjectPool</tt> should be sub-classed to override
026:         * the following methods:</p>
027:         * <pre>
028:         *   protected Reusable create() throws Exception
029:         *   protected boolean isValid(final Reusable o)
030:         *   protected void destroy(final Reusable o)
031:         * </pre>
032:         * <p>It is recommended that the sub-class implements methods for obtaining
033:         * and returning items within the pool, casting the objects returned by this
034:         * class as required to the appropriate class type.
035:         * <p>ObjectPool also support asynchronous destruction of items, which can be
036:         * useful in circumstances where destruction of items held can take a long
037:         * time which would delay the <tt>checkIn</tt> method. This also applies
038:         * to the release of the pool after it's final use, which should always be
039:         * done using either <tt>release</tt> or <tt>releaseAsync</tt>.
040:         * @author Giles Winstanley
041:         */
042:        public abstract class ObjectPool extends LogUtil {
043:            // Pool access method
044:            private static final int ACCESS_FIFO = 1;
045:            private static final int ACCESS_LIFO = 2;
046:            private static final int ACCESS_RANDOM = 3;
047:            private int accessMethod = ACCESS_LIFO;
048:            // Other variables
049:            private String name;
050:            private List free, used;
051:            private int poolSize, maxSize;
052:            private long expiryTime;
053:            private long requests, hits;
054:            private boolean released = false;
055:            private boolean asyncDestroy = false;
056:            private DateFormat dateFormat;
057:            private Cleaner cleaner;
058:            private InitThread initer;
059:            private static int cleanerCount = 0;
060:            private List listeners = new ArrayList();
061:
062:            /**
063:             * Creates new object pool.
064:             * @param name pool name
065:             * @param poolSize maximum number of pooled objects, or 0 for no limit
066:             * @param maxSize maximum number of possible objects, or 0 for no limit
067:             * @param expiryTime expiry time (milliseconds) for pooled object, or 0 for no expiry
068:             */
069:            protected ObjectPool(String name, int poolSize, int maxSize,
070:                    long expiryTime) {
071:                Class type = getPoolClass();
072:                if (!List.class.isAssignableFrom(type))
073:                    throw new RuntimeException(
074:                            "Invalid pool class type specified: "
075:                                    + type.getName()
076:                                    + " (must implement java.util.List)");
077:                try {
078:                    free = (List) type.newInstance();
079:                    used = (List) type.newInstance();
080:                } catch (Exception e) {
081:                    throw new RuntimeException(
082:                            "Unable to instantiate pool class type: "
083:                                    + type.getName());
084:                }
085:                this .name = name;
086:                this .setParameters(poolSize, maxSize, expiryTime);
087:            }
088:
089:            /**
090:             * Creates new object pool.
091:             * @param name pool name
092:             * @param poolSize maximum number of pooled objects, or 0 for no limit
093:             * @param maxSize maximum number of possible objects, or 0 for no limit
094:             * @param expiryTime expiry time (milliseconds) for pooled object, or 0 for no expiry
095:             */
096:            protected ObjectPool(String name, int poolSize, int maxSize,
097:                    int expiryTime) {
098:                this (name, poolSize, maxSize, (long) expiryTime);
099:            }
100:
101:            /**
102:             * Initializes the given number of items in the pool.
103:             * This spawns a new thread to create them in the background.
104:             */
105:            public final void init(int num) {
106:                if (num == 0)
107:                    return;
108:                if (num > 0 && num <= getMaxSize()) {
109:                    if (initer != null) {
110:                        initer.halt();
111:                        try {
112:                            initer.join();
113:                        } catch (InterruptedException ie) {
114:                        }
115:                    }
116:                    initer = new InitThread(num);
117:                    initer.start();
118:                } else
119:                    throw new IllegalArgumentException(
120:                            "Invalid number of items specified for initialization");
121:            }
122:
123:            /**
124:             * Checks out an item from the pool. If no free item
125:             * is available, a new item is created unless the maximum
126:             * number of items has been reached. If a free item
127:             * is not valid it is removed from the pool and another
128:             * is retrieved.
129:             * @return item from the pool, or null if nothing available
130:             * @exception Exception if there is an error creating a new object
131:             */
132:            protected final synchronized Reusable checkOut() throws Exception {
133:                if (released)
134:                    throw new RuntimeException("Pool no longer valid for use");
135:                int oldTotalConns = used.size() + free.size();
136:
137:                TimeWrapper tw = null;
138:                Reusable o = null;
139:                if (free.size() > 0) {
140:                    //  Get an object from the free list
141:                    switch (accessMethod) {
142:                    case ACCESS_FIFO:
143:                        tw = (TimeWrapper) free.remove(0);
144:                        break;
145:                    case ACCESS_RANDOM:
146:                        tw = (TimeWrapper) free
147:                                .remove((int) (free.size() * Math.random()));
148:                        break;
149:                    case ACCESS_LIFO:
150:                    default:
151:                        tw = (TimeWrapper) free.remove(free.size() - 1);
152:                    }
153:                    o = (Reusable) tw.getObject();
154:                    boolean valid = isValid(o);
155:                    while (!valid && free.size() > 0) {
156:                        destroyObject(o);
157:                        log("Removed invalid item from pool");
158:                        tw = (TimeWrapper) free.remove(0);
159:                        o = (Reusable) tw.getObject();
160:                        valid = isValid(o);
161:                    }
162:                    if (free.size() == 0 && !valid)
163:                        o = null;
164:                }
165:                boolean hit = (o != null);
166:
167:                // If no free items and can create more...create new item
168:                if (o == null) {
169:                    if (maxSize > 0 && used.size() == maxSize)
170:                        fireMaxSizeLimitErrorEvent();
171:                    else if (used.size() < maxSize || maxSize == 0) {
172:                        o = create();
173:                        if (!isValid(o))
174:                            throw new RuntimeException(
175:                                    "Unable to create a valid connection");
176:                    }
177:                }
178:
179:                // If a connection has been obtained/created, add it to used items collection
180:                if (o != null) {
181:                    used.add(o);
182:                    requests++;
183:                    if (hit)
184:                        hits++;
185:                    firePoolCheckOutEvent();
186:                    // Check for limit reaching so events can be fired.
187:                    // (Events only fired on increase of connection numbers).
188:                    int totalConns = used.size() + free.size();
189:                    if (totalConns == poolSize && totalConns > oldTotalConns)
190:                        fireMaxPoolLimitReachedEvent();
191:                    else if (totalConns == poolSize + 1
192:                            && totalConns > oldTotalConns)
193:                        fireMaxPoolLimitExceededEvent();
194:                    if (totalConns == maxSize && totalConns > oldTotalConns)
195:                        fireMaxSizeLimitReachedEvent();
196:                }
197:                if (debug) {
198:                    String ratio = used.size() + "/"
199:                            + (used.size() + free.size());
200:                    String hitRate = " (HitRate=" + getHitRate() + "%)";
201:                    log("Checkout - " + ratio + hitRate
202:                            + (o == null ? " - null returned" : ""));
203:                }
204:                return o;
205:            }
206:
207:            /**
208:             * Checks out an item from the pool.
209:             * If there is no pooled item available and the maximum number
210:             * possible has not been reached, another is created.
211:             * If a free item is detected as being invalid it is removed
212:             * from the pool and the another is retrieved.
213:             * If an item is not available and the maximum number possible
214:             * has been reached, the method waits for the timeout period
215:             * for one to become available by being checked in.
216:             * @param timeout timeout value in milliseconds
217:             * @return item from the pool, or null if nothing available within timeout period
218:             * @exception Exception if there is an error creating a new object
219:             */
220:            protected final synchronized Reusable checkOut(long timeout)
221:                    throws Exception {
222:                long time = System.currentTimeMillis();
223:                Reusable o = null;
224:                o = checkOut();
225:                while (o == null
226:                        && (System.currentTimeMillis() - time < timeout)) {
227:                    try {
228:                        if (debug)
229:                            log("No pooled items spare...waiting for up to "
230:                                    + timeout + "ms");
231:                        wait(timeout);
232:                        o = checkOut();
233:                    } catch (InterruptedException e) {
234:                        log(e, "Connection checkout interrupted");
235:                    }
236:                }
237:                return o;
238:            }
239:
240:            /**
241:             * Checks an object into the pool, and notify other
242:             * threads that may be waiting for one.
243:             * @param o object to check in
244:             */
245:            protected final void checkIn(Reusable o) {
246:                if (o == null) {
247:                    log("Attempt to return null item");
248:                    return;
249:                }
250:
251:                synchronized (this ) {
252:                    firePoolCheckInEvent();
253:
254:                    // Check if item is from this pool
255:                    if (!used.remove(o)) {
256:                        log("Attempt to return item not belonging to pool");
257:                        throw new RuntimeException(
258:                                "Attempt to return item not belonging to pool "
259:                                        + name);
260:                    }
261:
262:                    // If pool is full destroy object, else place in pool
263:                    boolean kill = maxSize > 0
264:                            && (free.size() + used.size() >= poolSize);
265:                    kill = kill || (maxSize == 0 && free.size() >= poolSize);
266:                    if (kill) {
267:                        destroyObject(o);
268:                        if (debug)
269:                            log("Checkin* - " + used.size() + "/"
270:                                    + (used.size() + free.size()));
271:                    } else {
272:                        try {
273:                            //  Recycle object for next use
274:                            o.recycle();
275:                            //  Add object to free list
276:                            free.add(new TimeWrapper(null, o, expiryTime));
277:                            if (debug)
278:                                log("Checkin  - " + used.size() + "/"
279:                                        + (used.size() + free.size()));
280:                            notifyAll();
281:                        } catch (Exception e) {
282:                            // If unable to recycle object, destroy it
283:                            destroyObject(o);
284:                            log(e, "Unable to recycle item - destroyed");
285:                        }
286:                    }
287:                }
288:            }
289:
290:            /**
291:             * Releases all items from the pool, and shuts the pool down.
292:             * If any items are still checked-out, this method waits until all items have
293:             * been checked-in before returning.
294:             */
295:            public final void release() {
296:                release(false);
297:            }
298:
299:            /**
300:             * Releases all items from the pool, and shuts the pool down.
301:             * This method returns immediately; a background thread is created to perform the release.
302:             */
303:            public final synchronized void releaseAsync() {
304:                releaseAsync(false);
305:            }
306:
307:            /**
308:             * Forcibly releases all items from the pool, and shuts the pool down.
309:             * If any items are still checked-out, this method forcibly destroys them
310:             * and then returns.
311:             */
312:            public final void releaseForcibly() {
313:                release(true);
314:            }
315:
316:            /**
317:             * Releases all items from the pool, and shuts the pool down.
318:             * @param forced whether to forcibly destroy items, or let them be checked-in
319:             */
320:            private final void release(boolean forced) {
321:                // Set released flag to prevent check-out of new items
322:                if (released)
323:                    return;
324:                released = true;
325:                //  Destroy cleaner thread
326:                if (cleaner != null) {
327:                    cleaner.halt();
328:                    try {
329:                        cleaner.join();
330:                    } catch (InterruptedException ie) {
331:                        log(ie,
332:                                "Interrupted during halting of old cleaner thread");
333:                    }
334:                    cleaner = null;
335:                }
336:
337:                synchronized (this ) {
338:                    int rel = 0, failed = 0;
339:                    TimeWrapper tw = null;
340:                    Reusable o = null;
341:                    // Destroy all items still in use
342:                    if (forced) {
343:                        for (Iterator iter = used.iterator(); iter.hasNext();) {
344:                            o = (Reusable) iter.next();
345:                            try {
346:                                destroy(o);
347:                                rel++;
348:                            } catch (Exception ex) {
349:                                failed++;
350:                                log(ex, "Unable to release item in pool");
351:                            }
352:                        }
353:                        used.clear();
354:                    } else {
355:                        if (debug && used.size() > 0)
356:                            log("Waiting for used items to be checked-in...");
357:                        while (used.size() > 0) {
358:                            try {
359:                                wait();
360:                            } catch (InterruptedException e) {
361:                            }
362:                        }
363:                    }
364:
365:                    // Destroy all currently free items
366:                    for (Iterator iter = free.iterator(); iter.hasNext();) {
367:                        tw = (TimeWrapper) iter.next();
368:                        o = (Reusable) tw.getObject();
369:                        try {
370:                            destroy(o);
371:                            rel++;
372:                        } catch (Exception ex) {
373:                            failed++;
374:                            log(ex, "Unable to release item in pool");
375:                        }
376:                    }
377:                    free.clear();
378:
379:                    //  Destroy log reference
380:                    if (debug) {
381:                        String s = "Released " + rel
382:                                + (rel > 1 ? " items" : " item");
383:                        if (failed > 0)
384:                            s += " (failed to release " + failed
385:                                    + (failed > 1 ? " items)" : " item)");
386:                        log(s);
387:                    }
388:                    firePoolReleasedEvent();
389:                    listeners.clear();
390:                    super .close();
391:                }
392:            }
393:
394:            /**
395:             * Releases all items from the pool, and shuts the pool down.
396:             * This method returns immediately; a background thread is created to perform the release.
397:             */
398:            private final void releaseAsync(final boolean forced) {
399:                Thread t = new Thread(new Runnable() {
400:                    public void run() {
401:                        release(forced);
402:                    }
403:                });
404:                t.start();
405:            }
406:
407:            /**
408:             * Object creation method.
409:             * This method is called when a new item needs to be created following a call
410:             * to one of the check-out methods.
411:             * @exception Exception if unable to create the item
412:             */
413:            protected abstract Reusable create() throws Exception;
414:
415:            /**
416:             * Object validation method.
417:             * This method is called when checking-out an item to see if it is valid for use.
418:             * When overridden by the sub-class it is recommended that this method perform
419:             * suitable checks to ensure the object can be used without problems.
420:             */
421:            protected abstract boolean isValid(final Reusable o);
422:
423:            /**
424:             * Object destruction method.
425:             * This method is called when an object needs to be destroyed due to pool
426:             * pruning/cleaning, or final release of the pool.
427:             */
428:            protected abstract void destroy(final Reusable o);
429:
430:            /**
431:             * Destroys the given object (asynchronously if necessary).
432:             */
433:            private final void destroyObject(final Reusable o) {
434:                if (o == null)
435:                    return;
436:                if (asyncDestroy) {
437:                    Thread t = new Thread(new Runnable() {
438:                        public void run() {
439:                            destroy(o);
440:                        }
441:                    });
442:                    t.start();
443:                } else
444:                    destroy(o);
445:            }
446:
447:            /**
448:             * Determines whether to perform asynchronous object destruction.
449:             * If set to true then each time an object is destroyed (invalid object
450:             * during pool operation, or when the pool is finally released) the operation
451:             * is done in a separate thread, allowing the method to return immediately.
452:             * This can be useful when calling the destroy method on an object takes a
453:             * long time to complete.
454:             */
455:            public final void setAsyncDestroy(boolean b) {
456:                asyncDestroy = b;
457:            }
458:
459:            /**
460:             * Returns whether asynchronous object destruction is enabled.
461:             * (Default: false)
462:             */
463:            public final boolean isAsyncDestroy() {
464:                return asyncDestroy;
465:            }
466:
467:            /**
468:             * Writes a message to the log.
469:             */
470:            public void log(String logEntry) {
471:                log(name + ": ", logEntry);
472:            }
473:
474:            /**
475:             * Writes a message with an Exception to the log file.
476:             */
477:            public void log(Throwable e, String logEntry) {
478:                log(e, name + ": ", logEntry);
479:            }
480:
481:            /**
482:             * Returns the pool name.
483:             */
484:            public final String getName() {
485:                return this .name;
486:            }
487:
488:            /**
489:             * Returns the maximum size of the pool.
490:             */
491:            public final int getPoolSize() {
492:                return poolSize;
493:            }
494:
495:            /**
496:             * Returns the maximum number of items that can be created.
497:             */
498:            public final int getMaxSize() {
499:                return maxSize;
500:            }
501:
502:            /**
503:             * Returns the expiry time for unused items in the pool.
504:             */
505:            public final long getExpiryTime() {
506:                return expiryTime;
507:            }
508:
509:            /**
510:             * Sets the pooling parameters.
511:             * Any items currently in the pool will remain, subject to the new parameters.
512:             * (The hit rate counters are reset when this method is called.)
513:             * @param poolSize number of items to be keep in pool
514:             * @param maxSize maximum number of items to be created
515:             * @param expiryTime expiry time for unused items (milliseconds) (0 = no expiry)
516:             */
517:            public final void setParameters(int poolSize, int maxSize,
518:                    long expiryTime) {
519:                synchronized (this ) {
520:                    if (cleaner != null)
521:                        cleaner.halt();
522:
523:                    this .poolSize = Math.max(poolSize, 0);
524:                    this .maxSize = Math.max(maxSize, 0);
525:                    this .expiryTime = Math.max(expiryTime, 0);
526:                    if (this .maxSize > 0 && this .maxSize < this .poolSize)
527:                        this .maxSize = this .poolSize;
528:                    resetHitCounter();
529:
530:                    //  Update pooled items to use new expiry
531:                    TimeWrapper tw = null;
532:                    for (Iterator iter = free.iterator(); iter.hasNext();) {
533:                        tw = (TimeWrapper) iter.next();
534:                        tw.setLiveTime(expiryTime);
535:                    }
536:                    //  Creates cleaner thread with check interval of at most 5 seconds.
537:                    if (this .expiryTime > 0) {
538:                        long iVal = Math.min(5000, this .expiryTime / 5);
539:                        (cleaner = new Cleaner(this , iVal)).start();
540:                    }
541:                }
542:                if (debug) {
543:                    String info = "pool=" + this .poolSize + ",max="
544:                            + this .maxSize + ",expiry=";
545:                    info += this .expiryTime == 0 ? "none" : this .expiryTime
546:                            + "ms";
547:                    log("Parameters changed (" + info + ")");
548:                }
549:                fireParametersChangedEvent();
550:            }
551:
552:            /**
553:             * Returns the total number of objects held (available and checked-out).
554:             */
555:            public final synchronized int getSize() {
556:                return free.size() + used.size();
557:            }
558:
559:            /**
560:             * Returns the number of items that are currently checked-out.
561:             */
562:            public final synchronized int getCheckedOut() {
563:                return used.size();
564:            }
565:
566:            /**
567:             * Returns the number of items held in the pool that are free to be checked-out.
568:             */
569:            public final synchronized int getFreeCount() {
570:                return free.size();
571:            }
572:
573:            /**
574:             * Returns hit rate of the pool as a percentage.
575:             * The hit rate is the proportion of requests for a connection which result
576:             * in the return of a connection which is in the pool, rather than which
577:             * results in the creation of a new connection.
578:             */
579:            public final float getHitRate() {
580:                return (requests == 0) ? 0 : (((float) hits / requests) * 100f);
581:            }
582:
583:            /**
584:             * Resets the counter for determining the pool's hit rate.
585:             */
586:            protected final void resetHitCounter() {
587:                requests = hits = 0;
588:            }
589:
590:            /**
591:             * Sets the pool access method to FIFO (first-in, first-out: a queue).
592:             */
593:            protected final void setAccessFIFO() {
594:                accessMethod = ACCESS_FIFO;
595:            }
596:
597:            /**
598:             * Sets the pool access method to LIFO (last-in, first-out: a stack).
599:             */
600:            protected final void setAccessLIFO() {
601:                accessMethod = ACCESS_LIFO;
602:            }
603:
604:            /**
605:             * Sets the pool access method to random (a random connection is selected for check-out).
606:             */
607:            protected final void setAccessRandom() {
608:                accessMethod = ACCESS_RANDOM;
609:            }
610:
611:            /**
612:             * Returns the class to use for the pool collection.
613:             * This can be over-ridden by a sub-class to provide a different List
614:             * type for the pool, which may give performance benefits in certain situations.
615:             * Only instances of List collections should be used.
616:             * (Default: java.util.ArrayList.class)
617:             * For those wanting to override this method, pool items are checked-out from
618:             * the front of the List - <tt>remove(0)</tt> - and replaced at the end of
619:             * the List when checked-in again - <tt>add(Object)</tt>.
620:             */
621:            protected Class getPoolClass() {
622:                return ArrayList.class;
623:            }
624:
625:            /**
626:             * Shuts down the object pool.
627:             * If overridden the sub-class should make sure super.finalize() is called.
628:             */
629:            public void finalize() {
630:                if (cleaner != null) {
631:                    cleaner.halt();
632:                    cleaner = null;
633:                }
634:                if (initer != null) {
635:                    initer.halt();
636:                    initer = null;
637:                }
638:            }
639:
640:            /**
641:             * Flushes the pool of all currently available items, emptying the pool.
642:             */
643:            public final void flush() {
644:                int count = 0;
645:                synchronized (this ) {
646:                    TimeWrapper tw = null;
647:                    for (Iterator iter = free.iterator(); iter.hasNext();) {
648:                        tw = (TimeWrapper) iter.next();
649:                        iter.remove();
650:                        destroyObject((Reusable) tw.getObject());
651:                        count++;
652:                    }
653:                }
654:                if (count > 0 && debug)
655:                    log("Flushed all spare items from pool");
656:            }
657:
658:            /**
659:             * Purges expired objects from the pool.
660:             * This method is called by the cleaner thread to purge expired items.
661:             * @return false if pool is empty after purging (no further purge required until items added), true otherwise
662:             */
663:            final synchronized boolean purge() {
664:                if (debug)
665:                    log("Checking for expired items");
666:                int count = 0;
667:                TimeWrapper tw = null;
668:                for (Iterator iter = free.iterator(); iter.hasNext();) {
669:                    tw = (TimeWrapper) iter.next();
670:                    if (tw.isExpired()) {
671:                        iter.remove();
672:                        destroyObject((Reusable) tw.getObject());
673:                        count++;
674:                    }
675:                }
676:                return free.size() > 0 || count > 0;
677:            }
678:
679:            //**************************
680:            //  Event-handling methods
681:            //**************************
682:
683:            /**
684:             * Adds an ObjectPoolListener to the event notification list.
685:             */
686:            public final void addObjectPoolListener(ObjectPoolListener x) {
687:                listeners.add(x);
688:            }
689:
690:            /**
691:             * Removes an ObjectPoolListener from the event notification list.
692:             */
693:            public final void removeObjectPoolListener(ObjectPoolListener x) {
694:                listeners.remove(x);
695:            }
696:
697:            private final void firePoolCheckOutEvent() {
698:                if (listeners.isEmpty())
699:                    return;
700:                ObjectPoolEvent poolEvent = new ObjectPoolEvent(this ,
701:                        ObjectPoolEvent.CHECKOUT);
702:                for (Iterator iter = listeners.iterator(); iter.hasNext();)
703:                    ((ObjectPoolListener) iter.next()).poolCheckOut(poolEvent);
704:            }
705:
706:            private final void firePoolCheckInEvent() {
707:                if (listeners.isEmpty())
708:                    return;
709:                ObjectPoolEvent poolEvent = new ObjectPoolEvent(this ,
710:                        ObjectPoolEvent.CHECKIN);
711:                for (Iterator iter = listeners.iterator(); iter.hasNext();)
712:                    ((ObjectPoolListener) iter.next()).poolCheckIn(poolEvent);
713:            }
714:
715:            private final void fireMaxPoolLimitReachedEvent() {
716:                if (listeners.isEmpty())
717:                    return;
718:                ObjectPoolEvent poolEvent = new ObjectPoolEvent(this ,
719:                        ObjectPoolEvent.MAX_POOL_LIMIT_REACHED);
720:                for (Iterator iter = listeners.iterator(); iter.hasNext();)
721:                    ((ObjectPoolListener) iter.next())
722:                            .maxPoolLimitReached(poolEvent);
723:            }
724:
725:            private final void fireMaxPoolLimitExceededEvent() {
726:                if (listeners.isEmpty())
727:                    return;
728:                ObjectPoolEvent poolEvent = new ObjectPoolEvent(this ,
729:                        ObjectPoolEvent.MAX_POOL_LIMIT_EXCEEDED);
730:                for (Iterator iter = listeners.iterator(); iter.hasNext();)
731:                    ((ObjectPoolListener) iter.next())
732:                            .maxPoolLimitExceeded(poolEvent);
733:            }
734:
735:            private final void fireMaxSizeLimitReachedEvent() {
736:                if (listeners.isEmpty())
737:                    return;
738:                ObjectPoolEvent poolEvent = new ObjectPoolEvent(this ,
739:                        ObjectPoolEvent.MAX_SIZE_LIMIT_REACHED);
740:                for (Iterator iter = listeners.iterator(); iter.hasNext();)
741:                    ((ObjectPoolListener) iter.next())
742:                            .maxSizeLimitReached(poolEvent);
743:            }
744:
745:            private final void fireMaxSizeLimitErrorEvent() {
746:                if (listeners.isEmpty())
747:                    return;
748:                ObjectPoolEvent poolEvent = new ObjectPoolEvent(this ,
749:                        ObjectPoolEvent.MAX_SIZE_LIMIT_ERROR);
750:                for (Iterator iter = listeners.iterator(); iter.hasNext();)
751:                    ((ObjectPoolListener) iter.next())
752:                            .maxSizeLimitError(poolEvent);
753:            }
754:
755:            private final void fireParametersChangedEvent() {
756:                if (listeners == null || listeners.isEmpty())
757:                    return;
758:                ObjectPoolEvent poolEvent = new ObjectPoolEvent(this ,
759:                        ObjectPoolEvent.PARAMETERS_CHANGED);
760:                for (Iterator iter = listeners.iterator(); iter.hasNext();)
761:                    ((ObjectPoolListener) iter.next())
762:                            .poolParametersChanged(poolEvent);
763:            }
764:
765:            private final void firePoolReleasedEvent() {
766:                if (listeners.isEmpty())
767:                    return;
768:                ObjectPoolEvent poolEvent = new ObjectPoolEvent(this ,
769:                        ObjectPoolEvent.POOL_RELEASED);
770:                for (Iterator iter = listeners.iterator(); iter.hasNext();)
771:                    ((ObjectPoolListener) iter.next()).poolReleased(poolEvent);
772:            }
773:
774:            /**
775:             * Thread to perform clean-up of expired objects in pool.
776:             * Each time nothing is cleaned because the pool is empty the cleaner waits
777:             * until an item is returned, when it is woken up and starts cleaning again.
778:             */
779:            final class Cleaner extends Thread {
780:                private ObjectPool pool;
781:                private long interval;
782:                private boolean stopped;
783:
784:                Cleaner(ObjectPool pool, long interval) {
785:                    this .setName("CleanerThread_"
786:                            + Integer.toString(cleanerCount++));
787:                    this .pool = pool;
788:                    this .interval = interval;
789:                }
790:
791:                public void start() {
792:                    stopped = false;
793:                    super .start();
794:                }
795:
796:                /**
797:                 * Safely stops the thread from running.
798:                 */
799:                public void halt() {
800:                    if (!isHalted()) {
801:                        stopped = true;
802:                        interrupt(); // Wake cleaner if necessary
803:                    }
804:                }
805:
806:                /**
807:                 * Returns whether the thread has been halted.
808:                 */
809:                public boolean isHalted() {
810:                    return stopped;
811:                }
812:
813:                /**
814:                 * Handles the expiry of old objects.
815:                 */
816:                public void run() {
817:                    while (pool.cleaner == Thread.currentThread() && !stopped) {
818:                        synchronized (pool) {
819:                            if (!pool.purge()) {
820:                                try {
821:                                    pool.wait();
822:                                } catch (InterruptedException e) {
823:                                }
824:                            }
825:                        }
826:                        if (!stopped) {
827:                            try {
828:                                sleep(interval);
829:                            } catch (InterruptedException e) {
830:                            }
831:                        }
832:                    }
833:                }
834:            }
835:
836:            /**
837:             * Thread to initialize items in pool.
838:             * This thread simply performs a check-out/in of new items up to the specified
839:             * number to ensure the pool is populated.
840:             */
841:            private class InitThread extends Thread {
842:                private int num;
843:                private boolean stopped = false;
844:
845:                private InitThread(int num) {
846:                    // Ensure 0 < num < poolSize.
847:                    this .num = Math.min(poolSize, Math.max(num, 0));
848:                }
849:
850:                public void halt() {
851:                    stopped = true;
852:                }
853:
854:                /**
855:                 * Populates the pool with the given number of database connections.
856:                 * If the pool already contains open connections then they will be counted
857:                 * towards the number created by this method.
858:                 */
859:                public void run() {
860:                    if (num > 0 && num <= poolSize && getSize() < num) {
861:                        int count = 0;
862:                        while (!stopped && getSize() < num && num <= poolSize) {
863:                            try {
864:                                Reusable o = create();
865:                                if (o == null)
866:                                    throw new RuntimeException(
867:                                            "Null item created");
868:                                else {
869:                                    free.add(new TimeWrapper(null, o,
870:                                            expiryTime));
871:                                    count++;
872:                                    if (debug)
873:                                        log("Initialized new item in pool");
874:                                }
875:                            } catch (Exception ex) {
876:                                log(ex, "Unable to initialize items in pool");
877:                                stopped = true;
878:                            }
879:                        }
880:                        if (debug)
881:                            log("Initialized pool with " + count + " new item"
882:                                    + (count > 1 ? "s" : ""));
883:                    }
884:                }
885:            }
886:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.