Source Code Cross Referenced for DBConnectionPool.java in  » J2EE » Expresso » com » jcorporate » expresso » core » db » 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 » J2EE » Expresso » com.jcorporate.expresso.core.db 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* ====================================================================
0002:         * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
0003:         *
0004:         * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
0005:         *
0006:         * Redistribution and use in source and binary forms, with or without
0007:         * modification, are permitted provided that the following conditions
0008:         * are met:
0009:         *
0010:         * 1. Redistributions of source code must retain the above copyright
0011:         *    notice, this list of conditions and the following disclaimer.
0012:         *
0013:         * 2. Redistributions in binary form must reproduce the above copyright
0014:         *    notice, this list of conditions and the following disclaimer in
0015:         *    the documentation and/or other materials provided with the
0016:         *    distribution.
0017:         *
0018:         * 3. The end-user documentation included with the redistribution,
0019:         *    if any, must include the following acknowledgment:
0020:         *       "This product includes software developed by Jcorporate Ltd.
0021:         *        (http://www.jcorporate.com/)."
0022:         *    Alternately, this acknowledgment may appear in the software itself,
0023:         *    if and wherever such third-party acknowledgments normally appear.
0024:         *
0025:         * 4. "Jcorporate" and product names such as "Expresso" must
0026:         *    not be used to endorse or promote products derived from this
0027:         *    software without prior written permission. For written permission,
0028:         *    please contact info@jcorporate.com.
0029:         *
0030:         * 5. Products derived from this software may not be called "Expresso",
0031:         *    or other Jcorporate product names; nor may "Expresso" or other
0032:         *    Jcorporate product names appear in their name, without prior
0033:         *    written permission of Jcorporate Ltd.
0034:         *
0035:         * 6. No product derived from this software may compete in the same
0036:         *    market space, i.e. framework, without prior written permission
0037:         *    of Jcorporate Ltd. For written permission, please contact
0038:         *    partners@jcorporate.com.
0039:         *
0040:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0041:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0042:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0043:         * DISCLAIMED.  IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
0044:         * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0045:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
0046:         * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0047:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0048:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0049:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0050:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0051:         * SUCH DAMAGE.
0052:         * ====================================================================
0053:         *
0054:         * This software consists of voluntary contributions made by many
0055:         * individuals on behalf of the Jcorporate Ltd. Contributions back
0056:         * to the project(s) are encouraged when you make modifications.
0057:         * Please send them to support@jcorporate.com. For more information
0058:         * on Jcorporate Ltd. and its products, please see
0059:         * <http://www.jcorporate.com/>.
0060:         *
0061:         * Portions of this software are based upon other open source
0062:         * products and are subject to their respective licenses.
0063:         */
0064:
0065:        package com.jcorporate.expresso.core.db;
0066:
0067:        import com.jcorporate.expresso.core.dataobjects.PersistenceManager;
0068:        import com.jcorporate.expresso.core.db.config.JDBCConfig;
0069:        import com.jcorporate.expresso.core.db.config.JNDIConfig;
0070:        import com.jcorporate.expresso.core.db.datasource.DSException;
0071:        import com.jcorporate.expresso.core.db.datasource.JndiDataSource;
0072:        import com.jcorporate.expresso.core.db.exception.ConnectionPoolException;
0073:        import com.jcorporate.expresso.core.db.exception.PoolFullException;
0074:        import com.jcorporate.expresso.core.misc.ConfigManager;
0075:        import com.jcorporate.expresso.core.misc.ConfigurationException;
0076:        import com.jcorporate.expresso.core.misc.DateTime;
0077:        import com.jcorporate.expresso.core.misc.StringUtil;
0078:        import com.jcorporate.expresso.kernel.RootContainerInterface;
0079:        import com.jcorporate.expresso.kernel.management.ExpressoRuntimeMap;
0080:        import com.jcorporate.expresso.kernel.util.ClassLocator;
0081:        import com.jcorporate.expresso.kernel.util.LocatorUtils;
0082:        import org.apache.log4j.Logger;
0083:
0084:        import java.util.ArrayList;
0085:        import java.util.Date;
0086:        import java.util.Enumeration;
0087:        import java.util.HashMap;
0088:        import java.util.Iterator;
0089:        import java.util.LinkedList;
0090:        import java.util.List;
0091:        import java.util.Map;
0092:
0093:        /**
0094:         * a generic database connection pooling
0095:         * object.</p>
0096:         * <p>Any object requiring connection to the database can request a connection
0097:         * from the connection pool, which will re-use connections and allocate
0098:         * new connections as required. </p>
0099:         * <p>A connection pool will automatically drop connections that have been idle
0100:         * for more than a certain number of seconds when the pool reaches it's
0101:         * maximum size & a new connection is required. </p>
0102:         * <p>It is the responsibility of the object that requests the connection
0103:         * to release it again as soon as possible.</p>
0104:         *
0105:         * @author Michael Nash
0106:         */
0107:        public class DBConnectionPool extends Thread {
0108:            static private int nextConnectionId = 1;
0109:
0110:            /**
0111:             * The Log4j log.
0112:             */
0113:            private static Logger log = Logger
0114:                    .getLogger(DBConnectionPool.class);
0115:
0116:            /*
0117:             * Does this particular instance of the pool connect to
0118:             * a database which supports transactions?
0119:             */
0120:            private boolean supportsTransactions = false;
0121:
0122:            /**
0123:             * Our hash of db pools connecting to other databases
0124:             */
0125:            static private HashMap otherDBPools = new HashMap();
0126:
0127:            /**
0128:             * Name of this class
0129:             */
0130:            private static final String THIS_CLASS = DBConnectionPool.class
0131:                    .getName();
0132:
0133:            /**
0134:             * How many milliseconds seconds must a connection be idle before it is released?
0135:             */
0136:            private long interval = 30 * 1000;
0137:
0138:            /**
0139:             * Maximum time that a currently unused connection can live before it is recycled.  This
0140:             * is irregardless of past usage.
0141:             */
0142:            private long maxttl = interval * 10;
0143:
0144:            /**
0145:             * The maximum number of retries to attempt to find a connection before
0146:             * we throw an exception
0147:             */
0148:            private static final int GET_CONNECTION_RETRIES = 30;
0149:
0150:            /* parameters that we need to make the connection to the database */
0151:            private String dbDriverType = null;
0152:
0153:            /**
0154:             * Database Driver Class
0155:             */
0156:            private String dbDriver = null;
0157:
0158:            /**
0159:             * URL to the database
0160:             */
0161:            private String dbURL = null;
0162:
0163:            /**
0164:             * Database Connection Format as per the expresso-config.xml
0165:             */
0166:            private String dbConnectFormat = null;
0167:
0168:            /**
0169:             * Database Login Name
0170:             */
0171:            private String dbLogin = null;
0172:
0173:            /**
0174:             * Password to access the database
0175:             */
0176:            private String dbPassword = null;
0177:
0178:            /**
0179:             * Name of this database connection/config key
0180:             */
0181:            private String dbName = "";
0182:
0183:            /**
0184:             * we hold a count of how many times we've served up a connection. When
0185:             * it reaches some maximum, we check the pool for "old" connections &
0186:             * drop 'em
0187:             */
0188:            private int issuedConnectionsCount = 0;
0189:
0190:            /**
0191:             * clean pool every N connections
0192:             */
0193:            private static final int CLEAN_POOL_MAX = 50;
0194:
0195:            /**
0196:             * start with a max of 6 connections
0197:             * as soon as the first connection is made, a setup value is read to give
0198:             * the true maximum
0199:             */
0200:            private int maxPoolSize = 6;
0201:
0202:            /**
0203:             * Flag to indicate if we've been initialized (e.g. given parameters
0204:             * to connect to the database & made the first connection) yet
0205:             */
0206:            private boolean initialized = false;
0207:
0208:            /**
0209:             * A vector of all of the possible wildcard characters
0210:             */
0211:            private ArrayList wildCards = new ArrayList(2);
0212:
0213:            /**
0214:             * Linked list of available connections to use from the connection pool
0215:             */
0216:            protected LinkedList available = new LinkedList();
0217:
0218:            /**
0219:             * Map of connections that are currently is use.
0220:             */
0221:            protected Map inUse = new HashMap(3);
0222:
0223:            /**
0224:             * Object that is used as a lock for both available and isUse lists
0225:             * in a single object.
0226:             */
0227:            protected Object poolLock = new Object();
0228:
0229:            /**
0230:             * object to lock finding current timestamp
0231:             */
0232:            protected Object timestampLock = new Object();
0233:
0234:            /**
0235:             * The query to execute against the database that defines a minimal test
0236:             * query that doesn't cause the target db to do a lot a work.  The purpose
0237:             * of this is to test if the connection is still alive.
0238:             */
0239:            private String testQuery = null;
0240:
0241:            /*
0242:             * SQL keyword that removes duplicate rows int a query - may be specific to this
0243:             * database engine implementation
0244:             */
0245:            private static String uniqueRowKeyword = "DISTINCT";
0246:
0247:            /**
0248:             * Limitation syntax database vendor specific optimisation is disabled
0249:             * <p/>
0250:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0251:             */
0252:            public final static int LIMITATION_DISABLED = 0;
0253:
0254:            /**
0255:             * Insert the limitation syntax after TABLE nomination
0256:             * <code>
0257:             * SELECT {COLUMNS}... FROM {TABLE}
0258:             * <font color="#660066">{limitation-syntax}</font>
0259:             * [ WHERE {where_clause}... ]
0260:             * [ ORDER BY {order_by_clause}... ]
0261:             * </code>
0262:             * <p/>
0263:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0264:             */
0265:            public final static int LIMITATION_AFTER_TABLE = 1;
0266:
0267:            /**
0268:             * Insert the limitation syntax after WHERE key word
0269:             * <code>
0270:             * SELECT {COLUMNS}... FROM {TABLE}
0271:             * [ WHERE {where_clause}... ]
0272:             * AND <font color="#660066">{limitation-syntax}</font>
0273:             * [ ORDER BY {order_by_clause}... ]
0274:             * </code>
0275:             * <p/>
0276:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0277:             */
0278:            public final static int LIMITATION_AFTER_WHERE = 2;
0279:
0280:            /**
0281:             * Insert the limitation syntax after ORDER BY key words
0282:             * <code>
0283:             * SELECT {COLUMNS}... FROM {TABLE}
0284:             * [ WHERE {where_clause}... ]
0285:             * [ ORDER BY {order_by_clause}... ]
0286:             * <font color="#660066">{limitation-syntax}</font>
0287:             * </code>
0288:             * <p/>
0289:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0290:             */
0291:            public final static int LIMITATION_AFTER_ORDER_BY = 3;
0292:
0293:            /**
0294:             * Insert the limitation syntax after TABLE nomination
0295:             * <code>
0296:             * SELECT <font color="#660066">{limitation-syntax}</font> {COLUMNS}... FROM {TABLE}
0297:             * [ WHERE {where_clause}... ]
0298:             * [ ORDER BY {order_by_clause}... ]
0299:             * </code>
0300:             * <p/>
0301:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0302:             *
0303:             * @since Expresso 4.0
0304:             */
0305:            public final static int LIMITATION_AFTER_SELECT = 4;
0306:
0307:            /**
0308:             * Rowset Limitation Optimisation Syntax Position.
0309:             * Specifies a where in the SQL command the limitation string should be
0310:             * inserted.
0311:             * <p/>
0312:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0313:             *
0314:             * @see #LIMITATION_DISABLED
0315:             * @see #LIMITATION_AFTER_TABLE
0316:             * @see #LIMITATION_AFTER_WHERE
0317:             * @see #LIMITATION_AFTER_ORDER_BY
0318:             * @see com.jcorporate.expresso.core.dbobj.DBObject#searchAndRetrieveList()
0319:             * @see com.jcorporate.expresso.core.dbobj.DBObject#getOffsetRecord()
0320:             * @see com.jcorporate.expresso.core.dbobj.DBObject#setOffsetRecord( int )
0321:             * @see com.jcorporate.expresso.core.dbobj.DBObject#setMaxRecords(int))
0322:             */
0323:            protected int limitationPosition = LIMITATION_DISABLED;
0324:
0325:            /**
0326:             * Rowset Limitation Optimisation Syntax String.
0327:             * Specifies a string to add database query to retrieve
0328:             * only a finite number of rows from the <code>ResultSet</code>.
0329:             * <p/>
0330:             * <p>For example for MYSQL the string should be
0331:             * <code>"LIMIT %offset% , %maxrecord%"</code>
0332:             * </p>
0333:             * <p/>
0334:             * <p>For example for ORACLE the string should be
0335:             * <code>"ROWNUM >= %offset% AND ROWNUM <=%endrecord%"</code>
0336:             * </p>
0337:             * <p/>
0338:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0339:             *
0340:             * @see #limitationPosition
0341:             * @see com.jcorporate.expresso.core.dbobj.DBObject#searchAndRetrieveList()
0342:             * @see com.jcorporate.expresso.core.dbobj.DBObject#setOffsetRecord( int )
0343:             * @see com.jcorporate.expresso.core.dbobj.DBObject#setMaxRecords( int )
0344:             */
0345:            protected String limitationSyntax = null;
0346:
0347:            /**
0348:             * Check zero update setting
0349:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
0350:             */
0351:            protected boolean checkZeroUpdate = false;
0352:
0353:            /**
0354:             * Class that performs appropriate escaping in the strings being sent
0355:             * to the partuclar database.
0356:             */
0357:            protected EscapeHandler escapeHandler = null;
0358:
0359:            /**
0360:             * This is a simple tag for when the last time the pool was ever used.  If
0361:             * it has elapsed the timeout time specified in the setup table, then
0362:             * we execute a clean before we try to hand out a connection.
0363:             */
0364:            protected long lastUsed;
0365:
0366:            /**
0367:             * JNDI DataSource Context instance to a DataSOurce Pool used inside
0368:             * Application server or Web Container
0369:             */
0370:            private JndiDataSource jndiDS = null;
0371:
0372:            /**
0373:             * Default Constructor
0374:             */
0375:            public DBConnectionPool() {
0376:                super ();
0377:                lastUsed = System.currentTimeMillis();
0378:            } /* DBConnectionPool() */
0379:
0380:            /**
0381:             * Creates a new database connection.  It just rather blindly does this without
0382:             * regards to database maximums, so it should rarely be used.  Normally
0383:             * it is used internally by createNewConnection().
0384:             *
0385:             * @return DBConnection object
0386:             * @throws DBException upon error
0387:             */
0388:            protected DBConnection buildNewConnection() throws DBException {
0389:                DBConnection oneConnection = null;
0390:                //
0391:                //todo FIXME: Refactor so that DBConnection simply takes a ConfigJdbc
0392:                //bean object and have it self configure itself.
0393:                //
0394:                if (dbDriverType.equalsIgnoreCase("datasource")) {
0395:                    JDBCConfig myJdbc = getJDBCConfig(getDataContext());
0396:                    oneConnection = new DBConnection(myJdbc);
0397:                } else {
0398:                    oneConnection = new DBConnection(dbDriver, dbURL,
0399:                            dbConnectFormat);
0400:                    oneConnection.connect(dbLogin, dbPassword);
0401:                }
0402:                oneConnection.setDataContext(getDataContext());
0403:                oneConnection.setId(nextConnectionId);
0404:                nextConnectionId++;
0405:                oneConnection.setDescription("New Connection");
0406:                return oneConnection;
0407:            }
0408:
0409:            /**
0410:             * Creates a new connection to the data source
0411:             *
0412:             * @return a newly instantiated and populated DBConnection, or null if maxconnections is exceeded,
0413:             *         or null if "available" list has items, so that we should not be creating.
0414:             * @throws DBException upon error
0415:             */
0416:            protected synchronized DBConnection createNewConnection()
0417:                    throws DBException {
0418:                DBConnection oneConnection = null;
0419:
0420:                //
0421:                // check number of existing connections; do not allow more than maxPoolSize
0422:                //
0423:                int totalConnections = 0;
0424:                int avail = 0;
0425:                int inuse = 0;
0426:                boolean firstConnection = false;
0427:                synchronized (poolLock) {
0428:                    avail = available.size();
0429:                    inuse = inUse.size();
0430:                    totalConnections = avail + inuse;
0431:                    firstConnection = totalConnections == 0;
0432:                    //
0433:                    //If there's one that's become available we'd rather try to get
0434:                    //that one instead.
0435:                    //
0436:                    if (avail > 0) {
0437:                        return null;
0438:                    }
0439:
0440:                    if (totalConnections >= this .maxPoolSize) {
0441:                        return null;
0442:                    }
0443:
0444:                } // sync
0445:
0446:                if (log.isInfoEnabled()) {
0447:                    log.info("Creating new connection Total size: "
0448:                            + totalConnections + "In Use Size: " + inuse
0449:                            + " Available: " + avail + " Name: "
0450:                            + this .getDataContext());
0451:                }
0452:
0453:                oneConnection = buildNewConnection();
0454:                oneConnection.setParentPool(this );
0455:
0456:                synchronized (poolLock) {
0457:                    // another thread could have created a connection
0458:                    // in the time between when we last peeked at number of connections, so recalc
0459:                    int totalPools = available.size() + inUse.size();
0460:                    if (totalPools >= this .maxPoolSize) {
0461:                        oneConnection.disconnect();
0462:                        log
0463:                                .warn("Got too many connections... abandoning one:  inUse.size()="
0464:                                        + inUse.size()
0465:                                        + " available.size()="
0466:                                        + available.size());
0467:                        return null;
0468:                    } else {
0469:                        // convention is that a new connection is marked unavailable,
0470:                        // since we do not want anyone else grabbing it out of the pool
0471:                        // before we hand it back to the requesting client
0472:                        oneConnection.setAvailable(false);
0473:
0474:                        inUse.put(new Integer(oneConnection.getId()),
0475:                                oneConnection);
0476:                    }
0477:                }
0478:
0479:                if (log.isDebugEnabled()) {
0480:                    log.debug("New connection " + oneConnection.getId()
0481:                            + " created successfully. " + "Now " + avail
0482:                            + " connections available in pool '"
0483:                            + getDataContext() + "', " + inuse
0484:                            + " currently connected");
0485:                }
0486:
0487:                /* if we've just initialized the connection pool */
0488:                if (firstConnection) {
0489:                    initialized = true;
0490:                    supportsTransactions = oneConnection.supportsTransactions();
0491:
0492:                    JDBCConfig myConfig = getJDBCConfig(getDataContext());
0493:
0494:                    // Try to get the "limitationPosition" setting from Expresso
0495:                    // config properties if possible
0496:                    String limPosStr = StringUtil.notNull(myConfig
0497:                            .getLimitationPosition());
0498:
0499:                    if (limPosStr.length() > 0) {
0500:                        setLimitationPosition(limPosStr);
0501:                    }
0502:
0503:                    // Try to get the "limitationSyntax" setting from Expresso
0504:                    // config properties if possible
0505:                    String limSynStr = StringUtil.notNull(myConfig
0506:                            .getLimitationSyntax());
0507:
0508:                    if (limPosStr.length() > 0) {
0509:                        setLimitationSyntax(limSynStr);
0510:                    }
0511:
0512:                    // Try to get the "unique row keyword" from Expresso
0513:                    // config properties if possible
0514:                    String keyword = StringUtil.notNull(myConfig
0515:                            .getUniqueRowKeyword());
0516:
0517:                    if (keyword.length() < 1) {
0518:                        uniqueRowKeyword = "DISTINCT"; // Default SQL keyword
0519:                    } else {
0520:                        // todo why do we not set uniqueRowKeyword in this case?????  LAH 6/03
0521:                        // uniqueRowKeyword = keyword;
0522:                    }
0523:
0524:                    // Try to get the "check zero update" from Expresso
0525:                    // config properties if possible
0526:                    String zeroUpdate = StringUtil.notNull(myConfig
0527:                            .getCheckZeroUpdate());
0528:
0529:                    if (zeroUpdate.length() > 0) {
0530:                        checkZeroUpdate = myConfig.checkZeroUpdate();
0531:                    }
0532:
0533:                    // Now call setWildCards to see if any user-specific
0534:                    // wildcards where loaded in the properties file.
0535:                    setWildCards();
0536:
0537:                }
0538:                //Added so that limitation syntax is properly set for the connection
0539:                oneConnection.setLimitationPosition(this .limitationPosition);
0540:                oneConnection.setLimitationSyntax(this .limitationSyntax);
0541:                oneConnection.setEscapeHandler(this .escapeHandler);
0542:
0543:                return oneConnection;
0544:            }
0545:
0546:            /**
0547:             * Iterates once through the available connections and cleans them.
0548:             */
0549:            protected void cleanAvailable() throws ConnectionPoolException {
0550:                if (log.isDebugEnabled()) {
0551:                    log
0552:                            .debug("Checking available pool for connections to remove");
0553:                }
0554:
0555:                long startTime = System.currentTimeMillis();
0556:                boolean removedConnections = false;
0557:                synchronized (poolLock) {
0558:
0559:                    // unusual iteration allows for removal of list item during iteration
0560:                    for (int i = 0; i < available.size();) {
0561:                        DBConnection dbc = (DBConnection) available.get(i);
0562:                        //
0563:                        //Check how long it has been since the connection was idle.  If
0564:                        //it has been idle too long, then we need to kill it so we don't
0565:                        //hand out stale connections in the long run.
0566:                        //
0567:                        if (dbc.getCreatedTime() + maxttl < startTime) {
0568:                            try {
0569:                                dbc.disconnect();
0570:                            } catch (Throwable ex) {
0571:                                log.warn("Error disconnecting", ex);
0572:                            }
0573:
0574:                            available.remove(i);
0575:                            removedConnections = true;
0576:                        } else {
0577:                            i++;
0578:                        }
0579:                    }
0580:
0581:                    if (removedConnections) {
0582:                        poolLock.notify();
0583:                    }
0584:                }
0585:
0586:            }
0587:
0588:            /**
0589:             * Clean the connection pool - see if any connections have
0590:             * been idle more than the allowed number of seconds . If so,
0591:             * disconnect & de- allocate them
0592:             *
0593:             * @throws DBException             If an error occurs releasing the stale connection
0594:             * @throws ConnectionPoolException for other errors relating internally
0595:             *                                 to the connectionpool code.
0596:             */
0597:            public void clean() throws ConnectionPoolException, DBException {
0598:
0599:                if (log.isDebugEnabled()) {
0600:                    log.debug("Checking connection pool for stale connections");
0601:                }
0602:
0603:                long now = System.currentTimeMillis();
0604:                long lastTouched = 0;
0605:                DBConnection oneConnection = null;
0606:
0607:                ArrayList connectionsToRelease = null;
0608:
0609:                /* Vector holding the identifiers of the connection objects */
0610:                List connectionsToBeRemoved = new ArrayList();
0611:                /* boolean to check whether the connection objects should be removed*/
0612:
0613:                synchronized (poolLock) {
0614:                    for (Iterator it = inUse.values().iterator(); it.hasNext();) {
0615:                        oneConnection = (DBConnection) it.next();
0616:                        if (log.isDebugEnabled()) {
0617:                            log.debug("Checking '"
0618:                                    + oneConnection.getDescription() + "'");
0619:                        }
0620:
0621:                        lastTouched = oneConnection.getLastTouched();
0622:                        long timeOutTime = lastTouched + interval;
0623:
0624:                        if (now > timeOutTime) {
0625:                            /* it's been too long */
0626:                            if (log.isDebugEnabled()) {
0627:                                log.debug("Closing connection");
0628:                            }
0629:
0630:                            if (!oneConnection.getImmortal()) {
0631:                                if (log.isDebugEnabled()) {
0632:                                    log
0633:                                            .debug("Connection "
0634:                                                    + oneConnection
0635:                                                            .getDescription()
0636:                                                    + " was idle more than "
0637:                                                    + (interval / 1000)
0638:                                                    + " seconds and was returned to the pool. "
0639:                                                    + "Last SQL executed was '"
0640:                                                    + oneConnection.getSQL()
0641:                                                    + "'");
0642:                                }
0643:
0644:                                if (connectionsToRelease == null) {
0645:                                    connectionsToRelease = new ArrayList();
0646:                                }
0647:                                connectionsToRelease.add(oneConnection);
0648:
0649:                            } else {
0650:                                log.warn("Warning: 'Immortal' Connection "
0651:                                        + oneConnection.getDescription()
0652:                                        + " was idle more than "
0653:                                        + (interval / 1000) + " seconds. "
0654:                                        + "Last SQL executed was '"
0655:                                        + oneConnection.getSQL() + "'");
0656:                            }
0657:                        }
0658:
0659:                        /* The block which was here to release the connections has been moved down
0660:                            after the iteration */
0661:
0662:                        /* If the connection is (interval * 3) MINUTES old, then close it */
0663:                        timeOutTime = lastTouched + (interval * 60 * 3);
0664:                        if (now > timeOutTime) {
0665:
0666:                            log
0667:                                    .warn("Connection "
0668:                                            + oneConnection.getDescription()
0669:                                            + " was idle more than "
0670:                                            + (interval / 1000)
0671:                                            + " minutes and was disconnected and removed "
0672:                                            + "from the pool");
0673:
0674:                            /* remove the elements only after iteration
0675:                                This is done to avoid the ConcurrentModificationException */
0676:
0677:                            connectionsToBeRemoved.add(oneConnection);
0678:
0679:                        }
0680:                    } /* for each connection in the pool */
0681:
0682:                    /* Now iterate that vector and remove the connection objects from the hashmap
0683:                            This is done to avoid the ConcurrentModificationException*/
0684:                    for (int i = 0; i < connectionsToBeRemoved.size(); i++) {
0685:                        DBConnection dbconn = (DBConnection) connectionsToBeRemoved
0686:                                .get(i);
0687:                        dbconn.disconnect();
0688:                        dbconn.setAvailable(true);
0689:                        inUse.remove(new Integer(dbconn.getId()));
0690:                    }
0691:
0692:                    /* This is the block which releases the connection and is done after the iteration*/
0693:                    DBConnection oneToRelease = null;
0694:                    if (connectionsToRelease != null) {
0695:                        for (Iterator rl = connectionsToRelease.iterator(); rl
0696:                                .hasNext();) {
0697:
0698:                            oneToRelease = (DBConnection) rl.next();
0699:                            release(oneToRelease);
0700:                            oneToRelease.clear();
0701:                            oneToRelease = null;
0702:                        }
0703:                    }
0704:                } /* End Lock */
0705:            } /* clean() */
0706:
0707:            /**
0708:             * Disconnect all of the current connections. Called when we shut down
0709:             */
0710:            public synchronized void disconnectAll() throws DBException {
0711:                DBConnection oneConnection = null;
0712:
0713:                for (Iterator it = getPoolList().iterator(); it.hasNext();) {
0714:                    oneConnection = (DBConnection) it.next();
0715:
0716:                    if (!oneConnection.isClosed()) {
0717:                        try {
0718:                            oneConnection.disconnect();
0719:                        } catch (DBException de) {
0720:                            log
0721:                                    .error(
0722:                                            "Unable to disconnect from "
0723:                                                    + "database successfully when clearing connection pool",
0724:                                            de);
0725:                        }
0726:                    }
0727:                } /* for each connection in the current pool */
0728:
0729:                synchronized (poolLock) {
0730:                    available = new LinkedList();
0731:                    inUse = new HashMap(3);
0732:                }
0733:            } /* disconnectAll() */
0734:
0735:            /**
0736:             * This allows an exclusive updated to be done to a database. (Such as
0737:             * drop table)  should ensure that no tables are in use when this update
0738:             * is executed.
0739:             *
0740:             * @param theSQL the SQL code to execute.
0741:             */
0742:            public synchronized void executeExclusiveUpdate(String theSQL)
0743:                    throws DBException {
0744:                this .disconnectAll();
0745:
0746:                try {
0747:                    yield();
0748:                    sleep(500); //We've got some sort of timing problem with connections closing
0749:
0750:                    //and being able to execute exclusive.  Maybe this will
0751:                    //help for interbase at least.
0752:                } catch (java.lang.InterruptedException ie) {
0753:                    if (log.isDebugEnabled()) {
0754:                        log.debug("Interrupted while sleeping");
0755:                    }
0756:                }
0757:
0758:                DBConnection dbc = null;
0759:
0760:                try {
0761:                    dbc = this .getConnection();
0762:                    dbc.executeUpdate(theSQL);
0763:                } finally {
0764:                    if (dbc != null) {
0765:                        this .release(dbc);
0766:                    }
0767:                }
0768:            }
0769:
0770:            /**
0771:             * Find a connection that is already in the pool that is available.
0772:             * If there isn't one, return null
0773:             *
0774:             * @return The available connection if one is found, else null
0775:             */
0776:            private DBConnection findExistingConnection() {
0777:                DBConnection oneConnection = null;
0778:
0779:                try {
0780:                    while (available.size() > 0) {
0781:                        synchronized (poolLock) {
0782:                            if (available.size() == 0) {
0783:                                return null;
0784:                            }
0785:                            oneConnection = (DBConnection) available
0786:                                    .removeFirst();
0787:                            oneConnection.setAvailable(false);
0788:
0789:                            /* Check for a dead connection */
0790:                            if (testQuery != null) {
0791:                                try {
0792:                                    oneConnection.execute(testQuery);
0793:                                } catch (DBException de) {
0794:                                    if (log.isDebugEnabled()) {
0795:                                        log
0796:                                                .debug("Test query '"
0797:                                                        + testQuery
0798:                                                        + "' failed:"
0799:                                                        + de.getMessage()
0800:                                                        + ", closing connection & trying again");
0801:                                    }
0802:                                    try {
0803:                                        oneConnection.disconnect();
0804:                                    } catch (Exception e) {
0805:                                        log.error(
0806:                                                "Unable to close connection that failed "
0807:                                                        + "test query", e);
0808:                                    }
0809:
0810:                                    // This was the cause of a bug because it returns a null while we could have
0811:                                    // more available connections. What we have to do is to continue iterating
0812:                                    // and decrease the number of total pools.
0813:                                    continue;
0814:                                }
0815:                            }
0816:
0817:                            if (oneConnection.isClosed()) {
0818:                                if (log.isDebugEnabled()) {
0819:                                    log.debug("Dead connection removed "
0820:                                            + "from pool. Was previously '"
0821:                                            + oneConnection.getDescription()
0822:                                            + "'. Currently "
0823:                                            + available.size()
0824:                                            + " connections available, "
0825:                                            + inUse.size()
0826:                                            + " clients connected");
0827:                                }
0828:                                try {
0829:                                    oneConnection.disconnect();
0830:                                } catch (Exception e) {
0831:                                    //Log, but otherwise ignore the exception
0832:                                    log.warn("Error Disconnecting", e);
0833:                                } finally {
0834:                                    // This was the cause of a bug because it returns a null while we could have
0835:                                    // more available connections. What we have to do is to continue iterating
0836:                                    // and decrease the number of total pools.
0837:                                    oneConnection = null;
0838:                                }
0839:                                continue;
0840:                            }
0841:
0842:                            //
0843:                            //New Logic since Expresso 5.1 ea2... If the connection was created
0844:                            //before the ttl interval, then we discard it and try to
0845:                            //get a new one.
0846:                            //
0847:                            if (oneConnection.getCreatedTime() + this .maxttl < System
0848:                                    .currentTimeMillis()) {
0849:                                if (log.isInfoEnabled()) {
0850:                                    log
0851:                                            .info("Discarding connection.  Timeout since created time reached");
0852:                                }
0853:
0854:                                try {
0855:                                    oneConnection.disconnect();
0856:                                } catch (Exception e) {
0857:                                    //Log, but otherwise ignore the exception
0858:                                    log.warn("Error Disconnecting", e);
0859:                                } finally {
0860:                                    // This was the cause of a bug because it returns a null while we could have
0861:                                    // more available connections. What we have to do is to continue iterating
0862:                                    // and decrease the number of total pools.
0863:                                    oneConnection = null;
0864:                                }
0865:                                continue;
0866:
0867:                            }
0868:
0869:                            /* connection wasn't dead or expired all is OK */
0870:                            if (log.isDebugEnabled()) {
0871:                                log.debug("Available connection "
0872:                                        + oneConnection.getId()
0873:                                        + " found. Was previously '"
0874:                                        + oneConnection.getDescription()
0875:                                        + "'. Currently " + available.size()
0876:                                        + " connections available, "
0877:                                        + inUse.size() + " clients connected");
0878:                            }
0879:
0880:                            inUse.put(new Integer(oneConnection.getId()),
0881:                                    oneConnection);
0882:                        }
0883:
0884:                        return oneConnection;
0885:
0886:                    } /* while */
0887:
0888:                } catch (DBException de) {
0889:                    log.error("Unable to test if connection is closed", de);
0890:                }
0891:
0892:                return null;
0893:            } /* findExistingConnection() */
0894:
0895:            /**
0896:             * Find an available connection in the default connection pool, if any.
0897:             * <p>If none, make a new one if we can.</p>
0898:             * <p>Does not set the new connection's description</p>
0899:             * This method will sleep for "interval" number of seconds if no
0900:             * connections are available and the pool is full. It then tries
0901:             * again to find or allocate a connection before failing.
0902:             *
0903:             * @return DBConnection A database connection ready for use
0904:             * @throws DBException             If there's an error talking with the Database
0905:             * @throws PoolFullException       if we're unable to allocate a new connection because
0906:             *                                 the pool is full and we still haven't gotten a connection
0907:             * @throws ConnectionPoolException for other connection-pool related errors.
0908:             *                                 author	  Yves Henri AMAIZO (Modification)
0909:             *                                 author	  Larry Hamel (Modification)
0910:             */
0911:            public DBConnection getConnection() throws ConnectionPoolException,
0912:                    PoolFullException, DBException {
0913:                if (!isInitialized()) {
0914:                    throw new ConnectionPoolException("Connection pool '"
0915:                            + getDataContext()
0916:                            + "' is not initialized. Can't get connection.");
0917:                }
0918:
0919:                //
0920:                //Parameter check
0921:                //
0922:                if (dbDriver == null) {
0923:                    throw new ConnectionPoolException(
0924:                            "Cannot make new connection - dbDriver is null");
0925:                }
0926:                if (dbURL == null) {
0927:                    throw new ConnectionPoolException(
0928:                            "Cannot make new connection - dbURL is null");
0929:                }
0930:                if (dbConnectFormat == null) {
0931:                    throw new ConnectionPoolException(
0932:                            "Cannot make new connection - dbConnectFormat is null");
0933:                }
0934:
0935:                DBConnection oneConnection = null;
0936:                int connectionTries = 0;
0937:                int numAvail, numInUse;
0938:
0939:                while (connectionTries < GET_CONNECTION_RETRIES) {
0940:                    //
0941:                    //Moved the periodic clean to here.  Will result in more cleans, but
0942:                    //may clearn out some of the locks we're having.
0943:                    //
0944:                    issuedConnectionsCount++;
0945:
0946:                    /* is it time to clean the pool? */
0947:                    if (issuedConnectionsCount >= CLEAN_POOL_MAX) {
0948:                        cleanAvailable();
0949:                        clean();
0950:                        issuedConnectionsCount = 0;
0951:                        //    synchronize since lastused is a long
0952:                        synchronized (timestampLock) {
0953:                            lastUsed = System.currentTimeMillis();
0954:                        }
0955:                    }
0956:                    /**
0957:                     * If the connection pool has been all together idle for more than
0958:                     * the timeout period, we need to attempt a clean anyway, since many
0959:                     * connections may have already timed out.
0960:                     */
0961:                    if (isTimeToClean()) {
0962:                        cleanAvailable();
0963:                        clean();
0964:                        issuedConnectionsCount = 0;
0965:                        //    synchronize since lastused is a long
0966:                        synchronized (timestampLock) {
0967:                            lastUsed = System.currentTimeMillis();
0968:                        }
0969:                    }
0970:
0971:                    synchronized (poolLock) {
0972:                        //
0973:                        //Ok, now try to find an available connection
0974:                        //
0975:                        oneConnection = this .findExistingConnection();
0976:                        if (oneConnection != null) {
0977:                            oneConnection.setDataContext(getDataContext());
0978:                            return oneConnection;
0979:                        }
0980:
0981:                        if (isFull()) {
0982:                            clean();
0983:                            if (isFull()) {
0984:                                //Sleep
0985:                                if (log.isInfoEnabled()) {
0986:                                    log
0987:                                            .info("--------------------------------");
0988:                                    log.info("WARNING: DB Connection Pool '"
0989:                                            + getDataContext() + "' is "
0990:                                            + "full even after clean.");
0991:                                }
0992:
0993:                                if (log.isDebugEnabled()) {
0994:                                    dumpDebugInfo();
0995:                                }
0996:
0997:                                long currentTime = System.currentTimeMillis();
0998:                                //
0999:                                //We wait for the maximum connection timeout divided by
1000:                                //two.  This way we have
1001:                                //
1002:                                long waitInterval = interval / 2;
1003:                                long finaltime = waitInterval + currentTime;
1004:                                try {
1005:                                    while (finaltime > currentTime && isFull()) {
1006:                                        /* Now wait for a number of seconds, retrying again */
1007:                                        poolLock.wait(waitInterval);
1008:
1009:                                        if (System.currentTimeMillis() >= finaltime
1010:                                                && isFull()) {
1011:                                            //
1012:                                            //Give ourselves a last chance to free something up.
1013:                                            //
1014:                                            clean();
1015:                                            if (isFull()) {
1016:                                                log.error("Pool '"
1017:                                                        + getDataContext()
1018:                                                        + "' still full");
1019:                                                //We timed out waiting for connection:
1020:                                                throw new PoolFullException(
1021:                                                        "Cannot allocate "
1022:                                                                + "another database connection. There are already "
1023:                                                                + "too many connections in use."
1024:                                                                + " Please report this problem to the System "
1025:                                                                + "Administrator");
1026:                                            }
1027:
1028:                                        } else {
1029:                                            //
1030:                                            //We got notified.  time to try to find an existing connection.
1031:                                            //
1032:                                            oneConnection = findExistingConnection();
1033:                                        }
1034:
1035:                                        if (oneConnection != null) {
1036:                                            if (log.isDebugEnabled()) {
1037:                                                log
1038:                                                        .debug("Found existing connection after sleep");
1039:                                            }
1040:
1041:                                            oneConnection
1042:                                                    .setDataContext(getDataContext());
1043:                                            return oneConnection;
1044:                                        }
1045:
1046:                                        currentTime = System
1047:                                                .currentTimeMillis();
1048:                                    }
1049:                                } catch (InterruptedException ie) {
1050:                                    throw new ConnectionPoolException(
1051:                                            "Interrupted while waiting for available connection");
1052:                                }
1053:
1054:                            }
1055:                        }
1056:
1057:                        // find sizes under sync
1058:                        numAvail = available.size();
1059:                        numInUse = inUse.size();
1060:                    } /* End Synchronized */
1061:
1062:                    //
1063:                    // no existing conn if we got here,
1064:                    // so if we have room to create a connection, then let's create it!
1065:                    //
1066:                    if (numAvail + numInUse < this .maxPoolSize) {
1067:                        //Create a new connection
1068:                        oneConnection = createNewConnection();
1069:
1070:                        if (oneConnection != null) {
1071:                            return oneConnection;
1072:                        }
1073:                    }
1074:
1075:                    //
1076:                    //OK, this time around, we couldn't create a new connection or
1077:                    //find an existing connection.  This is fine because we're running
1078:                    //a series of 'controlled' race conditions.  So we loop around again
1079:                    //looking for a connection to grab.  first we sleep to reduce CPU
1080:                    //usage for those cases where the system is
1081:                    //
1082:                    if (log.isInfoEnabled()) {
1083:                        log
1084:                                .info("Couldn't find or create a new connection for this iteration.");
1085:                    }
1086:
1087:                    synchronized (this ) {
1088:                        connectionTries++;
1089:                        try {
1090:                            sleep(1);
1091:                        } catch (InterruptedException ex) {
1092:                            log.debug("Interrupted while sleeping", ex);
1093:                        }
1094:                    }
1095:
1096:                } /* end while */
1097:
1098:                throw new PoolFullException(
1099:                        "Unable to get database connection in "
1100:                                + GET_CONNECTION_RETRIES + " attempts");
1101:
1102:            } /* getConnection() */
1103:
1104:            private boolean isTimeToClean() {
1105:                long now = System.currentTimeMillis();
1106:                boolean isTimeToClean = false;
1107:
1108:                //    synchronize since lastused is a long
1109:                synchronized (timestampLock) {
1110:                    isTimeToClean = now > this .lastUsed + this .interval;
1111:                }
1112:                return isTimeToClean;
1113:            }
1114:
1115:            /**
1116:             * Helper function that dumps all the current contents of the inUse
1117:             * connections.
1118:             */
1119:            protected void dumpDebugInfo() {
1120:                //
1121:                //Extensive Debugging Output if needed
1122:                //
1123:                if (log.isDebugEnabled()) {
1124:                    synchronized (poolLock) {
1125:                        int i = 0;
1126:                        log.debug("Current contents:");
1127:                        for (Iterator conns = inUse.values().iterator(); conns
1128:                                .hasNext();) {
1129:                            DBConnection oneConn = (DBConnection) conns.next();
1130:                            i++;
1131:                            Date dt = new Date(oneConn.getLastTouched());
1132:                            try {
1133:                                log.debug("Connection " + i + ":"
1134:                                        + oneConn.getDescription() + ":"
1135:                                        + DateTime.getDateTimeForDB(dt));
1136:                            } catch (DBException ex) {
1137:                                log.error("Error rendering date time object",
1138:                                        ex);
1139:                            }
1140:                        }
1141:
1142:                        log.debug("Waiting " + (interval / 2000)
1143:                                + " seconds for a connection to free up");
1144:                    }
1145:                }
1146:
1147:            }
1148:
1149:            /**
1150:             * Helper function to determine if the pool is full.
1151:             *
1152:             * @return true if the connection pool is full
1153:             */
1154:            protected boolean isFull() {
1155:                int inuse, avail;
1156:                synchronized (poolLock) {
1157:                    inuse = inUse.size();
1158:                    avail = available.size();
1159:                }
1160:                if (log.isDebugEnabled()) {
1161:                    int totalConnections = avail + inuse;
1162:                    log.debug("Available connections: " + avail
1163:                            + " In Use Connections: " + inuse
1164:                            + " totalConnections " + totalConnections);
1165:                }
1166:                return (inuse >= maxPoolSize);
1167:            }
1168:
1169:            /**
1170:             * Get a connection from the pool. If the pool does not have any free
1171:             * connections (and has not reached it's max size), create a new one.
1172:             * <p>This version of getConnection sets the new connections description
1173:             * as well, avoiding a seperate call to setDescription </p>
1174:             *
1175:             * @param connectionDescrip A description of the use of the database
1176:             *                          connection
1177:             * @return DBConnection A database connection ready for use, or null
1178:             *         if no more connections can be allocated
1179:             * @throws DBException If the pool is not initialized or the connection
1180:             *                     cannot be established
1181:             */
1182:            public DBConnection getConnection(String connectionDescrip)
1183:                    throws DBException {
1184:                DBConnection oneConnection = getConnection();
1185:                oneConnection.setDescription(connectionDescrip);
1186:
1187:                if (log.isDebugEnabled()) {
1188:                    log.debug("Connection for '" + connectionDescrip
1189:                            + "' established");
1190:                }
1191:
1192:                return oneConnection;
1193:            } /* getConnection(String) */
1194:
1195:            /**
1196:             * Return the current database name/config key
1197:             *
1198:             * @return The db name
1199:             */
1200:            public String getDBName() {
1201:                return dbName;
1202:            } /* getDBName() */
1203:
1204:            /**
1205:             * Return the current database name/config key
1206:             *
1207:             * @return The db name
1208:             */
1209:            public String getDataContext() {
1210:                return dbName;
1211:            } /* getDBName() */
1212:
1213:            /**
1214:             * Does this database connection support commit/rollback?
1215:             *
1216:             * @param connName the connection name
1217:             * @return true if the db supports transactions
1218:             */
1219:            static public boolean supportsTransactions(String connName)
1220:                    throws DBException {
1221:                DBConnectionPool myPool = getInstance(connName);
1222:
1223:                return myPool.supportsTransactions();
1224:            }
1225:
1226:            /**
1227:             * Does this database connection support commit/rollback?
1228:             *
1229:             * @return true if the db supports transactions
1230:             */
1231:            public boolean supportsTransactions() throws DBException {
1232:                return supportsTransactions;
1233:            }
1234:
1235:            /**
1236:             * Version of getInstance that can only get an already initialized
1237:             * connection pool to an alternate database
1238:             *
1239:             * @return DBConnectionPool The instance of a connection pool
1240:             * @throws DBException If the alternate pool cannot be created,
1241:             *                     for example if there is no connection by the given name
1242:             */
1243:            static synchronized public DBConnectionPool getInstance(
1244:                    String dataContext) throws DBException {
1245:
1246:                synchronized (DBConnectionPool.otherDBPools) {
1247:                    if (dataContext == null || dataContext.length() == 0) {
1248:                        dataContext = DBConnection.DEFAULT_DB_CONTEXT_NAME;
1249:                    }
1250:
1251:                    DBConnectionPool altPool = (DBConnectionPool) otherDBPools
1252:                            .get(dataContext);
1253:
1254:                    if (altPool == null) {
1255:                        DBConnectionPool newPool = new DBConnectionPool();
1256:                        newPool.setDataContext(dataContext);
1257:
1258:                        JDBCConfig myConfig = DBConnectionPool
1259:                                .getJDBCConfig(dataContext);
1260:
1261:                        try {
1262:                            newPool.setParams(myConfig);
1263:                        } catch (DBException de) {
1264:                            throw new ConnectionPoolException(
1265:                                    "Unable to initialize pool for configuration '"
1266:                                            + dataContext + "':"
1267:                                            + de.getMessage(), de);
1268:                        }
1269:
1270:                        otherDBPools.put(dataContext, newPool);
1271:
1272:                        return newPool;
1273:                    }
1274:
1275:                    return altPool;
1276:                }
1277:            } /* getInstance(String) */
1278:
1279:            /**
1280:             * Retrieve a dumb datasource implementation that is compatible with items such
1281:             * as reporting tools, etc.
1282:             * <p>Note that performance of the resulting DataSource may be very slow since
1283:             * the datasource is a dumb connector, and does NOT consider the connection
1284:             * pool (because Expresso, at this time, has no way to register for a java.sql.Connection
1285:             * to be removed from the pool when the API programmer closes it)
1286:             * </p>
1287:             *
1288:             * @param dataContext the data context to retrieve the data source for.
1289:             * @return
1290:             */
1291:            public static synchronized javax.sql.DataSource getDataSource(
1292:                    String dataContext) throws java.sql.SQLException {
1293:                try {
1294:                    return new SimpleDataSource(DBConnectionPool
1295:                            .getInstance(dataContext));
1296:                } catch (DBException ex) {
1297:                    log.error("Error getting database connection pool", ex);
1298:                    throw new java.sql.SQLException(ex.getMessage());
1299:                }
1300:            }
1301:
1302:            /**
1303:             * Return the entire pool of connections as a Vector
1304:             *
1305:             * @return ArrayList An array list containing the DBConnection objects
1306:             * @throws DBException If the pool cannot be returned
1307:             */
1308:            public synchronized ArrayList getPoolList() throws DBException {
1309:                ArrayList al;
1310:                synchronized (poolLock) {
1311:                    al = new ArrayList(available);
1312:                    for (Iterator it = inUse.values().iterator(); it.hasNext();) {
1313:                        al.add(it.next());
1314:                    }
1315:                }
1316:
1317:                return al;
1318:            }
1319:
1320:            public ArrayList getWildCardsList() {
1321:                return new ArrayList(wildCards);
1322:            }
1323:
1324:            /**
1325:             * Is this connection pool initialized, or does it require database
1326:             * parameters?
1327:             *
1328:             * @return true if the DBConnectionPool is initialized
1329:             */
1330:            public boolean isInitialized() {
1331:                return initialized;
1332:            } /* isInitialized() */
1333:
1334:            /**
1335:             * Release the given connection
1336:             * It is the object requesting the connection's responsibility to call
1337:             * this method to release the connection(s) it requested.
1338:             *
1339:             * @param connectionToRelease The DBConnection to be released back to
1340:             *                            the pool.
1341:             */
1342:            public void release(DBConnection connectionToRelease) {
1343:                if (connectionToRelease == null) {
1344:                    return;
1345:                }
1346:                /* We always set a connection that's being returned to the
1347:                 * pool to auto-commit,
1348:                 * so that when it's
1349:                 * used next time it can be assumed to be in autocommit mode
1350:
1351:                 */
1352:                try {
1353:                    if (!connectionToRelease.getAutoCommit()) {
1354:                        connectionToRelease.setAutoCommit(true);
1355:                    }
1356:
1357:                    connectionToRelease.clear();
1358:                } catch (DBException dbe) {
1359:                    if (log.isDebugEnabled()) {
1360:                        log.debug("Error setting auto-commit to true", dbe);
1361:                    }
1362:                    /* ignore the exception - just means that transactions are not handled */
1363:                    /* by this db */
1364:                }
1365:                if (connectionToRelease.isAvailable()) {
1366:                    return;
1367:                }
1368:                if (log.isDebugEnabled()) {
1369:                    log.debug("Releasing connection "
1370:                            + connectionToRelease.getId() + " '"
1371:                            + connectionToRelease.getDescription() + "'");
1372:                }
1373:                synchronized (poolLock) {
1374:                    if (inUse.remove(new Integer(connectionToRelease.getId())) == null) {
1375:                        if (log.isDebugEnabled()) {
1376:                            log.debug("Connection "
1377:                                    + connectionToRelease.getId()
1378:                                    + " was not listed as "
1379:                                    + "in use and could not be released");
1380:                        }
1381:
1382:                        return;
1383:                    }
1384:                    connectionToRelease.setAvailable(true);
1385:                    available.add(connectionToRelease);
1386:                    poolLock.notify();
1387:                }
1388:
1389:                if (log.isDebugEnabled()) {
1390:                    log.debug("Connection " + connectionToRelease.getId()
1391:                            + " '" + connectionToRelease.getDescription()
1392:                            + "' released back to pool. Now " + inUse.size()
1393:                            + " connected");
1394:                }
1395:            } /* release(DBConnection) */
1396:
1397:            /**
1398:             * Useful for querying the potential of the dbconnection pool's status
1399:             *
1400:             * @return maximum number of connections allowed.
1401:             */
1402:            public int getMaxConnections() {
1403:                return maxPoolSize;
1404:            }
1405:
1406:            /**
1407:             * Sets the maximum number of connections for this pool
1408:             *
1409:             * @param newMax The new maximum number of connections
1410:             */
1411:            public synchronized void setMaxConnections(int newMax)
1412:                    throws DBException {
1413:                maxPoolSize = newMax;
1414:            } /* setMaxConnections(int) */
1415:
1416:            /**
1417:             * Set the current database name/config key
1418:             *
1419:             * @param newDBName The new dataContext to set for this connection pool
1420:             */
1421:            protected synchronized void setDBName(String newDBName) {
1422:                if (StringUtil.notNull(newDBName).equals("")) {
1423:                    newDBName = DBConnection.DEFAULT_DB_CONTEXT_NAME;
1424:                }
1425:
1426:                dbName = newDBName;
1427:            } /* setDBName(String) */
1428:
1429:            /**
1430:             * Set the current database name/config key
1431:             *
1432:             * @param newDBName The new dataContext to set for this connection pool
1433:             */
1434:            protected synchronized void setDataContext(String newDBName) {
1435:                if (StringUtil.notNull(newDBName).equals("")) {
1436:                    newDBName = DBConnection.DEFAULT_DB_CONTEXT_NAME;
1437:                }
1438:
1439:                dbName = newDBName;
1440:            } /* setDBName(String) */
1441:
1442:            /**
1443:             * Set the parameters required to make database connections
1444:             * The servlet that gets invoked first passes this info to the connection
1445:             * pool from it's arguments, where they are used to create new connections
1446:             * as required.
1447:             *
1448:             * @param theParams The JDBC Config bean as defined by the system configuration
1449:             * @throws DBException If any parameters are invalid
1450:             * @see com.jcorporate.expresso.core.db.DBConnection
1451:             */
1452:            private synchronized void setParams(JDBCConfig theParams)
1453:                    throws DBException {
1454:                String myName = (THIS_CLASS + "setParams(String, String, String, String, String)");
1455:                dbDriverType = theParams.getDriverType();
1456:                dbDriver = theParams.getDriver();
1457:                dbURL = theParams.getUrl();
1458:                dbConnectFormat = theParams.getConnectFormat();
1459:                dbLogin = theParams.getLogin();
1460:                dbPassword = theParams.getPassword();
1461:
1462:                if (dbDriverType == null) {
1463:                    dbDriverType = ("manager");
1464:                }
1465:
1466:                if (dbDriver == null) {
1467:                    throw new ConnectionPoolException(myName
1468:                            + ":Database driver name cannot be " + "null");
1469:                }
1470:                if (dbURL == null) {
1471:                    throw new ConnectionPoolException(myName
1472:                            + ":Database URL cannot be null");
1473:                }
1474:                if (dbConnectFormat == null) {
1475:                    throw new ConnectionPoolException(myName
1476:                            + ":Database connection format " + "cannot be null");
1477:                }
1478:                if (dbLogin == null) {
1479:                    throw new ConnectionPoolException(myName
1480:                            + ":Database login cannot be null");
1481:                }
1482:                if (dbPassword == null) {
1483:                    throw new ConnectionPoolException(myName
1484:                            + ":Database password cannot be null");
1485:                }
1486:
1487:                try {
1488:                    escapeHandler = (EscapeHandler) ClassLocator.loadClass(
1489:                            theParams.getEscapeHandler()).newInstance();
1490:                } catch (Exception ex) {
1491:                    log.warn("Error instantiating escape handler "
1492:                            + theParams.getEscapeHandler());
1493:                    //Attempt to repair the
1494:                    //the situation by creating default escape handler
1495:                    escapeHandler = new DefaultEscapeHandler();
1496:                }
1497:
1498:                // JNDI DataSource Pool invocation for equivalent to Expresso DBConnectionPool
1499:                // Each DBConnectionPool Has Equivalent to JNDI DataSOurce Pool and
1500:                // and make mappings between each DataSource connection to DBConnection
1501:                // Yves Henri AMAIZO 04/08/2002  02:10
1502:                // @revision 1.12
1503:                if (dbDriverType.equalsIgnoreCase("datasource")) {
1504:                    if (this .getJNDIConfig(theParams) == null) {
1505:                        throw new ConnectionPoolException(myName
1506:                                + "JNDI info configure for datasource");
1507:                    }
1508:
1509:                    try {
1510:                        jndiDS = new JndiDataSource(this 
1511:                                .getJNDIConfig(theParams), theParams.getUrl());
1512:                        jndiDS.setupContext();
1513:                    } catch (DSException dse) {
1514:                        throw new ConnectionPoolException(myName
1515:                                + ":Cannot initialize jndi Context Factory");
1516:                    }
1517:                }
1518:
1519:                initialized = true;
1520:            } /* setParams(String, String, String, String, String) */
1521:
1522:            /**
1523:             * Set a small query to be used to "test" a connection before it's handed out
1524:             *
1525:             * @param newTestQuery The string to execute as a test query
1526:             */
1527:            public synchronized void setTestQuery(String newTestQuery) {
1528:                testQuery = newTestQuery;
1529:            } /* setTestQuery(String) */
1530:
1531:            /**
1532:             * Set the number of seconds that a connection must remain idle
1533:             * before it is considered "timed out" and cleared.  It also sets the
1534:             * maximum time-to-live for the connection to ten times the interval.
1535:             * <p/>
1536:             * although we are setting long values which are , no sync
1537:             *
1538:             * @param newInterval The new interval value in seconds
1539:             */
1540:            public synchronized void setTimeOutInterval(int newInterval)
1541:                    throws DBException {
1542:
1543:                if (newInterval < 1) {
1544:                    String myName = (THIS_CLASS + "setTimeOutInterval(int)");
1545:                    throw new ConnectionPoolException(myName
1546:                            + ":Interval must be greater than 0");
1547:                }
1548:
1549:                interval = (long) newInterval * 1000;
1550:                maxttl = interval * 10;
1551:            } /* setTimeOutInterval(int) */
1552:
1553:            /**
1554:             * set wild cards from config, or default if no config definition exists
1555:             */
1556:            private synchronized void setWildCards() throws DBException {
1557:                boolean propsFound = false;
1558:
1559:                JDBCConfig myConfig = getJDBCConfig(this .getDataContext());
1560:
1561:                for (Enumeration e = myConfig.getWildcards().elements(); e
1562:                        .hasMoreElements();) {
1563:                    propsFound = true;
1564:                    wildCards.add(e.nextElement());
1565:                }
1566:                /* The user can specify database wildcards in the config files
1567:                 *  which will override
1568:                 *  Note: If there is even just one dbWildCard, none of the defaults
1569:                 *  are used. This is because it is potentially harmful to have bogus
1570:                 *  wildchard characters defined (The LIKE operator will
1571:                 *  be used instead of the = operator in the wrong place,
1572:                 *  and you will not get a match).
1573:                 */
1574:                if (!propsFound) {
1575:
1576:                    // we did not get any wildcards loaded from the props file...
1577:                    // load the default wildcards
1578:                    for (Iterator it = getDefaultWildCards().iterator(); it
1579:                            .hasNext();) {
1580:                        wildCards.add(it.next());
1581:                    }
1582:                }
1583:            } /* setWildCards(DBConnection) */
1584:
1585:            /**
1586:             * Close all existing connections & empty the pools
1587:             */
1588:            public synchronized static void reInitialize() throws DBException {
1589:                synchronized (otherDBPools) {
1590:
1591:                    for (Iterator it = otherDBPools.values().iterator(); it
1592:                            .hasNext();) {
1593:                        DBConnectionPool onePool = (DBConnectionPool) it.next();
1594:                        onePool.disconnectAll();
1595:                    }
1596:
1597:                    otherDBPools = new HashMap();
1598:                    System.gc();
1599:                }
1600:            } /* reInitialize() */
1601:
1602:            /**
1603:             * programmatically gets the limitation optimisation insertion position
1604:             * <p/>
1605:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
1606:             *
1607:             * @return an integer code for the limitation syntax position
1608:             * @since Expresso 4.0
1609:             */
1610:            public synchronized int getLimitationPosition() {
1611:                return limitationPosition;
1612:            }
1613:
1614:            /**
1615:             * programmatically sets the limitation optimisation insertion position
1616:             *
1617:             * @param pos the position
1618:             * @throws DBException author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
1619:             * @since Expresso 4.0
1620:             */
1621:            public synchronized void setLimitationPosition(int pos)
1622:                    throws DBException {
1623:                if (pos != LIMITATION_DISABLED && pos != LIMITATION_AFTER_TABLE
1624:                        && pos != LIMITATION_AFTER_WHERE
1625:                        && pos != LIMITATION_AFTER_ORDER_BY
1626:                        && pos != LIMITATION_AFTER_SELECT) {
1627:                    throw new ConnectionPoolException(
1628:                            "illegal argument for limitation optimisation position");
1629:                }
1630:
1631:                this .limitationPosition = pos;
1632:            }
1633:
1634:            /**
1635:             * programmatically sets the limitation optimisation insertion position
1636:             * as readable string.
1637:             *
1638:             * @param pos the position as a String
1639:             *            author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
1640:             * @since Expresso 4.0
1641:             */
1642:            public synchronized void setLimitationPosition(String pos) {
1643:                if (pos.equalsIgnoreCase("LIMITATION_DISABLED")) {
1644:                    this .limitationPosition = LIMITATION_DISABLED;
1645:                } else if (pos.equalsIgnoreCase("LIMITATION_AFTER_TABLE")) {
1646:                    this .limitationPosition = LIMITATION_AFTER_TABLE;
1647:                } else if (pos.equalsIgnoreCase("LIMITATION_AFTER_WHERE")) {
1648:                    this .limitationPosition = LIMITATION_AFTER_WHERE;
1649:                } else if (pos.equalsIgnoreCase("LIMITATION_AFTER_ORDER_BY")) {
1650:                    this .limitationPosition = LIMITATION_AFTER_ORDER_BY;
1651:                } else if (pos.equalsIgnoreCase("LIMITATION_AFTER_SELECT")) {
1652:                    this .limitationPosition = LIMITATION_AFTER_SELECT;
1653:                } else {
1654:                    log
1655:                            .warn("DB Object '"
1656:                                    + getClass().getName()
1657:                                    + "' illegal string argument for limitation optimisation position.");
1658:                }
1659:            }
1660:
1661:            /**
1662:             * Programmatically gets the limitation syntax string
1663:             * <p/>
1664:             * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
1665:             *
1666:             * @return the limitation syntax string
1667:             * @since Expresso 4.0
1668:             */
1669:            public synchronized String getLimitationSyntax() {
1670:                return limitationSyntax;
1671:            }
1672:
1673:            /**
1674:             * Get the current character escape handler for this class.
1675:             *
1676:             * @return The <code>EscapeHandler</code> for this data context
1677:             * @see com.jcorporate.expresso.core.db.EscapeHandler
1678:             * @see com.jcorporate.expresso.core.db.DefaultEscapeHandler
1679:             */
1680:            public synchronized EscapeHandler getEscapeHandler() {
1681:                return this .escapeHandler;
1682:            }
1683:
1684:            /**
1685:             * Programmatically gets the limitation syntax string
1686:             *
1687:             * @param syntax the new syntax
1688:             *               <p/>
1689:             *               author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
1690:             * @since Expresso 4.0
1691:             */
1692:            public synchronized void setLimitationSyntax(String syntax) {
1693:                this .limitationSyntax = syntax;
1694:            }
1695:
1696:            /**
1697:             * <p>Sets the SQL keyword to remove duplicate records
1698:             * from a database query. Most databases use the
1699:             * <code>"DISTINCT" </code> keyword
1700:             * (which is the default), other databases use
1701:             * <code>"UNIQUE"</code>.</p>
1702:             * <p/>
1703:             * <p><b>Source</b>: An old tatty copy of
1704:             * "Introduction to SQL"</p>
1705:             *
1706:             * @param keyword the SQL keyword
1707:             *                author Peter Pilgrim
1708:             * @see #getDistinctRowsetKeyword()
1709:             * @see com.jcorporate.expresso.core.dbobj.DBObject#searchAndRetrieveList()
1710:             * @see com.jcorporate.expresso.core.dbobj.DBObject#searchAndRetrieveList( String )
1711:             * @since Expresso 4.0
1712:             */
1713:            public void setDistinctRowsetKeyword(String keyword) {
1714:                uniqueRowKeyword = keyword;
1715:            } /* setDistinctRowsetKeyword(String) */
1716:
1717:            /**
1718:             * Gets the SQL keyword to remove duplicate records
1719:             * from a database query.
1720:             * <p/>
1721:             * author Peter Pilgrim
1722:             *
1723:             * @return The distinct keyword
1724:             * @see #setDistinctRowsetKeyword( String )
1725:             * @see com.jcorporate.expresso.core.dbobj.DBObject#searchAndRetrieveList()
1726:             * @see com.jcorporate.expresso.core.dbobj.DBObject#setFieldDistinct(java.lang.String, boolean))
1727:             * @since Expresso 4.0
1728:             */
1729:            public String getDistinctRowsetKeyword() {
1730:                return uniqueRowKeyword;
1731:            } /* setDistinctRowsetKeyword() */
1732:
1733:            /**
1734:             * Sets the check zero update boolean flag for this database connection pool
1735:             * author Peter Pilgrim
1736:             *
1737:             * @param newValue true if you want to check for zero updates
1738:             */
1739:            public void setCheckZeroUpdate(boolean newValue) {
1740:                String myName = (THIS_CLASS + "setCheckZeroUpdate() ");
1741:                System.out.println(myName + " newValue:" + newValue);
1742:                this .checkZeroUpdate = newValue;
1743:            }
1744:
1745:            /**
1746:             * Gets the check zero update boolean flag for this database connection pool
1747:             * author Peter Pilgrim
1748:             *
1749:             * @return true if Zero updates are checked for
1750:             * @since Expresso 4.0
1751:             */
1752:            public boolean getCheckZeroUpdate() {
1753:                return this .checkZeroUpdate;
1754:            }
1755:
1756:            /**
1757:             * Function that retrieves the JNDI config.  If this pool is being configured
1758:             * by ConfigManager, then we get the old ConfigJNDI version.  If we are using
1759:             * the new kernel package for configuration, then
1760:             *
1761:             * @param curConfig The current config that we hold.
1762:             * @return a JNDI Configuration object.  May be null if none is configured in
1763:             *         the system.
1764:             * @throws ConnectionPoolException upon error getting configuration
1765:             */
1766:            protected JNDIConfig getJNDIConfig(JDBCConfig curConfig)
1767:                    throws ConnectionPoolException {
1768:                if (curConfig instanceof  com.jcorporate.expresso.core.misc.ConfigJdbc) {
1769:                    return ((com.jcorporate.expresso.core.misc.ConfigJdbc) curConfig)
1770:                            .getMyJndi();
1771:                } else {
1772:                    RootContainerInterface runtime = ExpressoRuntimeMap
1773:                            .getDefaultRuntime();
1774:                    LocatorUtils lc = new LocatorUtils(runtime);
1775:                    JNDIConfig manager = (JNDIConfig) lc.locateComponent(this 
1776:                            .getDataContext()
1777:                            + ".PersistenceManager.JNDIConfig");
1778:                    if (manager == null) {
1779:                        throw new ConnectionPoolException(
1780:                                "Unable to locate PersistenceManager for data context: "
1781:                                        + this .getDataContext());
1782:                    }
1783:                    return null;
1784:                }
1785:            }
1786:
1787:            /**
1788:             * Return the JDBConfig regardless of initialization by kernel package or
1789:             * DefaultInit servlet
1790:             *
1791:             * @param dataContext The name of the data context to retrieve
1792:             * @return The filled out JDBCConfig object.
1793:             * @throws ConnectionPoolException upon error getting configuration
1794:             */
1795:            static protected JDBCConfig getJDBCConfig(String dataContext)
1796:                    throws ConnectionPoolException {
1797:                RootContainerInterface runtime = ExpressoRuntimeMap
1798:                        .getDefaultRuntime();
1799:
1800:                //Check if there is a Default runtime installed or not;
1801:                if (runtime == null) {
1802:                    try {
1803:                        return ConfigManager.getJdbcRequired(dataContext);
1804:                    } catch (ConfigurationException ex) {
1805:                        throw new ConnectionPoolException(
1806:                                "Unable to get Database Configuration Information for context "
1807:                                        + dataContext, ex);
1808:                    }
1809:                } else {
1810:                    LocatorUtils lc = new LocatorUtils(runtime);
1811:                    PersistenceManager manager = (PersistenceManager) lc
1812:                            .locateComponent(dataContext
1813:                                    + ".PersistenceManager");
1814:                    if (manager == null) {
1815:                        throw new ConnectionPoolException(
1816:                                "Unable to locate PersistenceManager component for data context "
1817:                                        + dataContext);
1818:                    }
1819:
1820:                    return manager.getDBConfig().getCurrentConfig();
1821:                }
1822:            }
1823:
1824:            /**
1825:             * Return a list of default wild card characters.
1826:             * This can be used to determine if the search criteria supplied by a
1827:             * user has wild-card characters in it or is an exact match.
1828:             *
1829:             * @return A list of the wild-card characters
1830:             */
1831:            public ArrayList getDefaultWildCards() {
1832:                ArrayList newChars = new ArrayList(4);
1833:                newChars.add(("%"));
1834:                newChars.add(("_"));
1835:                newChars.add(("["));
1836:                newChars.add(("]"));
1837:
1838:                return newChars;
1839:            }
1840:        } /* DBConnectionPool */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.