Source Code Cross Referenced for ConnectionManager.java in  » J2EE » ow2-easybeans » org » ow2 » easybeans » component » jdbcpool » 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 » ow2 easybeans » org.ow2.easybeans.component.jdbcpool 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**
0002:         * EasyBeans
0003:         * Copyright (C) 2006 Bull S.A.S.
0004:         * Contact: easybeans@ow2.org
0005:         *
0006:         * This library is free software; you can redistribute it and/or
0007:         * modify it under the terms of the GNU Lesser General Public
0008:         * License as published by the Free Software Foundation; either
0009:         * version 2.1 of the License, or any later version.
0010:         *
0011:         * This library is distributed in the hope that it will be useful,
0012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014:         * Lesser General Public License for more details.
0015:         *
0016:         * You should have received a copy of the GNU Lesser General Public
0017:         * License along with this library; if not, write to the Free Software
0018:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
0019:         * USA
0020:         *
0021:         * --------------------------------------------------------------------------
0022:         * $Id: ConnectionManager.java 1970 2007-10-16 11:49:25Z benoitf $
0023:         * --------------------------------------------------------------------------
0024:         */package org.ow2.easybeans.component.jdbcpool;
0025:
0026:        import java.io.PrintWriter;
0027:        import java.sql.Connection;
0028:        import java.sql.DriverManager;
0029:        import java.sql.SQLException;
0030:        import java.util.HashMap;
0031:        import java.util.Iterator;
0032:        import java.util.LinkedList;
0033:        import java.util.Map;
0034:        import java.util.TreeSet;
0035:
0036:        import javax.naming.NamingException;
0037:        import javax.naming.Reference;
0038:        import javax.naming.Referenceable;
0039:        import javax.naming.StringRefAddr;
0040:        import javax.sql.ConnectionEvent;
0041:        import javax.sql.ConnectionEventListener;
0042:        import javax.sql.DataSource;
0043:        import javax.sql.XAConnection;
0044:        import javax.sql.XADataSource;
0045:        import javax.transaction.RollbackException;
0046:        import javax.transaction.SystemException;
0047:        import javax.transaction.Transaction;
0048:        import javax.transaction.TransactionManager;
0049:        import javax.transaction.xa.XAResource;
0050:
0051:        import org.ow2.util.log.Log;
0052:        import org.ow2.util.log.LogFactory;
0053:
0054:        /**
0055:         * DataSource implementation. Manage a pool of connections.
0056:         * @author Philippe Durieux
0057:         * @author Florent Benoit
0058:         */
0059:        public class ConnectionManager implements  DataSource, XADataSource,
0060:                Referenceable, ConnectionEventListener {
0061:
0062:            /**
0063:             * Logger.
0064:             */
0065:            private Log logger = LogFactory.getLog(ConnectionManager.class);
0066:
0067:            /**
0068:             * Milliseconds.
0069:             */
0070:            private static final long MILLI = 1000L;
0071:
0072:            /**
0073:             * One minute in milliseconds.
0074:             */
0075:            private static final long ONE_MIN_MILLI = 60L * MILLI;
0076:
0077:            /**
0078:             * Default timeout.
0079:             */
0080:            private static final int DEFAULT_TIMEOUT = 60;
0081:
0082:            /**
0083:             * Default timeout for waiters (10s).
0084:             */
0085:            private static final long WAITER_TIMEOUT = 10 * MILLI;
0086:
0087:            /**
0088:             * Max waiters (by default).
0089:             */
0090:            private static final int DEFAULT_MAX_WAITERS = 1000;
0091:
0092:            /**
0093:             * Default prepare statement.
0094:             */
0095:            private static final int DEFAULT_PSTMT = 12;
0096:
0097:            /**
0098:             * Default sampling period.
0099:             */
0100:            private static final int DEFAULT_SAMPLING = 60;
0101:
0102:            /**
0103:             * List of all datasources.
0104:             */
0105:            private static Map<String, ConnectionManager> cmList = new HashMap<String, ConnectionManager>();
0106:
0107:            /**
0108:             * Transaction manager.
0109:             */
0110:            private TransactionManager tm = null;
0111:
0112:            /**
0113:             * List of JManagedConnection not currently used. This avoids closing and
0114:             * reopening physical connections. We try to keep a minimum of minConPool
0115:             * elements here.
0116:             */
0117:            private TreeSet<JManagedConnection> freeList = new TreeSet<JManagedConnection>();
0118:
0119:            /**
0120:             * Total list of JManagedConnection physically opened.
0121:             */
0122:            private LinkedList<JManagedConnection> mcList = new LinkedList<JManagedConnection>();
0123:
0124:            /**
0125:             * This HashMap gives the JManagedConnection from its transaction Requests
0126:             * with same tx get always the same connection.
0127:             */
0128:            private Map<Transaction, JManagedConnection> tx2mc = new HashMap<Transaction, JManagedConnection>();
0129:
0130:            /**
0131:             * Login timeout (DataSource impl).
0132:             */
0133:            private int loginTimeout = DEFAULT_TIMEOUT;
0134:
0135:            /**
0136:             * PrintWriter used logging (DataSource impl).
0137:             */
0138:            private PrintWriter log = null;
0139:
0140:            /**
0141:             * Constructor for Factory.
0142:             */
0143:            public ConnectionManager() {
0144:
0145:            }
0146:
0147:            /**
0148:             * Gets the ConnectionManager matching the DataSource name.
0149:             * @param dsname datasource name.
0150:             * @return a connection manager impl.
0151:             */
0152:            public static ConnectionManager getConnectionManager(
0153:                    final String dsname) {
0154:                ConnectionManager cm = cmList.get(dsname);
0155:                return cm;
0156:            }
0157:
0158:            /**
0159:             * Datasource name.
0160:             */
0161:            private String dSName = null;
0162:
0163:            /**
0164:             * @return Jndi name of the datasource
0165:             */
0166:            public String getDSName() {
0167:                return dSName;
0168:            }
0169:
0170:            /**
0171:             * @param s Jndi name for the datasource
0172:             */
0173:            public void setDSName(final String s) {
0174:                dSName = s;
0175:                // Add it to the list
0176:                cmList.put(s, this );
0177:            }
0178:
0179:            /**
0180:             * @serial datasource name
0181:             */
0182:            private String dataSourceName;
0183:
0184:            /**
0185:             * Gets the name of the datasource.
0186:             * @return the name of the datasource
0187:             */
0188:            public String getDatasourceName() {
0189:                return dataSourceName;
0190:            }
0191:
0192:            /**
0193:             * Sets the name of the datasource.
0194:             * @param dataSourceName the name of the datasource
0195:             */
0196:            public void setDatasourceName(final String dataSourceName) {
0197:                this .dataSourceName = dataSourceName;
0198:            }
0199:
0200:            /**
0201:             * url for database.
0202:             */
0203:            private String url = null;
0204:
0205:            /**
0206:             * @return the url used to get the connection.
0207:             */
0208:            public String getUrl() {
0209:                return url;
0210:            }
0211:
0212:            /**
0213:             * Sets the url to get connections.
0214:             * @param url the url for JDBC connections.
0215:             */
0216:            public void setUrl(final String url) {
0217:                this .url = url;
0218:            }
0219:
0220:            /**
0221:             * JDBC driver Class.
0222:             */
0223:            private String className = null;
0224:
0225:            /**
0226:             * @return the JDBC driver class name.
0227:             */
0228:            public String getClassName() {
0229:                return className;
0230:            }
0231:
0232:            /**
0233:             * Sets the driver class for JDBC.
0234:             * @param className the name of the JDBC driver
0235:             * @throws ClassNotFoundException if driver is not found
0236:             */
0237:            public void setClassName(final String className)
0238:                    throws ClassNotFoundException {
0239:                this .className = className;
0240:
0241:                // Loads standard JDBC driver and keeps it loaded (via driverClass)
0242:                logger.debug("Load JDBC driver {0}", className);
0243:                try {
0244:                    Class.forName(className);
0245:                } catch (java.lang.ClassNotFoundException e) {
0246:                    logger.error("Cannot load JDBC driver", e);
0247:                    throw e;
0248:                }
0249:            }
0250:
0251:            /**
0252:             * default user.
0253:             */
0254:            private String userName = null;
0255:
0256:            /**
0257:             * @return the user used for getting connections.
0258:             */
0259:            public String getUserName() {
0260:                return userName;
0261:            }
0262:
0263:            /**
0264:             * Sets the user for getting connections.
0265:             * @param userName the name of the user.
0266:             */
0267:            public void setUserName(final String userName) {
0268:                this .userName = userName;
0269:            }
0270:
0271:            /**
0272:             * default passwd.
0273:             */
0274:            private String password = null;
0275:
0276:            /**
0277:             * @return the password used for connections.
0278:             */
0279:            public String getPassword() {
0280:                return password;
0281:            }
0282:
0283:            /**
0284:             * Sets the password used to get connections.
0285:             * @param password the password value.
0286:             */
0287:            public void setPassword(final String password) {
0288:                this .password = password;
0289:            }
0290:
0291:            /**
0292:             * Isolation level for JDBC.
0293:             */
0294:            private int isolationLevel = -1;
0295:
0296:            /**
0297:             * Isolation level (but String format).
0298:             */
0299:            private String isolationStr = null;
0300:
0301:            /**
0302:             * Sets the transaction isolation level of the connections.
0303:             * @param level the level of isolation.
0304:             */
0305:            public void setTransactionIsolation(final String level) {
0306:                if (level.equals("serializable")) {
0307:                    isolationLevel = Connection.TRANSACTION_SERIALIZABLE;
0308:                } else if (level.equals("none")) {
0309:                    isolationLevel = Connection.TRANSACTION_NONE;
0310:                } else if (level.equals("read_committed")) {
0311:                    isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
0312:                } else if (level.equals("read_uncommitted")) {
0313:                    isolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
0314:                } else if (level.equals("repeatable_read")) {
0315:                    isolationLevel = Connection.TRANSACTION_REPEATABLE_READ;
0316:                } else {
0317:                    isolationStr = "default";
0318:                    return;
0319:                }
0320:                isolationStr = level;
0321:            }
0322:
0323:            /**
0324:             * Gets the transaction isolation level.
0325:             * @return transaction isolation level.
0326:             */
0327:            public String getTransactionIsolation() {
0328:                return isolationStr;
0329:            }
0330:
0331:            /**
0332:             * count max waiters during current period.
0333:             */
0334:            private int waiterCount = 0;
0335:
0336:            /**
0337:             * count max waiting time during current period.
0338:             */
0339:            private long waitingTime = 0;
0340:
0341:            /**
0342:             * count max busy connection during current period.
0343:             */
0344:            private int busyMax = 0;
0345:
0346:            /**
0347:             * count min busy connection during current period.
0348:             */
0349:            private int busyMin = 0;
0350:
0351:            /**
0352:             * High Value for no limit for the connection pool.
0353:             */
0354:            private static final int NO_LIMIT = 99999;
0355:
0356:            /**
0357:             * Nb of milliseconds in a day.
0358:             */
0359:            private static final long ONE_DAY = 1440L * 60L * 1000L;
0360:
0361:            /**
0362:             * max number of remove at once in the freelist We avoid removing too much
0363:             * mcs at once for perf reasons.
0364:             */
0365:            private static final int MAX_REMOVE_FREELIST = 10;
0366:
0367:            /**
0368:             * minimum size of the connection pool.
0369:             */
0370:            private int poolMin = 0;
0371:
0372:            /**
0373:             * @return min pool size.
0374:             */
0375:            public int getPoolMin() {
0376:                return poolMin;
0377:            }
0378:
0379:            /**
0380:             * @param min minimum connection pool size to be set.
0381:             */
0382:            public synchronized void setPoolMin(final int min) {
0383:                if (poolMin != min) {
0384:                    poolMin = min;
0385:                    adjust();
0386:                }
0387:            }
0388:
0389:            /**
0390:             * maximum size of the connection pool. default value is "NO LIMIT".
0391:             */
0392:            private int poolMax = NO_LIMIT;
0393:
0394:            /**
0395:             * @return actual max pool size
0396:             */
0397:            public int getPoolMax() {
0398:                return poolMax;
0399:            }
0400:
0401:            /**
0402:             * @param max max pool size. -1 means "no limit".
0403:             */
0404:            public synchronized void setPoolMax(final int max) {
0405:                if (poolMax != max) {
0406:                    if (max < 0 || max > NO_LIMIT) {
0407:                        if (currentWaiters > 0) {
0408:                            notify();
0409:                        }
0410:                        poolMax = NO_LIMIT;
0411:                    } else {
0412:                        if (currentWaiters > 0 && poolMax < max) {
0413:                            notify();
0414:                        }
0415:                        poolMax = max;
0416:                        adjust();
0417:                    }
0418:                }
0419:            }
0420:
0421:            /**
0422:             * Max age of a Connection in milliseconds. When the time is elapsed, the
0423:             * connection will be closed. This avoids keeping connections open too long
0424:             * for nothing.
0425:             */
0426:            private long maxAge = ONE_DAY;
0427:
0428:            /**
0429:             * Same value in mns.
0430:             */
0431:            private int maxAgeMn;
0432:
0433:            /**
0434:             * @return max age for connections (in mm).
0435:             */
0436:            public int getMaxAge() {
0437:                return maxAgeMn;
0438:            }
0439:
0440:            /**
0441:             * @return max age for connections (in millisec).
0442:             */
0443:            public long getMaxAgeMilli() {
0444:                return maxAge;
0445:            }
0446:
0447:            /**
0448:             * @param mn max age of connection in minutes.
0449:             */
0450:            public void setMaxAge(final int mn) {
0451:                maxAgeMn = mn;
0452:                // set times in milliseconds
0453:                maxAge = mn * ONE_MIN_MILLI;
0454:            }
0455:
0456:            /**
0457:             * max open time for a connection, in millisec.
0458:             */
0459:            private long maxOpenTime = ONE_DAY;
0460:
0461:            /**
0462:             * Same value in mn.
0463:             */
0464:            private int maxOpenTimeMn;
0465:
0466:            /**
0467:             * @return max age for connections (in mns).
0468:             */
0469:            public int getMaxOpenTime() {
0470:                return maxOpenTimeMn;
0471:            }
0472:
0473:            /**
0474:             * @return max age for connections (in millisecs).
0475:             */
0476:            public long getMaxOpenTimeMilli() {
0477:                return maxOpenTime;
0478:            }
0479:
0480:            /**
0481:             * @param mn max time of open connection in minutes.
0482:             */
0483:            public void setMaxOpenTime(final int mn) {
0484:                maxOpenTimeMn = mn;
0485:                // set times in milliseconds
0486:                maxOpenTime = mn * ONE_MIN_MILLI;
0487:            }
0488:
0489:            /**
0490:             * max nb of milliseconds to wait for a connection when pool is empty.
0491:             */
0492:            private long waiterTimeout = WAITER_TIMEOUT;
0493:
0494:            /**
0495:             * @return waiter timeout in seconds.
0496:             */
0497:            public int getMaxWaitTime() {
0498:                return (int) (waiterTimeout / MILLI);
0499:            }
0500:
0501:            /**
0502:             * @param sec max time to wait for a connection, in seconds.
0503:             */
0504:            public void setMaxWaitTime(final int sec) {
0505:                waiterTimeout = sec * MILLI;
0506:            }
0507:
0508:            /**
0509:             * max nb of waiters allowed to wait for a Connection.
0510:             */
0511:            private int maxWaiters = DEFAULT_MAX_WAITERS;
0512:
0513:            /**
0514:             * @return max nb of waiters
0515:             */
0516:            public int getMaxWaiters() {
0517:                return maxWaiters;
0518:            }
0519:
0520:            /**
0521:             * @param nb max nb of waiters
0522:             */
0523:            public void setMaxWaiters(final int nb) {
0524:                maxWaiters = nb;
0525:            }
0526:
0527:            /**
0528:             * sampling period in sec.
0529:             */
0530:            private int samplingPeriod = DEFAULT_SAMPLING; // default sampling period
0531:
0532:            /**
0533:             * @return sampling period in sec.
0534:             */
0535:            public int getSamplingPeriod() {
0536:                return samplingPeriod;
0537:            }
0538:
0539:            /**
0540:             * @param sec sampling period in sec.
0541:             */
0542:            public void setSamplingPeriod(final int sec) {
0543:                if (sec > 0) {
0544:                    samplingPeriod = sec;
0545:                }
0546:            }
0547:
0548:            /**
0549:             * Level of checking on connections when got from the pool. this avoids
0550:             * reusing bad connections because too old, for example when database was
0551:             * restarted... 0 = no checking 1 = check that still physically opened. 2 =
0552:             * try a null statement.
0553:             */
0554:            private int checkLevel = 0; // default = 0
0555:
0556:            /**
0557:             * @return connection checking level
0558:             */
0559:            public int getCheckLevel() {
0560:                return checkLevel;
0561:            }
0562:
0563:            /**
0564:             * @param level jdbc connection checking level (0, 1, or 2)
0565:             */
0566:            public void setCheckLevel(final int level) {
0567:                checkLevel = level;
0568:            }
0569:
0570:            /**
0571:             * PreparedStatement pool size per managed connection.
0572:             */
0573:            private int pstmtMax = DEFAULT_PSTMT;
0574:
0575:            /**
0576:             * @return PreparedStatement cache size.
0577:             */
0578:            public int getPstmtMax() {
0579:                return pstmtMax;
0580:            }
0581:
0582:            /**
0583:             * @param nb PreparedStatement cache size.
0584:             */
0585:            public void setPstmtMax(final int nb) {
0586:                pstmtMax = nb;
0587:                // Set the value in each connection.
0588:                for (Iterator i = mcList.iterator(); i.hasNext();) {
0589:                    JManagedConnection mc = (JManagedConnection) i.next();
0590:                    mc.setPstmtMax(pstmtMax);
0591:                }
0592:            }
0593:
0594:            /**
0595:             * test statement used when checkLevel = 2.
0596:             */
0597:            private String testStatement;
0598:
0599:            /**
0600:             * @return test statement used when checkLevel = 2.
0601:             */
0602:            public String getTestStatement() {
0603:                return testStatement;
0604:            }
0605:
0606:            /**
0607:             * @param s test statement
0608:             */
0609:            public void setTestStatement(final String s) {
0610:                testStatement = s;
0611:            }
0612:
0613:            /**
0614:             * Configure the Connection pool. Called by the Container at init.
0615:             * Configuration can be set in datasource.properties files.
0616:             * @param connchecklevel JDBC connection checking level
0617:             * @param connmaxage JDBC connection maximum age
0618:             * @param maxopentime JDBC connection maximum open time
0619:             * @param connteststmt SQL query for test statement
0620:             * @param pstmtmax prepare statement pool size per managed connection
0621:             * @param minconpool Min size for the connection pool
0622:             * @param maxconpool Max size for the connection pool
0623:             * @param maxwaittime Max time to wait for a connection (in seconds)
0624:             * @param maxwaiters Max nb of waiters for a connection
0625:             * @param samplingperiod sampling period in sec.
0626:             */
0627:            @SuppressWarnings("boxing")
0628:            public void poolConfigure(final String connchecklevel,
0629:                    final String connmaxage, final String maxopentime,
0630:                    final String connteststmt, final String pstmtmax,
0631:                    final String minconpool, final String maxconpool,
0632:                    final String maxwaittime, final String maxwaiters,
0633:                    final String samplingperiod) {
0634:
0635:                // Configure pool
0636:                setCheckLevel((new Integer(connchecklevel)).intValue());
0637:                // set con max age BEFORE min/max pool size.
0638:                setMaxAge((new Integer(connmaxage)).intValue());
0639:                setMaxOpenTime((new Integer(maxopentime)).intValue());
0640:                setTestStatement(connteststmt);
0641:                setPstmtMax((new Integer(pstmtmax)).intValue());
0642:                setPoolMin((new Integer(minconpool)).intValue());
0643:                setPoolMax((new Integer(maxconpool)).intValue());
0644:                setMaxWaitTime((new Integer(maxwaittime)).intValue());
0645:                setMaxWaiters((new Integer(maxwaiters)).intValue());
0646:                setSamplingPeriod((new Integer(samplingperiod)).intValue());
0647:                if (logger.isDebugEnabled()) {
0648:                    logger.debug("ConnectionManager configured with:");
0649:                    logger
0650:                            .debug("   jdbcConnCheckLevel  = {0}",
0651:                                    connchecklevel);
0652:                    logger.debug("   jdbcConnMaxAge      = {0}", connmaxage);
0653:                    logger.debug("   jdbcMaxOpenTime     = {0}", maxopentime);
0654:                    logger.debug("   jdbcTestStmt        = {0}", connteststmt);
0655:                    logger.debug("   jdbcPstmtMax        = {0}", pstmtmax);
0656:                    logger.debug("   minConPool          = {0}", getPoolMin());
0657:                    logger.debug("   maxConPool          = {0}", getPoolMax());
0658:                    logger.debug("   maxWaitTime         = {0}",
0659:                            getMaxWaitTime());
0660:                    logger.debug("   maxWaiters          = {0}",
0661:                            getMaxWaiters());
0662:                    logger.debug("   samplingPeriod      = {0}",
0663:                            getSamplingPeriod());
0664:                }
0665:            }
0666:
0667:            /**
0668:             * maximum nb of busy connections in last sampling period.
0669:             */
0670:            private int busyMaxRecent = 0;
0671:
0672:            /**
0673:             * @return maximum nb of busy connections in last sampling period.
0674:             */
0675:            public int getBusyMaxRecent() {
0676:                return busyMaxRecent;
0677:            }
0678:
0679:            /**
0680:             * minimum nb of busy connections in last sampling period.
0681:             */
0682:            private int busyMinRecent = 0;
0683:
0684:            /**
0685:             * @return minimum nb of busy connections in last sampling period.
0686:             */
0687:            public int getBusyMinRecent() {
0688:                return busyMinRecent;
0689:            }
0690:
0691:            /**
0692:             * nb of threads waiting for a Connection.
0693:             */
0694:            private int currentWaiters = 0;
0695:
0696:            /**
0697:             * @return current number of connection waiters.
0698:             */
0699:            public int getCurrentWaiters() {
0700:                return currentWaiters;
0701:            }
0702:
0703:            /**
0704:             * total number of opened physical connections since the datasource
0705:             * creation.
0706:             */
0707:            private int openedCount = 0;
0708:
0709:            /**
0710:             * @return int number of physical jdbc connection opened.
0711:             */
0712:            public int getOpenedCount() {
0713:                return openedCount;
0714:            }
0715:
0716:            /**
0717:             * total nb of physical connection failures.
0718:             */
0719:            private int connectionFailures = 0;
0720:
0721:            /**
0722:             * @return int number of xa connection failures on open.
0723:             */
0724:            public int getConnectionFailures() {
0725:                return connectionFailures;
0726:            }
0727:
0728:            /**
0729:             * total nb of connection leaks. A connection leak occurs when the caller
0730:             * never issues a close method on the connection.
0731:             */
0732:            private int connectionLeaks = 0;
0733:
0734:            /**
0735:             * @return int number of connection leaks.
0736:             */
0737:            public int getConnectionLeaks() {
0738:                return connectionLeaks;
0739:            }
0740:
0741:            /**
0742:             * total number of opened connections since the datasource creation.
0743:             */
0744:            private int servedOpen = 0;
0745:
0746:            /**
0747:             * @return int number of xa connection served.
0748:             */
0749:            public int getServedOpen() {
0750:                return servedOpen;
0751:            }
0752:
0753:            /**
0754:             * total nb of open connection failures because waiter overflow.
0755:             */
0756:            private int rejectedFull = 0;
0757:
0758:            /**
0759:             * @return int number of open calls that were rejected due to waiter
0760:             *         overflow.
0761:             */
0762:            public int getRejectedFull() {
0763:                return rejectedFull;
0764:            }
0765:
0766:            /**
0767:             * total nb of open connection failures because timeout.
0768:             */
0769:            private int rejectedTimeout = 0;
0770:
0771:            /**
0772:             * @return int number of open calls that were rejected by timeout.
0773:             */
0774:            public int getRejectedTimeout() {
0775:                return rejectedTimeout;
0776:            }
0777:
0778:            /**
0779:             * total nb of open connection failures for any other reason.
0780:             */
0781:            private int rejectedOther = 0;
0782:
0783:            /**
0784:             * @return int number of open calls that were rejected.
0785:             */
0786:            public int getRejectedOther() {
0787:                return rejectedOther;
0788:            }
0789:
0790:            /**
0791:             * @return int number of open calls that were rejected.
0792:             */
0793:            public int getRejectedOpen() {
0794:                return rejectedFull + rejectedTimeout + rejectedOther;
0795:            }
0796:
0797:            /**
0798:             * maximum nb of waiters since datasource creation.
0799:             */
0800:            private int waitersHigh = 0;
0801:
0802:            /**
0803:             * @return maximum nb of waiters since the datasource creation.
0804:             */
0805:            public int getWaitersHigh() {
0806:                return waitersHigh;
0807:            }
0808:
0809:            /**
0810:             * maximum nb of waiters in last sampling period.
0811:             */
0812:            private int waitersHighRecent = 0;
0813:
0814:            /**
0815:             * @return maximum nb of waiters in last sampling period.
0816:             */
0817:            public int getWaitersHighRecent() {
0818:                return waitersHighRecent;
0819:            }
0820:
0821:            /**
0822:             * total nb of waiters since datasource creation.
0823:             */
0824:            private int totalWaiterCount = 0;
0825:
0826:            /**
0827:             * @return total nb of waiters since the datasource creation.
0828:             */
0829:            public int getWaiterCount() {
0830:                return totalWaiterCount;
0831:            }
0832:
0833:            /**
0834:             * total waiting time in milliseconds.
0835:             */
0836:            private long totalWaitingTime = 0;
0837:
0838:            /**
0839:             * @return total waiting time since the datasource creation.
0840:             */
0841:            public long getWaitingTime() {
0842:                return totalWaitingTime;
0843:            }
0844:
0845:            /**
0846:             * max waiting time in milliseconds.
0847:             */
0848:            private long waitingHigh = 0;
0849:
0850:            /**
0851:             * @return max waiting time since the datasource creation.
0852:             */
0853:            public long getWaitingHigh() {
0854:                return waitingHigh;
0855:            }
0856:
0857:            /**
0858:             * max waiting time in milliseconds in last sampling period.
0859:             */
0860:            private long waitingHighRecent = 0;
0861:
0862:            /**
0863:             * @return max waiting time in last sampling period.
0864:             */
0865:            public long getWaitingHighRecent() {
0866:                return waitingHighRecent;
0867:            }
0868:
0869:            /**
0870:             * {@inheritDoc}
0871:             */
0872:            public int getLoginTimeout() throws SQLException {
0873:                return loginTimeout;
0874:            }
0875:
0876:            /**
0877:             * {@inheritDoc}
0878:             */
0879:            public void setLoginTimeout(final int seconds) throws SQLException {
0880:                loginTimeout = seconds;
0881:            }
0882:
0883:            /**
0884:             * {@inheritDoc}
0885:             */
0886:            public PrintWriter getLogWriter() throws SQLException {
0887:                return log;
0888:            }
0889:
0890:            /**
0891:             * {@inheritDoc}
0892:             */
0893:            public void setLogWriter(final PrintWriter out) throws SQLException {
0894:                log = out;
0895:            }
0896:
0897:            /**
0898:             * {@inheritDoc}
0899:             */
0900:            public Connection getConnection() throws SQLException {
0901:                return getConnection(userName, password);
0902:            }
0903:
0904:            /**
0905:             * Attempts to establish a connection with the data source that this
0906:             * DataSource object represents. - comes from the javax.sql.DataSource
0907:             * interface
0908:             * @param username - the database user on whose behalf the connection is
0909:             *        being made
0910:             * @param password - the user's password
0911:             * @return a connection to the data source
0912:             * @throws SQLException - if a database access error occurs
0913:             */
0914:            public Connection getConnection(final String username,
0915:                    final String password) throws SQLException {
0916:                JManagedConnection mc = null;
0917:
0918:                // Get the current Transaction
0919:                Transaction tx = null;
0920:                try {
0921:                    tx = tm.getTransaction();
0922:                } catch (NullPointerException n) {
0923:                    // current is null: we are not in EasyBeans Server.
0924:                    logger
0925:                            .error("ConnectionManager: should not be used outside a EasyBeans Server");
0926:                } catch (SystemException e) {
0927:                    logger.error("ConnectionManager: getTransaction failed", e);
0928:                }
0929:                logger.debug("Tx = {0}", tx);
0930:
0931:                // Get a JManagedConnection in the pool for this user
0932:                mc = openConnection(username, tx);
0933:                Connection ret = mc.getConnection();
0934:
0935:                // Enlist XAResource if we are actually in a transaction
0936:                if (tx != null) {
0937:                    if (mc.getOpenCount() == 1) { // Only if first/only thread
0938:                        try {
0939:                            logger.debug("enlist XAResource on {0}", tx);
0940:                            tx.enlistResource(mc.getXAResource());
0941:                            ret.setAutoCommit(false);
0942:                        } catch (RollbackException e) {
0943:                            // Although tx has been marked to be rolled back,
0944:                            // XAResource has been correctly enlisted.
0945:                            logger
0946:                                    .warn(
0947:                                            "XAResource enlisted, but tx is marked rollback",
0948:                                            e);
0949:                        } catch (IllegalStateException e) {
0950:                            // In case tx is committed, no need to register resource!
0951:                            ret.setAutoCommit(true);
0952:                        } catch (Exception e) {
0953:                            logger.error("Cannot enlist XAResource", e);
0954:                            logger
0955:                                    .error("Connection will not be enlisted in a transaction");
0956:                            // should return connection in the pool XXX
0957:                            throw new SQLException("Cannot enlist XAResource");
0958:                        }
0959:                    }
0960:                } else {
0961:                    ret.setAutoCommit(true); // in case we do not start a Tx
0962:                }
0963:
0964:                // return a Connection object
0965:                return ret;
0966:            }
0967:
0968:            /**
0969:             * Attempts to establish a physical database connection that can be
0970:             * used in a distributed transaction.
0971:             *
0972:             * @return  an <code>XAConnection</code> object, which represents a
0973:             *          physical connection to a data source, that can be used in
0974:             *          a distributed transaction
0975:             * @exception SQLException if a database access error occurs
0976:             */
0977:            public XAConnection getXAConnection() throws SQLException {
0978:                return getXAConnection(userName, password);
0979:            }
0980:
0981:            /**
0982:             * Attempts to establish a physical database connection, using the given
0983:             * user name and password. The connection that is returned is one that can
0984:             * be used in a distributed transaction - comes from the
0985:             * javax.sql.XADataSource interface
0986:             * @param user - the database user on whose behalf the connection is being
0987:             *        made
0988:             * @param passwd - the user's password
0989:             * @return an XAConnection object, which represents a physical connection to
0990:             *         a data source, that can be used in a distributed transaction
0991:             * @throws SQLException - if a database access error occurs
0992:             */
0993:            @SuppressWarnings("boxing")
0994:            public XAConnection getXAConnection(final String user,
0995:                    final String passwd) throws SQLException {
0996:                // Create the actual connection in the std driver
0997:                Connection conn = null;
0998:                try {
0999:                    if (user.length() == 0) {
1000:                        conn = DriverManager.getConnection(url);
1001:                        logger.debug("    * New Connection on {0}", url);
1002:                    } else {
1003:                        // Accept password of zero length.
1004:                        conn = DriverManager.getConnection(url, user, passwd);
1005:                        logger.debug(
1006:                                "    * New Connection on {0} for user {1}",
1007:                                url, user);
1008:                    }
1009:                } catch (SQLException e) {
1010:                    logger.error("Could not get Connection on {0}", url, e);
1011:                    throw new SQLException("Could not get Connection on url : "
1012:                            + url + " for user : " + user + " inner exception"
1013:                            + e.getMessage());
1014:                }
1015:
1016:                // Attempt to set the transaction isolation level
1017:                // Depending on the underlaying database, this may not succeed.
1018:                if (isolationLevel != -1) {
1019:                    try {
1020:                        logger.debug("set transaction isolation to {0}",
1021:                                isolationLevel);
1022:                        conn.setTransactionIsolation(isolationLevel);
1023:                    } catch (SQLException e) {
1024:                        String ilstr = "?";
1025:                        switch (isolationLevel) {
1026:                        case Connection.TRANSACTION_SERIALIZABLE:
1027:                            ilstr = "SERIALIZABLE";
1028:                            break;
1029:                        case Connection.TRANSACTION_NONE:
1030:                            ilstr = "NONE";
1031:                            break;
1032:                        case Connection.TRANSACTION_READ_COMMITTED:
1033:                            ilstr = "READ_COMMITTED";
1034:                            break;
1035:                        case Connection.TRANSACTION_READ_UNCOMMITTED:
1036:                            ilstr = "READ_UNCOMMITTED";
1037:                            break;
1038:                        case Connection.TRANSACTION_REPEATABLE_READ:
1039:                            ilstr = "REPEATABLE_READ";
1040:                            break;
1041:                        default:
1042:                            throw new SQLException("Invalid isolation level '"
1043:                                    + ilstr + "'.");
1044:                        }
1045:                        logger
1046:                                .error(
1047:                                        "Cannot set transaction isolation to {0} for this DataSource url {1}",
1048:                                        ilstr, url, e);
1049:                        isolationLevel = -1;
1050:                    }
1051:                }
1052:
1053:                // Create the JManagedConnection object
1054:                JManagedConnection mc = new JManagedConnection(conn, this );
1055:
1056:                // return the XAConnection
1057:                return mc;
1058:            }
1059:
1060:            // -----------------------------------------------------------------
1061:            // Referenceable Implementation
1062:            // -----------------------------------------------------------------
1063:
1064:            /**
1065:             * Retrieves the Reference of this object. Used at binding time by JNDI to
1066:             * build a reference on this object.
1067:             * @return The non-null Reference of this object.
1068:             * @exception NamingException If a naming exception was encountered while
1069:             *            retrieving the reference.
1070:             */
1071:            public Reference getReference() throws NamingException {
1072:
1073:                Reference ref = new Reference(this .getClass().getName(),
1074:                        DataSourceFactory.class.getName(), null);
1075:                // These values are used by ObjectFactory (see DataSourceFactory.java)
1076:                ref.add(new StringRefAddr("datasource.name", getDSName()));
1077:                ref.add(new StringRefAddr("datasource.url", getUrl()));
1078:                ref.add(new StringRefAddr("datasource.classname",
1079:                        getClassName()));
1080:                ref
1081:                        .add(new StringRefAddr("datasource.username",
1082:                                getUserName()));
1083:                ref
1084:                        .add(new StringRefAddr("datasource.password",
1085:                                getPassword()));
1086:                ref.add(new StringRefAddr("datasource.isolationlevel",
1087:                        getTransactionIsolation()));
1088:                Integer checklevel = new Integer(getCheckLevel());
1089:                ref.add(new StringRefAddr("connchecklevel", checklevel
1090:                        .toString()));
1091:                Integer maxage = new Integer(getMaxAge());
1092:                ref.add(new StringRefAddr("connmaxage", maxage.toString()));
1093:                Integer maxopentime = new Integer(getMaxOpenTime());
1094:                ref
1095:                        .add(new StringRefAddr("maxopentime", maxopentime
1096:                                .toString()));
1097:                ref.add(new StringRefAddr("connteststmt", getTestStatement()));
1098:                Integer pstmtmax = new Integer(getPstmtMax());
1099:                ref.add(new StringRefAddr("pstmtmax", pstmtmax.toString()));
1100:                Integer minpool = new Integer(getPoolMin());
1101:                ref.add(new StringRefAddr("minconpool", minpool.toString()));
1102:                Integer maxpool = new Integer(getPoolMax());
1103:                ref.add(new StringRefAddr("maxconpool", maxpool.toString()));
1104:                Integer maxwaittime = new Integer(getMaxWaitTime());
1105:                ref
1106:                        .add(new StringRefAddr("maxwaittime", maxwaittime
1107:                                .toString()));
1108:                Integer maxwaiters = new Integer(getMaxWaiters());
1109:                ref.add(new StringRefAddr("maxwaiters", maxwaiters.toString()));
1110:                Integer samplingperiod = new Integer(getSamplingPeriod());
1111:                ref.add(new StringRefAddr("samplingperiod", samplingperiod
1112:                        .toString()));
1113:                return ref;
1114:            }
1115:
1116:            /**
1117:             * Notifies this <code>ConnectionEventListener</code> that
1118:             * the application has called the method <code>close</code> on its
1119:             * representation of a pooled connection.
1120:             *
1121:             * @param event an event object describing the source of
1122:             * the event
1123:             */
1124:            public void connectionClosed(final ConnectionEvent event) {
1125:                JManagedConnection mc = (JManagedConnection) event.getSource();
1126:                closeConnection(mc, XAResource.TMSUCCESS);
1127:            }
1128:
1129:            /**
1130:             * Notifies this <code>ConnectionEventListener</code> that
1131:             * a fatal error has occurred and the pooled connection can
1132:             * no longer be used.  The driver makes this notification just
1133:             * before it throws the application the <code>SQLException</code>
1134:             * contained in the given <code>ConnectionEvent</code> object.
1135:             *
1136:             * @param event an event object describing the source of
1137:             * the event and containing the <code>SQLException</code> that the
1138:             * driver is about to throw
1139:             */
1140:            @SuppressWarnings("boxing")
1141:            public void connectionErrorOccurred(final ConnectionEvent event) {
1142:
1143:                JManagedConnection mc = (JManagedConnection) event.getSource();
1144:                logger.debug("mc= {0}", mc.getIdentifier());
1145:
1146:                // remove it from the list of open connections for this thread
1147:                // only if it was opened outside a tx.
1148:                closeConnection(mc, XAResource.TMFAIL);
1149:            }
1150:
1151:            /**
1152:             * @return int number of xa connection
1153:             */
1154:            public int getCurrentOpened() {
1155:                return mcList.size();
1156:            }
1157:
1158:            /**
1159:             * @return int number of busy xa connection.
1160:             */
1161:            public int getCurrentBusy() {
1162:                return mcList.size() - freeList.size();
1163:            }
1164:
1165:            /**
1166:             * compute current min/max busyConnections.
1167:             */
1168:            public void recomputeBusy() {
1169:                int busy = getCurrentBusy();
1170:                if (busyMax < busy) {
1171:                    busyMax = busy;
1172:                }
1173:                if (busyMin > busy) {
1174:                    busyMin = busy;
1175:                }
1176:            }
1177:
1178:            /**
1179:             * @return int number of xa connection reserved for tx.
1180:             */
1181:            public int getCurrentInTx() {
1182:                return tx2mc.size();
1183:            }
1184:
1185:            /**
1186:             * make samples with some monitoring values.
1187:             */
1188:            public synchronized void sampling() {
1189:                waitingHighRecent = waitingTime;
1190:                if (waitingHigh < waitingTime) {
1191:                    waitingHigh = waitingTime;
1192:                }
1193:                waitingTime = 0;
1194:
1195:                waitersHighRecent = waiterCount;
1196:                if (waitersHigh < waiterCount) {
1197:                    waitersHigh = waiterCount;
1198:                }
1199:                waiterCount = 0;
1200:
1201:                busyMaxRecent = busyMax;
1202:                busyMax = getCurrentBusy();
1203:                busyMinRecent = busyMin;
1204:                busyMin = getCurrentBusy();
1205:            }
1206:
1207:            /**
1208:             * Adjust the pool size, according to poolMax and poolMin values. Also
1209:             * remove old connections in the freeList.
1210:             */
1211:            @SuppressWarnings("boxing")
1212:            public synchronized void adjust() {
1213:                logger.debug(dSName);
1214:
1215:                // Remove max aged elements in freelist
1216:                // - Not more than MAX_REMOVE_FREELIST
1217:                // - Don't reduce pool size less than poolMin
1218:                int count = mcList.size() - poolMin;
1219:                // In case count is null, a new connection will be
1220:                // recreated just after
1221:                if (count >= 0) {
1222:                    if (count > MAX_REMOVE_FREELIST) {
1223:                        count = MAX_REMOVE_FREELIST;
1224:                    }
1225:                    for (Iterator i = freeList.iterator(); i.hasNext();) {
1226:                        JManagedConnection mc = (JManagedConnection) i.next();
1227:                        if (mc.isAged()) {
1228:                            logger.debug("remove a timed out connection");
1229:                            i.remove();
1230:                            destroyItem(mc);
1231:                            count--;
1232:                            if (count <= 0) {
1233:                                break;
1234:                            }
1235:                        }
1236:                    }
1237:                }
1238:                recomputeBusy();
1239:
1240:                // Close (physically) connections lost (opened for too long time)
1241:                for (Iterator i = mcList.iterator(); i.hasNext();) {
1242:                    JManagedConnection mc = (JManagedConnection) i.next();
1243:                    if (mc.inactive()) {
1244:                        if (logger.isWarnEnabled()) {
1245:                            logger.warn(
1246:                                    "close a timed out open connection {0}", mc
1247:                                            .getIdentifier());
1248:                        }
1249:                        i.remove();
1250:                        // destroy mc
1251:                        mc.remove();
1252:                        connectionLeaks++;
1253:                        // Notify 1 thread waiting for a Connection.
1254:                        if (currentWaiters > 0) {
1255:                            notify();
1256:                        }
1257:                    }
1258:                }
1259:
1260:                // Shrink the pool in case of max pool size
1261:                // This occurs when max pool size has been reduced by admin console.
1262:                if (poolMax != NO_LIMIT) {
1263:                    while (freeList.size() > poolMin && mcList.size() > poolMax) {
1264:                        JManagedConnection mc = freeList.first();
1265:                        freeList.remove(mc);
1266:                        destroyItem(mc);
1267:                    }
1268:                }
1269:                recomputeBusy();
1270:
1271:                // Recreate more Connections while poolMin is not reached
1272:                while (mcList.size() < poolMin) {
1273:                    JManagedConnection mc = null;
1274:                    try {
1275:                        mc = (JManagedConnection) getXAConnection();
1276:                        openedCount++;
1277:                    } catch (SQLException e) {
1278:                        throw new IllegalStateException("Could not create "
1279:                                + poolMin + " mcs in the pool : ", e);
1280:                    }
1281:                    // tx = null. Assumes maxage already configured.
1282:                    freeList.add(mc);
1283:                    mcList.add(mc);
1284:                    mc.addConnectionEventListener(this );
1285:                }
1286:            }
1287:
1288:            /**
1289:             * Lookup connection in the pool for this user/tx.
1290:             * @param user user name
1291:             * @param tx Transaction the connection is involved
1292:             * @return a free JManagedConnection (never null)
1293:             * @throws SQLException Cannot open a connection because the pool's max size
1294:             *         is reached
1295:             */
1296:            @SuppressWarnings("boxing")
1297:            public synchronized JManagedConnection openConnection(
1298:                    final String user, final Transaction tx)
1299:                    throws SQLException {
1300:                JManagedConnection mc = null;
1301:                // If a Connection exists already for this tx, just return it.
1302:                // If no transaction, never reuse a connection already used.
1303:                if (tx != null) {
1304:                    mc = tx2mc.get(tx);
1305:                    if (mc != null) {
1306:                        logger.debug("Reuse a Connection for same tx");
1307:                        mc.hold();
1308:                        servedOpen++;
1309:                        return mc;
1310:                    }
1311:                }
1312:                // Loop until a valid mc is found
1313:                long timetowait = waiterTimeout;
1314:                long starttime = 0;
1315:                while (mc == null) {
1316:                    // try to find an mc in the free list
1317:                    if (freeList.isEmpty()) {
1318:                        // In case we have reached the maximum limit of the pool,
1319:                        // we must wait until a connection is released.
1320:                        if (mcList.size() >= poolMax) {
1321:                            boolean stoplooping = true;
1322:                            // If a timeout has been specified, wait, unless maxWaiters
1323:                            // is reached.
1324:                            if (timetowait > 0) {
1325:                                if (currentWaiters < maxWaiters) {
1326:                                    currentWaiters++;
1327:                                    // Store the maximum concurrent waiters
1328:                                    if (waiterCount < currentWaiters) {
1329:                                        waiterCount = currentWaiters;
1330:                                    }
1331:                                    if (starttime == 0) {
1332:                                        starttime = System.currentTimeMillis();
1333:                                        logger
1334:                                                .debug(
1335:                                                        "Wait for a free Connection, {0}",
1336:                                                        mcList.size());
1337:                                    }
1338:                                    try {
1339:                                        wait(timetowait);
1340:                                    } catch (InterruptedException ign) {
1341:                                        logger.warn("Interrupted");
1342:                                    } finally {
1343:                                        currentWaiters--;
1344:                                    }
1345:                                    long stoptime = System.currentTimeMillis();
1346:                                    long stillwaited = stoptime - starttime;
1347:                                    timetowait = waiterTimeout - stillwaited;
1348:                                    stoplooping = (timetowait <= 0);
1349:                                    if (stoplooping) {
1350:                                        // We have been waked up by the timeout.
1351:                                        totalWaiterCount++;
1352:                                        totalWaitingTime += stillwaited;
1353:                                        if (waitingTime < stillwaited) {
1354:                                            waitingTime = stillwaited;
1355:                                        }
1356:                                    } else {
1357:                                        if (!freeList.isEmpty()
1358:                                                || mcList.size() < poolMax) {
1359:                                            // We have been notified by a connection
1360:                                            // released.
1361:                                            logger.debug("Notified after {0}",
1362:                                                    stillwaited);
1363:                                            totalWaiterCount++;
1364:                                            totalWaitingTime += stillwaited;
1365:                                            if (waitingTime < stillwaited) {
1366:                                                waitingTime = stillwaited;
1367:                                            }
1368:                                        }
1369:                                        continue;
1370:                                    }
1371:                                }
1372:                            }
1373:                            if (stoplooping && freeList.isEmpty()
1374:                                    && mcList.size() >= poolMax) {
1375:                                if (starttime > 0) {
1376:                                    rejectedTimeout++;
1377:                                    logger
1378:                                            .warn("Cannot create a Connection - timeout");
1379:                                } else {
1380:                                    rejectedFull++;
1381:                                    logger.warn("Cannot create a Connection");
1382:                                }
1383:                                throw new SQLException(
1384:                                        "No more connections in "
1385:                                                + getDatasourceName());
1386:                            }
1387:                            continue;
1388:                        }
1389:                        logger
1390:                                .debug("empty free list: Create a new Connection");
1391:                        try {
1392:                            // create a new XA Connection
1393:                            mc = (JManagedConnection) getXAConnection();
1394:                            openedCount++;
1395:                        } catch (SQLException e) {
1396:                            connectionFailures++;
1397:                            rejectedOther++;
1398:                            logger.warn("Cannot create new Connection for tx",
1399:                                    e);
1400:                            throw e;
1401:                        }
1402:                        // Register the connection manager as a ConnectionEventListener
1403:                        mc.addConnectionEventListener(this );
1404:                        mcList.add(mc);
1405:                    } else {
1406:                        mc = freeList.last();
1407:                        freeList.remove(mc);
1408:                        // Check the connection before reusing it
1409:                        if (checkLevel > 0) {
1410:                            try {
1411:                                JConnection conn = (JConnection) mc
1412:                                        .getConnection();
1413:                                if (conn.isPhysicallyClosed()) {
1414:                                    logger
1415:                                            .warn("The JDBC connection has been closed!");
1416:                                    destroyItem(mc);
1417:                                    starttime = 0;
1418:                                    mc = null;
1419:                                    continue;
1420:                                }
1421:                                if (checkLevel > 1) {
1422:                                    java.sql.Statement stmt = conn
1423:                                            .createStatement();
1424:                                    stmt.execute(testStatement);
1425:                                    stmt.close();
1426:                                }
1427:                            } catch (Exception e) {
1428:                                logger.error("DataSource "
1429:                                        + getDatasourceName()
1430:                                        + " error: removing invalid mc", e);
1431:                                destroyItem(mc);
1432:                                starttime = 0;
1433:                                mc = null;
1434:                                continue;
1435:                            }
1436:                        }
1437:                    }
1438:                }
1439:                recomputeBusy();
1440:                mc.setTx(tx);
1441:                if (tx == null) {
1442:                    logger.debug("Got a Connection - no TX: ");
1443:                } else {
1444:                    logger.debug("Got a Connection for TX: ");
1445:                    // register synchronization
1446:                    try {
1447:                        tx.registerSynchronization(mc);
1448:                        tx2mc.put(tx, mc); // only if registerSynchronization was OK.
1449:                    } catch (javax.transaction.RollbackException e) {
1450:                        // / optimization is probably possible at this point
1451:                        logger
1452:                                .warn(
1453:                                        "DataSource "
1454:                                                + getDatasourceName()
1455:                                                + " error: Pool mc registered, but tx is rollback only",
1456:                                        e);
1457:                    } catch (javax.transaction.SystemException e) {
1458:                        logger
1459:                                .error(
1460:                                        "DataSource "
1461:                                                + getDatasourceName()
1462:                                                + " error in pool: system exception from transaction manager ",
1463:                                        e);
1464:                    } catch (IllegalStateException e) {
1465:                        // In case transaction has already committed, do as if no tx.
1466:                        logger.warn("Got a Connection - committed TX: ", e);
1467:                        mc.setTx(null);
1468:                    }
1469:                }
1470:                mc.hold();
1471:                servedOpen++;
1472:                return mc;
1473:            }
1474:
1475:            /**
1476:             * The transaction has committed (or rolled back). We can return its
1477:             * connections to the pool of available connections.
1478:             * @param tx the non null transaction
1479:             */
1480:            public synchronized void freeConnections(final Transaction tx) {
1481:                logger.debug("free connection for Tx = " + tx);
1482:                JManagedConnection mc = tx2mc.remove(tx);
1483:                if (mc == null) {
1484:                    logger.error("pool: no connection found to free for Tx = "
1485:                            + tx);
1486:                    return;
1487:                }
1488:                mc.setTx(null);
1489:                if (mc.isOpen()) {
1490:                    // Connection not yet closed (but committed).
1491:                    logger.debug("Connection not closed by caller");
1492:                    return;
1493:                }
1494:                freeItem(mc);
1495:            }
1496:
1497:            /**
1498:             * Close all connections in the pool, when server is shut down.
1499:             */
1500:            public synchronized void closeAllConnection() {
1501:                // Close physically all connections
1502:                Iterator it = mcList.iterator();
1503:                try {
1504:                    while (it.hasNext()) {
1505:                        JManagedConnection mc = (JManagedConnection) it.next();
1506:                        mc.close();
1507:                    }
1508:                } catch (java.sql.SQLException e) {
1509:                    logger.error("Error while closing a Connection:", e);
1510:                }
1511:            }
1512:
1513:            // -----------------------------------------------------------------------
1514:            // private methods
1515:            // -----------------------------------------------------------------------
1516:
1517:            /**
1518:             * Mark a specific Connection in the pool as closed. If it is no longer
1519:             * associated to a Tx, we can free it.
1520:             * @param mc XAConnection being closed
1521:             * @param flag TMSUCCESS (normal close) or TMFAIL (error) or null if error.
1522:             * @return false if has not be closed (still in use)
1523:             */
1524:            private boolean closeConnection(final JManagedConnection mc,
1525:                    final int flag) {
1526:                // The connection will be available only if not associated
1527:                // to a transaction. Else, it will be reusable only for the
1528:                // same transaction.
1529:                if (!mc.release()) {
1530:                    return false;
1531:                }
1532:                if (mc.getTx() != null) {
1533:                    logger.debug("keep connection for same tx");
1534:                } else {
1535:                    freeItem(mc);
1536:                }
1537:
1538:                // delist Resource if in transaction
1539:                Transaction tx = null;
1540:                try {
1541:                    tx = tm.getTransaction();
1542:                } catch (NullPointerException n) {
1543:                    // current is null: we are not in EasyBeans Server.
1544:                    logger
1545:                            .error(
1546:                                    "Pool: should not be used outside a EasyBeans Server",
1547:                                    n);
1548:                } catch (SystemException e) {
1549:                    logger.error("Pool: getTransaction failed:", e);
1550:                }
1551:                if (tx != null && mc.isClosed()) {
1552:                    try {
1553:                        tx.delistResource(mc.getXAResource(), flag);
1554:                    } catch (Exception e) {
1555:                        logger.error(
1556:                                "Pool: Exception while delisting resource:", e);
1557:                    }
1558:                }
1559:                return true;
1560:            }
1561:
1562:            /**
1563:             * Free item and return it in the free list.
1564:             * @param item The item to be freed
1565:             */
1566:            @SuppressWarnings("boxing")
1567:            private synchronized void freeItem(final JManagedConnection item) {
1568:                // Add it to the free list
1569:                // Even if maxage is reached, because we avoids going under min pool
1570:                // size.
1571:                // PoolKeeper will manage aged connections.
1572:                freeList.add(item);
1573:                if (logger.isDebugEnabled()) {
1574:                    logger.debug("item added to freeList: "
1575:                            + item.getIdentifier());
1576:                }
1577:
1578:                // Notify 1 thread waiting for a Connection.
1579:                if (currentWaiters > 0) {
1580:                    notify();
1581:                }
1582:                recomputeBusy();
1583:            }
1584:
1585:            /**
1586:             * Destroy an mc because connection closed or error occured.
1587:             * @param mc The mc to be destroyed
1588:             */
1589:            private synchronized void destroyItem(final JManagedConnection mc) {
1590:                mcList.remove(mc);
1591:                mc.remove();
1592:                // Notify 1 thread waiting for a Connection.
1593:                if (currentWaiters > 0) {
1594:                    notify();
1595:                }
1596:                recomputeBusy();
1597:            }
1598:
1599:            /**
1600:             * Check on a connection the test statement.
1601:             * @param testStatement the statement to use for test
1602:             * @return the test statement if the test succeeded, an error message
1603:             *         otherwise
1604:             * @throws SQLException If an error occured when trying to test (not due to
1605:             *         the test itself, but to other preliminary or post operation).
1606:             */
1607:            public String checkConnection(final String testStatement)
1608:                    throws SQLException {
1609:                String noError = testStatement;
1610:                JManagedConnection mc = null;
1611:                boolean jmcCreated = false;
1612:                if (!freeList.isEmpty()) {
1613:                    // find a connection to test in the freeList
1614:                    Iterator it = freeList.iterator();
1615:                    while (it.hasNext()) {
1616:                        mc = (JManagedConnection) it.next();
1617:                        try {
1618:                            JConnection conn = (JConnection) mc.getConnection();
1619:                            if (!conn.isPhysicallyClosed()) {
1620:                                // ok, we found a connection we can use to test
1621:                                logger
1622:                                        .debug("Use a free JManagedConnection to test with "
1623:                                                + testStatement);
1624:                                break;
1625:                            }
1626:                            mc = null;
1627:                        } catch (SQLException e) {
1628:                            // Can't use this connection to test
1629:                            mc = null;
1630:                        }
1631:                    }
1632:                }
1633:                if (mc == null) {
1634:                    // try to create mc Connection
1635:                    logger.debug("Create a JManagedConnection to test with "
1636:                            + testStatement);
1637:                    Connection conn = null;
1638:                    try {
1639:                        conn = DriverManager.getConnection(url, userName,
1640:                                password);
1641:                    } catch (SQLException e) {
1642:                        logger.error(
1643:                                "Could not get Connection on " + url + ":", e);
1644:                    }
1645:                    mc = new JManagedConnection(conn, this );
1646:                    jmcCreated = true;
1647:                }
1648:                if (mc != null) {
1649:                    // Do the test on a the free connection or the created connection
1650:                    JConnection conn = (JConnection) mc.getConnection();
1651:                    java.sql.Statement stmt = conn.createStatement();
1652:                    try {
1653:                        stmt.execute(testStatement);
1654:                    } catch (SQLException e) {
1655:                        // The test fails
1656:                        return e.getMessage();
1657:                    }
1658:                    stmt.close();
1659:                    if (jmcCreated) {
1660:                        mc.close();
1661:                    }
1662:                }
1663:                return noError;
1664:            }
1665:
1666:            /**
1667:             * Sets the transaction managed used by the connections.
1668:             * @param tm the transaction manager.
1669:             */
1670:            protected void setTm(final TransactionManager tm) {
1671:                this.tm = tm;
1672:            }
1673:
1674:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.