Source Code Cross Referenced for ObjectPool.java in  » ERP-CRM-Financial » SourceTap-CRM » org » ofbiz » minerva » pool » 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 » ERP CRM Financial » SourceTap CRM » org.ofbiz.minerva.pool 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed under the X license (see http://www.x.org/terms.htm)
0003:         */
0004:        package org.ofbiz.minerva.pool;
0005:
0006:        import EDU.oswego.cs.dl.util.concurrent.FIFOSemaphore;
0007:
0008:        import java.util.ArrayList;
0009:        import java.util.Collection;
0010:        import java.util.Collections;
0011:        import java.util.ConcurrentModificationException;
0012:        import java.util.HashMap;
0013:        import java.util.HashSet;
0014:        import java.util.Iterator;
0015:        import java.util.Map;
0016:        import java.util.Set;
0017:
0018:        import org.apache.log4j.Logger;
0019:
0020:        /**
0021:         * A generic object pool.  You must provide a PoolObjectFactory (or the class
0022:         * of a Java Bean) so the pool knows what kind of objects to create.  It has
0023:         * many configurable parameters, such as the minimum and maximum size of the
0024:         * pool, whether to enable idle timeouts, etc.  If the pooled objects
0025:         * implement PooledObject, they will automatically be returned to the pool at
0026:         * the appropriate times.
0027:         * <P>In general, the appropriate way to use a pool is:</P>
0028:         * <OL>
0029:         *   <LI>Create it</LI>
0030:         *   <LI>Configure it (set factory, name, parameters, etc.)</LI>
0031:         *   <LI>Initialize it (once done, further configuration is not allowed)</LI>
0032:         *   <LI>Use it</LI>
0033:         *   <LI>Shut it down</LI>
0034:         * </OL>
0035:         * @see org.ofbiz.minerva.pool.PooledObject
0036:         *
0037:         * @author Aaron Mulder (ammulder@alumni.princeton.edu)
0038:         * @author <a href="mailto:danch@nvisia.com">danch (Dan Christopherson)</a>
0039:         *
0040:         * Revision:
0041:         * 20010701 danch added code for timeout in blocking.
0042:         */
0043:        public class ObjectPool implements  PoolEventListener {
0044:
0045:            private final static String INITIALIZED = "Pool already initialized!";
0046:            private final static PoolGCThread collector = new PoolGCThread();
0047:
0048:            static {
0049:                collector.start();
0050:            }
0051:
0052:            private Logger log = Logger.getLogger(ObjectPool.class);
0053:            private PoolObjectFactory factory;
0054:            private String poolName;
0055:
0056:            private final Map objects = new HashMap();
0057:            private final Set deadObjects = Collections
0058:                    .synchronizedSet(new HashSet());
0059:            private int minSize = 0;
0060:            private int maxSize = 0;
0061:            private boolean idleTimeout = false;
0062:            private boolean runGC = false;
0063:            private float maxIdleShrinkPercent = 1.0f; // don't replace idle connections that timeout
0064:            private long idleTimeoutMillis = 1800000l; // must be idle in pool for 30 minutes
0065:            private long gcMinIdleMillis = 1200000l; // must be unused by client for 20 minutes
0066:            private long gcIntervalMillis = 120000l; // shrink & gc every 2 minutes
0067:            private long lastGC = System.currentTimeMillis();
0068:            private boolean blocking = true;
0069:            private int blockingTimeout = 10000;//Integer.MAX_VALUE;//this is silly
0070:            private boolean trackLastUsed = false;
0071:            private boolean invalidateOnError = false;
0072:
0073:            private FIFOSemaphore permits;
0074:            private boolean initialized = false;
0075:
0076:            /**
0077:             * Creates a new pool.  It cannot be used until you specify a name and
0078:             * object factory or bean class, and initialize it.
0079:             * @see #setName
0080:             * @see #setObjectFactory
0081:             * @see #initialize
0082:             */
0083:            public ObjectPool() {
0084:            }
0085:
0086:            /**
0087:             * Creates a new pool with the specified parameters.  It cannot be used
0088:             * until you initialize it.
0089:             * @param factory The object factory that will create the objects to go in
0090:             *    the pool.
0091:             * @param poolName The name of the pool.  This does not have to be unique
0092:             *    across all pools, but it is strongly recommended (and it may be a
0093:             *    requirement for certain uses of the pool).
0094:             * @see #initialize
0095:             */
0096:            public ObjectPool(PoolObjectFactory factory, String poolName) {
0097:                setObjectFactory(factory);
0098:                setName(poolName);
0099:            }
0100:
0101:            /**
0102:             * Creates a new pool with the specified parameters.  It cannot be used
0103:             * until you initialize it.
0104:             * @param javaBeanClass The Class of a Java Bean.  New instances for the
0105:             *    pool will be created with the no-argument constructor, and no
0106:             *    particular initialization or cleanup will be performed on the
0107:             *    instances.  Use a PoolObjectFactory if you want more control over
0108:             *    the instances.
0109:             * @param poolName The name of the pool.  This does not have to be unique
0110:             *    across all pools, but it is strongly recommended (and it may be a
0111:             *    requirement for certain uses of the pool).
0112:             * @see #initialize
0113:             */
0114:            public ObjectPool(Class javaBeanClass, String poolName) {
0115:                setObjectFactory(javaBeanClass);
0116:                setName(poolName);
0117:            }
0118:
0119:            /**
0120:             * Sets the object factory for the pool.  The object factory controls the
0121:             * instances created for the pool, and can initialize instances given out
0122:             * by the pool and cleanup instances returned to the pool.
0123:             * @throws java.lang.IllegalStateException
0124:             *    Occurs when you try to set the object factory after the pool has been
0125:             *    initialized.
0126:             */
0127:            public void setObjectFactory(PoolObjectFactory factory) {
0128:                if (initialized)
0129:                    throw new IllegalStateException(INITIALIZED);
0130:                this .factory = factory;
0131:            }
0132:
0133:            /**
0134:             * Sets the object factory as a new factory for Java Beans.  New instances
0135:             *    for the pool will be created with the no-argument constructor, and no
0136:             *    particular initialization or cleanup will be performed on the
0137:             *    instances.
0138:             * @throws java.lang.IllegalStateException
0139:             *    Occurs when you try to set the object factory after the pool has been
0140:             *    initialized.
0141:             */
0142:            public void setObjectFactory(Class javaBeanClass) {
0143:                if (initialized)
0144:                    throw new IllegalStateException(INITIALIZED);
0145:                factory = new BeanFactory(javaBeanClass);
0146:            }
0147:
0148:            /**
0149:             * Sets the name of the pool.  This is not required to be unique across all
0150:             * pools, but is strongly recommended.  Certain uses of the pool (such as
0151:             * a JNDI object factory) may require it.  This must be set exactly once
0152:             * for each pool (it may be set in the constructor).
0153:             * @throws java.lang.IllegalStateException
0154:             *    Occurs when you try to set the name of the pool more than once.
0155:             */
0156:            public void setName(String name) {
0157:                if (name == null || name.length() == 0)
0158:                    throw new IllegalArgumentException(
0159:                            "Cannot set pool name to null or empty!");
0160:                if (poolName != null && !poolName.equals(name))
0161:                    throw new IllegalStateException(
0162:                            "Cannot change pool name once set!");
0163:                poolName = name;
0164:                log = Logger.getLogger(ObjectPool.class.getName() + "." + name);
0165:            }
0166:
0167:            /**
0168:             * Gets the name of the pool.
0169:             */
0170:            public String getName() {
0171:                return poolName;
0172:            }
0173:
0174:            /**
0175:             * Sets the minimum size of the pool.  The pool will create this many
0176:             * instances at startup, and once running, it will never shrink below this
0177:             * size.  The default is zero.
0178:             * @throws java.lang.IllegalStateException
0179:             *    Occurs when you try to set the minimum size after the pool has been
0180:             *    initialized.
0181:             */
0182:            public void setMinSize(int size) {
0183:                if (initialized)
0184:                    throw new IllegalStateException(INITIALIZED);
0185:                minSize = size;
0186:                if (maxSize != 0 && minSize > maxSize) {
0187:                    maxSize = minSize;
0188:                    log.warn("pool max size set to " + maxSize
0189:                            + " to stay >= min size");
0190:                }
0191:            }
0192:
0193:            /**
0194:             * Gets the minimum size of the pool.
0195:             * @see #setMinSize
0196:             */
0197:            public int getMinSize() {
0198:                return minSize;
0199:            }
0200:
0201:            /**
0202:             * Sets the maximum size of the pool.  Once the pool has grown to hold this
0203:             * number of instances, it will not add any more instances.  If one of the
0204:             * pooled instances is available when a request comes in, it will be
0205:             * returned.  If none of the pooled instances are available, the pool will
0206:             * either block until an instance is available, or return null.  The default
0207:             * is no maximum size.
0208:             * @see #setBlocking
0209:             * @param size The maximum size of the pool, or 0 if the pool should grow
0210:             *    indefinitely (not recommended).
0211:             * @throws java.lang.IllegalStateException
0212:             *    Occurs when you try to set the maximum size after the pool has been
0213:             *    initialized.
0214:             */
0215:            public void setMaxSize(int size) {
0216:                if (initialized)
0217:                    throw new IllegalStateException(INITIALIZED);
0218:                maxSize = size;
0219:                if (maxSize != 0 && minSize > maxSize) {
0220:                    minSize = maxSize;
0221:                    log.warn("pool min size set to " + minSize
0222:                            + " to stay <= max size");
0223:                }
0224:            }
0225:
0226:            /**
0227:             * Gets the maximum size of the pool.
0228:             * @see #setMaxSize
0229:             */
0230:            public int getMaxSize() {
0231:                return maxSize;
0232:            }
0233:
0234:            /**
0235:             * Sets whether the pool should release instances that have not been used
0236:             * recently.  This is intended to reclaim resources (memory, database
0237:             * connections, file handles, etc) during periods of inactivity.  This runs
0238:             * as often as garbage collection (even if garbage collection is disabled,
0239:             * this uses the same timing parameter), but the required period of
0240:             * inactivity is different.  All objects that have been unused for more
0241:             * than the idle timeout are closed, but if you set the MaxIdleShrinkPercent
0242:             * parameter, the pool may recreate some objects so the total number of
0243:             * pooled instances doesn't shrink as rapidly. Also, under no circumstances
0244:             * will the number of pooled instances fall below the minimum size.</p>
0245:             * <P>The default is disabled.</P>
0246:             * @see #setGCInterval
0247:             * @see #setIdleTimeout
0248:             * @see #setMaxIdleTimeoutPercent
0249:             * @see #setMinSize
0250:             * @throws java.lang.IllegalStateException
0251:             *    Occurs when you try to set the idle timeout state after the pool has
0252:             *    been initialized.
0253:             */
0254:            public void setIdleTimeoutEnabled(boolean enableTimeout) {
0255:                if (initialized)
0256:                    throw new IllegalStateException(INITIALIZED);
0257:                idleTimeout = enableTimeout;
0258:            }
0259:
0260:            /**
0261:             * Gets whether the pool releases instances that have not been used
0262:             * recently.  This is different than garbage collection, which returns
0263:             * instances to the pool if a client checked an instance out but has not
0264:             * used it and not returned it to the pool.
0265:             * @see #setIdleTimeoutEnabled
0266:             */
0267:            public boolean isIdleTimeoutEnabled() {
0268:                return idleTimeout;
0269:            }
0270:
0271:            /**
0272:             * Sets whether garbage collection is enabled.  This is the process of
0273:             * returning objects to the pool if they have been checked out of the pool
0274:             * but have not been used in a long periond of time.  This is meant to
0275:             * reclaim resources, generally caused by unexpected failures on the part
0276:             * of the pool client (which forestalled returning an object to the pool).
0277:             * This runs on the same schedule as the idle timeout (if enabled), but
0278:             * objects that were just garbage collected will not be eligible for the
0279:             * idle timeout immediately (after all, they presumably represented "active"
0280:             * clients).  Objects that are garbage collected will be checked out again
0281:             * immediately if a client is blocking waiting for an object.  The default
0282:             * value is disabled.
0283:             * @see #setGCMinIdleTime
0284:             * @see #setGCInterval
0285:             * @throws java.lang.IllegalStateException
0286:             *    Occurs when you try to set the garbage collection state after the pool
0287:             *    has been initialized.
0288:             */
0289:            public void setGCEnabled(boolean enabled) {
0290:                if (initialized)
0291:                    throw new IllegalStateException(INITIALIZED);
0292:                runGC = enabled;
0293:            }
0294:
0295:            /**
0296:             * Gets whether garbage collection is enabled.
0297:             * @see #setGCEnabled
0298:             */
0299:            public boolean isGCEnabled() {
0300:                return runGC;
0301:            }
0302:
0303:            /**
0304:             * Sets the idle timeout percent as a fraction between 0 and 1.  If a number
0305:             * of objects are determined to be idle, they will all be closed and
0306:             * removed from the pool.  However, if the ratio of objects released to
0307:             * objects in the pool is greater than this fraction, some new objects
0308:             * will be created to replace the closed objects.  This prevents the pool
0309:             * size from decreasing too rapidly.  Set to 0 to decrease the pool size by
0310:             * a maximum of 1 object per test, or 1 to never replace objects that have
0311:             * exceeded the idle timeout.  The pool will always replace enough closed
0312:             * connections to stay at the minimum size.
0313:             * @see #setIdleTimeoutEnabled
0314:             * @throws java.lang.IllegalStateException
0315:             *    Occurs when you try to set the idle timeout percent after the pool
0316:             *    has been initialized.
0317:             * @throws java.lang.IllegalArgumentException
0318:             *    Occurs when the percent parameter is not between 0 and 1.
0319:             */
0320:            public void setMaxIdleTimeoutPercent(float percent) {
0321:                if (initialized)
0322:                    throw new IllegalStateException(INITIALIZED);
0323:                if (percent < 0f || percent > 1f)
0324:                    throw new IllegalArgumentException(
0325:                            "Percent must be between 0 and 1!");
0326:                maxIdleShrinkPercent = percent;
0327:            }
0328:
0329:            /**
0330:             * Gets the idle timeout percent as a fraction between 0 and 1.
0331:             * @see #setMaxIdleTimeoutPercent
0332:             */
0333:            public float getMaxIdleTimeoutPercent() {
0334:                return maxIdleShrinkPercent;
0335:            }
0336:
0337:            /**
0338:             * Sets the minimum idle time to release an unused object from the pool.  If
0339:             * the object is not in use and has not been used for this amount of time,
0340:             * it will be released from the pool.  If timestamps are enabled, the client
0341:             * may update the last used time.  Otherwise, the last used time is only
0342:             * updated when an object is acquired or released.  The default value is
0343:             * 30 minutes.
0344:             * @see #setIdleTimeoutEnabled
0345:             * @param millis The idle time, in milliseconds.
0346:             * @throws java.lang.IllegalStateException
0347:             *    Occurs when you try to set the idle timeout after the pool
0348:             *    has been initialized.
0349:             */
0350:            public void setIdleTimeout(long millis) {
0351:                if (initialized)
0352:                    throw new IllegalStateException(INITIALIZED);
0353:                idleTimeoutMillis = millis;
0354:
0355:                if (log.isDebugEnabled())
0356:                    log.debug("setIdleTimeout(" + millis + ")");
0357:            }
0358:
0359:            /**
0360:             * Gets the minimum idle time to release an unused object from the pool.
0361:             * @see #setIdleTimeout
0362:             */
0363:            public long getIdleTimeout() {
0364:                return idleTimeoutMillis;
0365:            }
0366:
0367:            /**
0368:             * Sets the minimum idle time to make an object eligible for garbage
0369:             * collection.  If the object is in use and has not been used for this
0370:             * amount of time, it may be returned to the pool.  If timestamps are
0371:             * enabled, the client may update the last used time (this is generally
0372:             * recommended if garbage collection is enabled).  Otherwise, the last used
0373:             * time is only updated when an object is acquired or released.  The default
0374:             * value is 20 minutes.
0375:             * @see #setGCEnabled
0376:             * @param millis The idle time, in milliseconds.
0377:             * @throws java.lang.IllegalStateException
0378:             *    Occurs when you try to set the garbage collection idle time after the
0379:             *    pool has been initialized.
0380:             */
0381:            public void setGCMinIdleTime(long millis) {
0382:                if (initialized)
0383:                    throw new IllegalStateException(INITIALIZED);
0384:                gcMinIdleMillis = millis;
0385:
0386:                if (log.isDebugEnabled())
0387:                    log.debug("setGCMinIdleTime(" + millis + ")");
0388:            }
0389:
0390:            /**
0391:             * Gets the minimum idle time to make an object eligible for garbage
0392:             * collection.
0393:             * @see #setGCMinIdleTime
0394:             */
0395:            public long getGCMinIdleTime() {
0396:                return gcMinIdleMillis;
0397:            }
0398:
0399:            /**
0400:             * Sets the length of time between garbage collection and idle timeout runs.
0401:             * This is inexact - if there are many pools with garbage collection and/or
0402:             * the idle timeout enabled, there will not be a thread for each one, and
0403:             * several nearby actions may be combined.  Likewise if the collection
0404:             * process is lengthy for certain types of pooled objects (not recommended),
0405:             * other actions may be delayed.  This is to prevend an unnecessary
0406:             * proliferation of threads.  Note that this parameter controls
0407:             * both garbage collection and the idle timeout - and they will be performed
0408:             * together if both are enabled.  The deafult value is 2 minutes.
0409:             * @throws java.lang.IllegalStateException
0410:             *    Occurs when you try to set the garbage collection interval after the
0411:             *    pool has been initialized.
0412:             */
0413:            public void setGCInterval(long millis) {
0414:                if (initialized)
0415:                    throw new IllegalStateException(INITIALIZED);
0416:
0417:                gcIntervalMillis = millis;
0418:
0419:                if (log.isDebugEnabled())
0420:                    log.debug("setGCInterval(" + gcIntervalMillis + ")");
0421:            }
0422:
0423:            /**
0424:             * Gets the length of time between garbage collection and idle timeout runs.
0425:             * @see #setGCInterval
0426:             */
0427:            public long getGCInterval() {
0428:                return gcIntervalMillis;
0429:            }
0430:
0431:            /**
0432:             * Sets whether a request for an object will block if the pool size is
0433:             * maxed out and no objects are available.  If set to block, the request
0434:             * will not return until an object is available.  Otherwise, the request
0435:             * will return null immediately (and may be retried).  If multiple
0436:             * requests block, there is no guarantee which will return first.  The
0437:             * default is to block.
0438:             * @throws java.lang.IllegalStateException
0439:             *    Occurs when you try to set the blocking parameter after the
0440:             *    pool has been initialized.
0441:             */
0442:            public void setBlocking(boolean blocking) {
0443:                if (initialized)
0444:                    throw new IllegalStateException(INITIALIZED);
0445:                this .blocking = blocking;
0446:            }
0447:
0448:            /**
0449:             * Gets whether a request for an object will block if the pool size is
0450:             * maxed out and no objects are available.
0451:             * @see #setBlocking
0452:             */
0453:            public boolean isBlocking() {
0454:                return blocking;
0455:            }
0456:
0457:            /** sets how long to wait for a free object when blocking, -1 indicating
0458:             *  forever.
0459:             */
0460:            public void setBlockingTimeout(int blockingTimeout) {
0461:                this .blockingTimeout = blockingTimeout;
0462:            }
0463:
0464:            /** get how long this pool will wait for a free object while blocking */
0465:            public int getBlockingTimeout() {
0466:                return this .blockingTimeout;
0467:            }
0468:
0469:            /**
0470:             * Sets whether object clients can update the last used time.  If not, the
0471:             * last used time will only be updated when the object is given to a client
0472:             * and returned to the pool.  This time is important if the idle timeout or
0473:             * garbage collection is enabled (particularly the latter).  The default
0474:             * is false.
0475:             * @throws java.lang.IllegalStateException
0476:             *    Occurs when you try to set the timestamp parameter after the
0477:             *    pool has been initialized.
0478:             */
0479:            public void setTimestampUsed(boolean timestamp) {
0480:                if (initialized)
0481:                    throw new IllegalStateException(INITIALIZED);
0482:
0483:                trackLastUsed = timestamp;
0484:
0485:                if (log.isDebugEnabled())
0486:                    log.debug("setTimestampUsed(" + timestamp + ")");
0487:            }
0488:
0489:            /**
0490:             * Gets whether object clients can update the last used time.
0491:             */
0492:            public boolean isTimestampUsed() {
0493:                return trackLastUsed;
0494:            }
0495:
0496:            /**
0497:             * Sets the response for object errors.  If this flag is set and an error
0498:             * event occurs, the object is removed from the pool entirely.  Otherwise,
0499:             * the object is returned to the pool of available objects.  For example, a
0500:             * SQL error may not indicate a bad database connection (flag not set),
0501:             * while a TCP/IP error probably indicates a bad network connection (flag
0502:             * set).  If this flag is not set, you can still manually invalidate
0503:             * objects using markObjectAsInvalid.
0504:             * @see #markObjectAsInvalid
0505:             * @see #objectError
0506:             */
0507:            public void setInvalidateOnError(boolean invalidate) {
0508:                if (initialized)
0509:                    throw new IllegalStateException(INITIALIZED);
0510:                invalidateOnError = invalidate;
0511:            }
0512:
0513:            /**
0514:             * Gets whether objects are removed from the pool in case of errors.
0515:             */
0516:            public boolean isInvalidateOnError() {
0517:                return invalidateOnError;
0518:            }
0519:
0520:            /**
0521:             * Prepares the pool for use.  This must be called exactly once before
0522:             * getObject is even called.  The pool name and object factory must be set
0523:             * before this call will succeed.
0524:             * @throws java.lang.IllegalStateException
0525:             *    Occurs when you try to initialize the pool without setting the object
0526:             *    factory or name, or you initialize the pool more than once.
0527:             */
0528:            public void initialize() {
0529:                if (factory == null || poolName == null)
0530:                    throw new IllegalStateException(
0531:                            "Factory and Name must be set before pool initialization!");
0532:                if (initialized)
0533:                    throw new IllegalStateException(
0534:                            "Cannot initialize more than once!");
0535:                initialized = true;
0536:                permits = new FIFOSemaphore(maxSize);
0537:                factory.poolStarted(this );
0538:                lastGC = System.currentTimeMillis();
0539:                //fill pool to min size
0540:                fillToMin();
0541:                /*
0542:                int max = maxSize <= 0 ? minSize : Math.min(minSize, maxSize);
0543:                Collection cs = new LinkedList();
0544:                for(int i=0; i<max; i++)
0545:                {
0546:                   cs.add(getObject(null));
0547:                }
0548:                while (Iterator i = cs.iterator(); i.hasNext();)
0549:                {
0550:                   releaseObject(i.next());
0551:                } // end of while ()
0552:                 */
0553:                collector.addPool(this );
0554:            }
0555:
0556:            /**
0557:             * Shuts down the pool.  All outstanding objects are closed and all objects
0558:             * are released from the pool.  No getObject or releaseObject calls will
0559:             * succeed after this method is called - and they will probably fail during
0560:             * this method call.
0561:             */
0562:            public void shutDown() {
0563:                collector.removePool(this );
0564:                factory.poolClosing(this );
0565:
0566:                // close all objects
0567:                synchronized (objects) {
0568:                    for (Iterator it = objects.values().iterator(); it
0569:                            .hasNext();) {
0570:                        ObjectRecord rec = (ObjectRecord) it.next();
0571:                        if (null != rec) {
0572:                            if (rec.isInUse())
0573:                                factory.returnObject(rec.getClientObject());
0574:                            factory.deleteObject(rec.getObject());
0575:                            rec.close();
0576:                        }
0577:                    }
0578:                    objects.clear();
0579:                    deadObjects.clear();
0580:                }//end of synch
0581:
0582:                factory = null;
0583:                poolName = null;
0584:                initialized = false;
0585:            }
0586:
0587:            /**
0588:             * Gets an object from the pool.  If all the objects in the pool are in use,
0589:             * creates a new object, adds it to the pool, and returns it.  If all
0590:             * objects are in use and the pool is at maximum size, will block or
0591:             * return null.
0592:             * @see #setBlocking
0593:             */
0594:            public Object getObject() {
0595:                return getObject(null);
0596:            }
0597:
0598:            /**
0599:             * Gets an object that fits the specified parameters from the pool.
0600:             * If all the objects in the pool are in use or don't fit, creates
0601:             * a new object, adds it to the pool, and returns it.  If all
0602:             * objects are in use or don't fit and the pool is at maximum size,
0603:             * will block or return null.
0604:             * @see #setBlocking
0605:             */
0606:            public Object getObject(Object parameters) {
0607:                if (objects == null)
0608:                    throw new IllegalStateException(
0609:                            "Tried to use pool before it was Initialized or after it was ShutDown!");
0610:
0611:                Object result = factory.isUniqueRequest();
0612:                if (result != null) // If this is identical to a previous request,
0613:                    return result; // return the same result.  This is the 2.4 total hack to
0614:                //share local connections within a managed tx.
0615:
0616:                try {
0617:                    if (permits.attempt(blockingTimeout)) {
0618:                        ObjectRecord rec = null;
0619:                        synchronized (objects) {
0620:                            for (Iterator it = objects.values().iterator(); it
0621:                                    .hasNext();) {
0622:                                rec = (ObjectRecord) it.next();
0623:                                if (null != rec
0624:                                        && !rec.isInUse()
0625:                                        && factory.checkValidObject(rec
0626:                                                .getObject(), parameters)) {
0627:                                    log.info("Handing out from pool object: "
0628:                                            + rec.getObject());
0629:                                    try {
0630:                                        rec.setInUse(true);
0631:                                    } catch (ConcurrentModificationException e) {
0632:                                        log
0633:                                                .info("Conflict trying to set rec. in use flag:"
0634:                                                        + rec.getObject());
0635:                                        // That's OK, just go on and try another object
0636:                                        continue;//shouldn't happen now.
0637:                                    }
0638:                                    break;
0639:                                }
0640:                                rec = null;//not found
0641:                            }
0642:                        }//synch on objects
0643:
0644:                        if (rec == null) {
0645:                            rec = createNewObject(parameters);
0646:                        } // end of if ()
0647:                        if (rec == null) {
0648:                            throw new RuntimeException(
0649:                                    "Pool is broken, did not find or create an object");
0650:                        } // end of if ()
0651:                        Object ob = rec.getObject();
0652:
0653:                        result = factory.prepareObject(ob);
0654:                        if (result != ob)
0655:                            rec.setClientObject(result);
0656:                        if (result instanceof  PooledObject)
0657:                            ((PooledObject) result).addPoolEventListener(this );
0658:
0659:                        log.debug("Pool " + this  + " gave out object: "
0660:                                + result);
0661:                        return result;
0662:                    }//end of permits
0663:                    else {
0664:                        //we timed out
0665:                        throw new RuntimeException(
0666:                                "No ManagedConnections Available!");
0667:                    } // end of else
0668:                }//try
0669:                catch (RuntimeException e) {
0670:                    throw e;
0671:                } // end of catch
0672:                catch (InterruptedException ie) {
0673:                    log.info("Interrupted while requesting permit!",
0674:                            new Exception("stacktrace"));
0675:                    throw new RuntimeException(
0676:                            "Interrupted while requesting permit!");
0677:                } // end of try-catch
0678:                catch (Exception e) {
0679:                    log.info("problem getting connection from pool", e);
0680:                    throw new RuntimeException(
0681:                            "problem getting connection from pool "
0682:                                    + e.getMessage());
0683:                } // end of catch
0684:            }
0685:
0686:            /**
0687:             * Sets the last used time for an object in the pool that is currently
0688:             * in use.  If the timestamp parameter is not set, this call does nothing.
0689:             * Otherwise, the object is marked as last used at the current time.
0690:             * @throws java.lang.IllegalArgumentException
0691:             *         Occurs when the object is not recognized by the factory or not
0692:             *         in the pool.
0693:             * @throws java.lang.IllegalStateException
0694:             *         Occurs when the object is not currently in use.
0695:             * @see #setTimestampUsed
0696:             */
0697:            public void setLastUsed(Object object) {
0698:                if (!trackLastUsed)
0699:                    return;
0700:                Object ob = null;
0701:                try {
0702:                    ob = factory.translateObject(object);
0703:                } catch (Exception e) {
0704:                    throw new IllegalArgumentException("Pool " + getName()
0705:                            + " does not recognize object for last used time: "
0706:                            + object);
0707:                }
0708:                ObjectRecord rec = ob == null ? null : (ObjectRecord) objects
0709:                        .get(ob);
0710:                if (rec == null)
0711:                    throw new IllegalArgumentException("Pool " + getName()
0712:                            + " does not recognize object for last used time: "
0713:                            + object);
0714:                if (rec.isInUse())
0715:                    rec.setLastUsed();
0716:                else
0717:                    throw new IllegalStateException(
0718:                            "Cannot set last updated time for an object that's not in use!");
0719:            }
0720:
0721:            /**
0722:             * Indicates that an object is no longer valid, and should be removed from
0723:             * the pool entirely.  This should be called before the object is returned
0724:             * to the pool (specifically, before factory.returnObject returns), or else
0725:             * the object may be given out again by the time this is called!  Also, you
0726:             * still need to actually return the object to the pool by calling
0727:             * releaseObject, if you aren't calling this during that process already.
0728:             * @param object The object to invalidate, which must be the exact object
0729:             *               returned by getObject
0730:             */
0731:            public void markObjectAsInvalid(Object object) {
0732:                if (deadObjects == null)
0733:                    throw new IllegalStateException(
0734:                            "Tried to use pool before it was Initialized or after it was ShutDown!");
0735:                deadObjects.add(object); //a synchronized set
0736:
0737:            }
0738:
0739:            /**
0740:             * Returns an object to the pool.  This must be the exact object that was
0741:             * given out by getObject, and it must be returned to the same pool that
0742:             * generated it.  If other clients are blocked waiting on an object, the
0743:             * object may be re-released immediately.
0744:             * @throws java.lang.IllegalArgumentException
0745:             *    Occurs when the object is not in this pool.
0746:             */
0747:            public void releaseObject(Object object) {
0748:
0749:                log.debug("Pool " + this  + " object released: " + object);
0750:
0751:                Object pooled = null;
0752:                try {
0753:                    factory.returnObject(object);//do this first
0754:                    pooled = factory.translateObject(object);
0755:                } catch (Exception e) {
0756:                    return; // We can't release it if the factory can't recognize it
0757:                }
0758:                if (pooled == null) // We can't release it if the factory can't recognize it
0759:                    return;
0760:                boolean removed = false;
0761:                synchronized (objects) {
0762:                    ObjectRecord rec = (ObjectRecord) objects.get(pooled);
0763:                    if (rec == null) // Factory understands it, but we don't
0764:                        throw new IllegalArgumentException("Object " + object
0765:                                + " is not in pool " + poolName + "!");
0766:                    if (!rec.isInUse())
0767:                        return; // Must have been released by GC?
0768:                    if (object instanceof  PooledObject)
0769:                        ((PooledObject) object).removePoolEventListener(this );
0770:                    removed = deadObjects.remove(object);
0771:                    rec.setInUse(false);
0772:                    if (removed) {
0773:                        log.debug("Object was dead: " + object);
0774:                        objects.remove(pooled);
0775:                        rec.close();
0776:                    } // end of if ()
0777:
0778:                }//end of synch on objects
0779:                if (removed) {
0780:                    try {
0781:                        factory.deleteObject(pooled);
0782:                    } catch (Exception e) {
0783:                        log.error("Pool " + this  + " factory ("
0784:                                + factory.getClass().getName()
0785:                                + " delete error: ", e);
0786:                    }
0787:                    fillToMin();
0788:                    /*FIXME --MINSIZE
0789:                      if(objects.size() < minSize)
0790:                      createNewObject(null);
0791:                     */
0792:                }
0793:
0794:                if (removed)
0795:                    log.debug("Pool " + this  + " destroyed object " + object
0796:                            + ".");
0797:                else
0798:                    log.debug("Pool " + this  + " returned object " + object
0799:                            + " to the pool.");
0800:
0801:                permits.release();
0802:                /*
0803:                if(blocking)
0804:                {
0805:                   synchronized(this)
0806:                   {
0807:                      notify();
0808:                   }
0809:                }
0810:                 */
0811:            }
0812:
0813:            private int getUsedCount() {
0814:                int total = 0;
0815:                synchronized (objects) {
0816:                    for (Iterator it = new HashSet(objects.values()).iterator(); it
0817:                            .hasNext();) {
0818:                        ObjectRecord or = (ObjectRecord) it.next();
0819:                        if (or != null && or.isInUse())
0820:                            ++total;
0821:                    }
0822:                }
0823:                return total;
0824:            }
0825:
0826:            /**
0827:             * Returns the pool name and status.
0828:             */
0829:            public String toString() {
0830:                return poolName
0831:                        + " ["
0832:                        + getUsedCount()
0833:                        + "/"
0834:                        + (objects == null ? 0 : objects.size())
0835:                        + "/"
0836:                        + (maxSize == 0 ? "Unlimited" : Integer
0837:                                .toString(maxSize)) + "]";
0838:            }
0839:
0840:            // ---- PoolEventListener Implementation ----
0841:
0842:            /**
0843:             * If the object has been closed, release it.
0844:             */
0845:            public void objectClosed(PoolEvent evt) {
0846:                releaseObject(evt.getSource());
0847:            }
0848:
0849:            /**
0850:             * If the invalidateOnError flag is set, the object will be removed from
0851:             * the pool entirely when the client has finished with it.
0852:             */
0853:            public void objectError(PoolEvent evt) {
0854:                if (invalidateOnError || evt.isCatastrophic())
0855:                    markObjectAsInvalid(evt.getSource());
0856:            }
0857:
0858:            /**
0859:             * If we're tracking the last used times, update the last used time for the
0860:             * specified object.
0861:             */
0862:            public void objectUsed(PoolEvent evt) {
0863:                if (!trackLastUsed)
0864:                    return;
0865:                setLastUsed(evt.getSource());
0866:            }
0867:
0868:            long getNextGCMillis(long now) {
0869:                long t = lastGC + gcIntervalMillis - now;
0870:
0871:                log.debug("getNextGCMillis(): returning " + t);
0872:
0873:                if (!runGC)
0874:                    return Long.MAX_VALUE;
0875:
0876:                return t;
0877:            }
0878:
0879:            // Allow GC if we're within 10% of the desired interval
0880:            boolean isTimeToGC() {
0881:                long now;
0882:                now = System.currentTimeMillis();
0883:
0884:                log.debug("isTimeToGC(): "
0885:                        + (now >= lastGC
0886:                                + Math.round((float) gcIntervalMillis * 0.9f)));
0887:
0888:                return now >= lastGC
0889:                        + Math.round((float) gcIntervalMillis * 0.9f);
0890:
0891:            }
0892:
0893:            void runGCandShrink() {
0894:
0895:                log.debug("runGCandShrink(): runGC = " + runGC
0896:                        + "; idleTimeout = " + idleTimeout);
0897:
0898:                if (runGC || idleTimeout) {
0899:                    HashSet objsCopy;
0900:                    synchronized (objects) {
0901:                        objsCopy = new HashSet(objects.values());
0902:                    }
0903:
0904:                    if (runGC) { // Garbage collection - return any object that's been out too long with no use
0905:                        Iterator it = objsCopy.iterator();
0906:                        while (it.hasNext()) {
0907:                            ObjectRecord rec = (ObjectRecord) it.next();
0908:                            if (rec != null
0909:                                    && rec.isInUse()
0910:                                    && rec.getMillisSinceLastUse() >= gcMinIdleMillis) {
0911:                                releaseObject(rec.getClientObject());
0912:                            }
0913:                        }
0914:                    }
0915:                    if (idleTimeout) { // Shrinking the pool - remove objects from the pool if they have not been used in a long time
0916:                        // Find object eligible for removal
0917:                        HashSet eligible = new HashSet();
0918:                        Iterator it = objsCopy.iterator();
0919:                        while (it.hasNext()) {
0920:                            ObjectRecord rec = (ObjectRecord) it.next();
0921:                            if (rec != null
0922:                                    && !rec.isInUse()
0923:                                    && rec.getMillisSinceLastUse() > idleTimeoutMillis)
0924:                                eligible.add(rec);
0925:                        }
0926:                        // Calculate max number of objects to remove without replacing
0927:                        int max = Math.round(eligible.size()
0928:                                * maxIdleShrinkPercent);
0929:                        if (max == 0 && eligible.size() > 0)
0930:                            max = 1;
0931:                        int count = 0;
0932:                        // Attempt to remove that many objects
0933:                        it = eligible.iterator();
0934:                        while (it.hasNext()) {
0935:                            try {
0936:                                // Delete the object
0937:                                ObjectRecord rec = (ObjectRecord) it.next();
0938:                                if (rec != null) {
0939:                                    rec.setInUse(true); // Don't let someone use it while we destroy it
0940:                                    Object pooled = rec.getObject();
0941:                                    synchronized (objects) {
0942:                                        objects.remove(pooled);
0943:                                    }
0944:                                    //removeObject(pooled);
0945:                                    try {
0946:                                        factory.deleteObject(pooled);
0947:                                    } catch (Exception e) {
0948:                                        log.error("Pool " + this  + " factory ("
0949:                                                + factory.getClass().getName()
0950:                                                + " delete error: ", e);
0951:                                    }
0952:                                    rec.close();
0953:                                    ++count;
0954:                                }
0955:                                fillToMin();
0956:                                /*FIXME --MINSIZE
0957:                                            if(count > max || objects.size() < minSize)
0958:                                               createNewObject(null);
0959:
0960:                                 */
0961:                            } catch (ConcurrentModificationException e) {
0962:                            }
0963:                        }
0964:                    }
0965:                }
0966:                lastGC = System.currentTimeMillis();
0967:            }
0968:
0969:            /**
0970:             * Removes an object from the pool.  Only one thread can add or remove
0971:             * an object at a time.
0972:             */
0973:            /*   private void removeObject(Object pooled)
0974:            {
0975:               synchronized(objects)
0976:               {
0977:                  objects.remove(pooled);
0978:               }
0979:            }
0980:             */
0981:            /**
0982:             * Creates a new Object.
0983:             * @param parameters If <b>true</b>, then the object is locked and
0984:             *          translated by the factory, and the resulting object
0985:             *          returned.  If <b>false</b>, then the object is left in the
0986:             *          pool unlocked.
0987:             */
0988:            private ObjectRecord createNewObject(Object parameters) {
0989:                Object ob = null;
0990:                try {
0991:                    ob = factory.createObject(parameters);
0992:                } catch (Exception ex) {
0993:                    throw new RuntimeException("Could not create connection");
0994:                }
0995:                if (ob != null) { // if factory can create object
0996:                    ObjectRecord rec = new ObjectRecord(ob);
0997:                    synchronized (objects) {
0998:                        objects.put(ob, rec);
0999:                    }
1000:                    return rec;
1001:                } else {
1002:                    throw new RuntimeException("could not create new object!");
1003:                }
1004:            }
1005:
1006:            public void fillToMin() {
1007:                Collection newMCs = new ArrayList();
1008:                try {
1009:                    while (objects.size() < minSize) {
1010:                        newMCs.add(getObject(null));
1011:                    } // end of while ()
1012:                } catch (Exception re) {
1013:                    //Whatever the reason, stop trying to add more!
1014:                } // end of try-catch
1015:                for (Iterator i = newMCs.iterator(); i.hasNext();) {
1016:                    releaseObject(i.next());
1017:                } // end of for ()
1018:
1019:            }
1020:
1021:        }
1022:
1023:        class BeanFactory extends PoolObjectFactory {
1024:
1025:            private Class beanClass;
1026:
1027:            private Logger log = Logger.getLogger(BeanFactory.class);
1028:
1029:            public BeanFactory(Class beanClass) {
1030:                try {
1031:                    beanClass.getConstructor(new Class[0]);
1032:                } catch (NoSuchMethodException e) {
1033:                    throw new IllegalArgumentException(
1034:                            "Bean class doesn't have no-arg constructor!");
1035:                }
1036:                this .beanClass = beanClass;
1037:            }
1038:
1039:            public void poolStarted(ObjectPool pool) {
1040:                super .poolStarted(pool);
1041:            }
1042:
1043:            public Object createObject(Object parameters) {
1044:                try {
1045:                    return beanClass.newInstance();
1046:                } catch (Exception e) {
1047:                    log.error("Unable to create instance of "
1048:                            + beanClass.getName(), e);
1049:                }
1050:                return null;
1051:            }
1052:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.