Source Code Cross Referenced for ConnectionManager.java in  » J2EE » JOnAS-4.8.6 » org » objectweb » jonas » dbm » 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 » JOnAS 4.8.6 » org.objectweb.jonas.dbm 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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