0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.sql;
0031:
0032: import com.caucho.config.ConfigException;
0033: import com.caucho.config.types.InitParam;
0034: import com.caucho.config.types.Period;
0035: import com.caucho.loader.Environment;
0036: import com.caucho.loader.EnvironmentClassLoader;
0037: import com.caucho.loader.EnvironmentListener;
0038: import com.caucho.log.Log;
0039: import com.caucho.util.Alarm;
0040: import com.caucho.util.AlarmListener;
0041: import com.caucho.util.L10N;
0042: import com.caucho.sql.spy.*;
0043:
0044: import javax.naming.InitialContext;
0045: import javax.naming.NamingException;
0046: import javax.resource.spi.ManagedConnectionFactory;
0047: import javax.sql.ConnectionPoolDataSource;
0048: import javax.sql.XADataSource;
0049: import javax.transaction.TransactionManager;
0050: import java.io.PrintWriter;
0051: import java.sql.Driver;
0052: import java.sql.SQLException;
0053: import java.util.ArrayList;
0054: import java.util.HashMap;
0055: import java.util.Iterator;
0056: import java.util.logging.Level;
0057: import java.util.logging.Logger;
0058:
0059: /**
0060: * Manages a pool of database connections. In addition, DBPool configures
0061: * the database connection from a configuration file.
0062: *
0063: * <p>Like JDBC 2.0 pooling, DBPool returns a wrapped Connection.
0064: * Applications can use that connection just like an unpooled connection.
0065: * It is more important than ever to <code>close()</code> the connection,
0066: * because the close returns the connection to the connection pool.
0067: *
0068: * <h4>Example using DataSource JNDI style (recommended)</h4>
0069: *
0070: * <pre><code>
0071: * Context env = (Context) new InitialContext().lookup("java:comp/env");
0072: * DataSource pool = (DataSource) env.lookup("jdbc/test");
0073: * Connection conn = pool.getConnection();
0074: * try {
0075: * ... // normal connection stuff
0076: * } finally {
0077: * conn.close();
0078: * }
0079: * </code></pre>
0080: *
0081: * <h4>Configuration</h4>
0082: *
0083: * <pre><code>
0084: * <database name='jdbc/test'>
0085: * <init>
0086: * <driver>postgresql.Driver</driver>
0087: * <url>jdbc:postgresql://localhost/test</url>
0088: * <user>ferg</user>
0089: * <password>foobar</password>
0090: * </init>
0091: * </database>
0092: * </code></pre>
0093: *
0094: * <h4>Pool limits and timeouts</h4>
0095: *
0096: * The pool will only allow getMaxConnections() connections alive at a time.
0097: * If <code>getMaxConnection</code> connections are already active,
0098: * <code>getPooledConnection</code> will block waiting for an available
0099: * connection. The wait is timed. If connection-wait-time passes
0100: * and there is still no connection, <code>getPooledConnection</code>
0101: * create a new connection anyway.
0102: *
0103: * <p>Connections will only stay in the pool for about 5 seconds. After
0104: * that they will be removed and closed. This reduces the load on the DB
0105: * and also protects against the database dropping old connections.
0106: */
0107: public class DBPoolImpl implements AlarmListener, EnvironmentListener {
0108: protected static final Logger log = Logger
0109: .getLogger(DBPoolImpl.class.getName());
0110: private static final L10N L = new L10N(DBPoolImpl.class);
0111:
0112: /**
0113: * The beginning of the URL used to connect to a database with
0114: * this pooled connection driver.
0115: */
0116: private static final String URL_PREFIX = "jdbc:caucho:";
0117:
0118: /**
0119: * The key used to look into the properties passed to the
0120: * connect method to find the username.
0121: */
0122: public static final String PROPERTY_USER = "user";
0123: /**
0124: * The key used to look into the properties passed to the
0125: * connect method to find the password.
0126: */
0127: public static final String PROPERTY_PASSWORD = "password";
0128:
0129: // How long an unused connection can remain in the pool
0130: private static final long MAX_IDLE_TIME = 30000;
0131:
0132: private String _name;
0133:
0134: private ArrayList<DriverConfig> _driverList = new ArrayList<DriverConfig>();
0135:
0136: private ArrayList<DriverConfig> _backupDriverList = new ArrayList<DriverConfig>();
0137:
0138: private ConnectionConfig _connectionConfig = new ConnectionConfig();
0139:
0140: // private ManagedFactoryImpl _mcf;
0141: private ManagedConnectionFactory _mcf;
0142:
0143: private String _user;
0144: private String _password;
0145:
0146: // total connections allowed in this pool
0147: private int _maxConnections = 128;
0148: // time before an idle connection is closed
0149: private long _maxIdleTime = MAX_IDLE_TIME;
0150: // max time a connection is allowed to be active (6 hr)
0151: private long _maxActiveTime = 6L * 3600L * 1000L;
0152: // max time a connection is allowed in the pool
0153: private long _maxPoolTime = 24L * 3600L * 1000L;
0154:
0155: // how long to wait for a connection, say 10 minutes
0156: private long _connectionWaitTime = 600 * 1000;
0157: private int _connectionWaitCount = (int) (_connectionWaitTime / 1000);
0158:
0159: // connections to create even when the max-connections overflows.
0160: private int _maxOverflowConnections = 0;
0161:
0162: // true if the pool has started
0163: private boolean _isStarted;
0164: // true if the pool has closed
0165: private boolean _isClosed;
0166: // if true, the pool can't be closed.
0167: private boolean _forbidClose;
0168:
0169: // The JDBC table to be used to ping for connection liveness.
0170: private String _pingTable;
0171: // The Query used for connection liveness.
0172: private String _pingQuery;
0173: // Ping when the connection is reused.
0174: private Boolean _isPing;
0175: // How long between pings
0176: private long _pingInterval = 1000;
0177:
0178: // True if the pool is transactional
0179: private boolean _isTransactional = true;
0180: // True if the pool should never allow isSameRM
0181: private boolean _isXAForbidSameRM = false;
0182: // The transaction manager if the pool participates in transactions.
0183: private TransactionManager _tm;
0184: // how long before the transaction times out
0185: private long _transactionTimeout = 0;
0186:
0187: private boolean _isSpy;
0188: private SpyDataSource _spyDataSource;
0189:
0190: private int _maxCloseStatements = 256;
0191: // The prepared statement cache size.
0192: private int _preparedStatementCacheSize = 0;
0193:
0194: private boolean _isWrapStatements = true;
0195:
0196: // The connections currently in the pool.
0197: // transient ArrayList<PoolItem> _connections = new ArrayList<PoolItem>();
0198:
0199: // Count for debugging ids.
0200: private int _idCount;
0201:
0202: // The alarm
0203: private Alarm _alarm;
0204:
0205: /**
0206: * Null constructor for the Driver interface; called by the JNDI
0207: * configuration. Applications should not call this directly.
0208: */
0209: public DBPoolImpl() {
0210: }
0211:
0212: /**
0213: * Returns the Pool's name
0214: */
0215: public String getName() {
0216: return _name;
0217: }
0218:
0219: /**
0220: * Sets the Pool's name. Also puts the pool in the classloader's
0221: * list of pools.
0222: */
0223: public void setName(String name) {
0224: _name = name;
0225: }
0226:
0227: public String getURL() {
0228: return _driverList.get(0).getURL();
0229: }
0230:
0231: /**
0232: * Returns the driver config.
0233: */
0234: public DriverConfig createDriver() {
0235: DriverConfig driver = new DriverConfig(this );
0236:
0237: _driverList.add(driver);
0238:
0239: return driver;
0240: }
0241:
0242: /**
0243: * Returns the driver config.
0244: */
0245: public DriverConfig createBackupDriver() {
0246: DriverConfig driver = new DriverConfig(this );
0247:
0248: _backupDriverList.add(driver);
0249:
0250: return driver;
0251: }
0252:
0253: /**
0254: * Sets a driver parameter.
0255: */
0256: public void setInitParam(InitParam init) {
0257: DriverConfig driver = _driverList.get(0);
0258:
0259: HashMap<String, String> params = init.getParameters();
0260:
0261: Iterator<String> iter = params.keySet().iterator();
0262: while (iter.hasNext()) {
0263: String key = iter.next();
0264: driver.setInitParam(key, params.get(key));
0265: }
0266: }
0267:
0268: /**
0269: * Sets the jdbc-driver config.
0270: */
0271: public void setJDBCDriver(Driver jdbcDriver) throws SQLException {
0272: DriverConfig driver;
0273:
0274: if (_driverList.size() > 0)
0275: driver = _driverList.get(0);
0276: else
0277: driver = createDriver();
0278:
0279: driver.setDriver(jdbcDriver);
0280: }
0281:
0282: /**
0283: * Creates the connection config.
0284: */
0285: public ConnectionConfig createConnection() {
0286: return _connectionConfig;
0287: }
0288:
0289: /**
0290: * Returns the connection config.
0291: */
0292: public ConnectionConfig getConnectionConfig() {
0293: return _connectionConfig;
0294: }
0295:
0296: /**
0297: * Sets the jdbc-driver config.
0298: */
0299: public void setPoolDataSource(
0300: ConnectionPoolDataSource poolDataSource)
0301: throws SQLException {
0302: DriverConfig driver;
0303:
0304: if (_driverList.size() > 0)
0305: driver = _driverList.get(0);
0306: else
0307: driver = createDriver();
0308:
0309: driver.setPoolDataSource(poolDataSource);
0310: }
0311:
0312: /**
0313: * Sets the jdbc-driver config.
0314: */
0315: public void setXADataSource(XADataSource xaDataSource)
0316: throws SQLException {
0317: DriverConfig driver;
0318:
0319: if (_driverList.size() > 0)
0320: driver = _driverList.get(0);
0321: else
0322: driver = createDriver();
0323:
0324: driver.setXADataSource(xaDataSource);
0325: }
0326:
0327: /**
0328: * Sets the jdbc-driver config.
0329: */
0330: public void setURL(String url) throws ConfigException {
0331: DriverConfig driver;
0332:
0333: if (_driverList.size() > 0)
0334: driver = _driverList.get(0);
0335: else
0336: throw new ConfigException(L
0337: .l("The driver must be assigned before the URL."));
0338:
0339: driver.setURL(url);
0340: }
0341:
0342: /**
0343: * Returns the connection's user.
0344: */
0345: public String getUser() {
0346: return _user;
0347: }
0348:
0349: /**
0350: * Sets the connection's user.
0351: */
0352: public void setUser(String user) {
0353: _user = user;
0354: }
0355:
0356: /**
0357: * Returns the connection's password
0358: */
0359: public String getPassword() {
0360: return _password;
0361: }
0362:
0363: /**
0364: * Sets the connection's password
0365: */
0366: public void setPassword(String password) {
0367: _password = password;
0368: }
0369:
0370: /**
0371: * Get the maximum number of pooled connections.
0372: */
0373: public int getMaxConnections() {
0374: return _maxConnections;
0375: }
0376:
0377: /**
0378: * Sets the maximum number of pooled connections.
0379: */
0380: public void setMaxConnections(int maxConnections) {
0381: _maxConnections = maxConnections;
0382: }
0383:
0384: /**
0385: * Get the total number of connections
0386: */
0387: public int getTotalConnections() {
0388: // return _connections.size();
0389: return 0;
0390: }
0391:
0392: /**
0393: * Sets the time to wait for a connection when all are used.
0394: */
0395: public void setConnectionWaitTime(Period waitTime) {
0396: long period = waitTime.getPeriod();
0397:
0398: _connectionWaitTime = period;
0399:
0400: if (period < 0)
0401: _connectionWaitCount = 3600; // wait for an hour == infinity
0402: else {
0403: _connectionWaitCount = (int) ((period + 999) / 1000);
0404:
0405: if (_connectionWaitCount <= 0)
0406: _connectionWaitCount = 1;
0407: }
0408: }
0409:
0410: /**
0411: * Gets the time to wait for a connection when all are used.
0412: */
0413: public long getConnectionWaitTime() {
0414: return _connectionWaitTime;
0415: }
0416:
0417: /**
0418: * The number of connections to overflow if the connection pool fills
0419: * and there's a timeout.
0420: */
0421: public void setMaxOverflowConnections(int maxOverflowConnections) {
0422: _maxOverflowConnections = maxOverflowConnections;
0423: }
0424:
0425: /**
0426: * The number of connections to overflow if the connection pool fills
0427: * and there's a timeout.
0428: */
0429: public int getMaxOverflowConnections() {
0430: return _maxOverflowConnections;
0431: }
0432:
0433: /**
0434: * Sets the transaction timeout.
0435: */
0436: public void setTransactionTimeout(Period period) {
0437: _transactionTimeout = period.getPeriod();
0438: }
0439:
0440: /**
0441: * Gets the transaction timeout.
0442: */
0443: public long getTransactionTimeout() {
0444: return _transactionTimeout;
0445: }
0446:
0447: /**
0448: * Sets the max statement.
0449: */
0450: public void setMaxCloseStatements(int max) {
0451: _maxCloseStatements = max;
0452: }
0453:
0454: /**
0455: * Gets the max statement.
0456: */
0457: public int getMaxCloseStatements() {
0458: return _maxCloseStatements;
0459: }
0460:
0461: /**
0462: * Sets true if statements should be wrapped.
0463: */
0464: public void setWrapStatements(boolean isWrap) {
0465: _isWrapStatements = isWrap;
0466: }
0467:
0468: /**
0469: * Sets true if statements should be wrapped.
0470: */
0471: public boolean isWrapStatements() {
0472: return _isWrapStatements;
0473: }
0474:
0475: /**
0476: * Returns the prepared statement cache size.
0477: */
0478: public int getPreparedStatementCacheSize() {
0479: return _preparedStatementCacheSize;
0480: }
0481:
0482: /**
0483: * Sets the prepared statement cache size.
0484: */
0485: public void setPreparedStatementCacheSize(int size) {
0486: _preparedStatementCacheSize = size;
0487: }
0488:
0489: /**
0490: * Get the time in milliseconds a connection will remain in the pool before
0491: * being closed.
0492: */
0493: public long getMaxIdleTime() {
0494: if (_maxIdleTime > Long.MAX_VALUE / 2)
0495: return -1;
0496: else
0497: return _maxIdleTime;
0498: }
0499:
0500: /**
0501: * Set the time in milliseconds a connection will remain in the pool before
0502: * being closed.
0503: */
0504: public void setMaxIdleTime(Period idleTime) {
0505: long period = idleTime.getPeriod();
0506:
0507: if (period < 0)
0508: _maxIdleTime = Long.MAX_VALUE / 2;
0509: else if (period < 1000L)
0510: _maxIdleTime = 1000L;
0511: else
0512: _maxIdleTime = period;
0513: }
0514:
0515: /**
0516: * Get the time in milliseconds a connection will remain in the pool before
0517: * being closed.
0518: */
0519: public long getMaxPoolTime() {
0520: if (_maxPoolTime > Long.MAX_VALUE / 2)
0521: return -1;
0522: else
0523: return _maxPoolTime;
0524: }
0525:
0526: /**
0527: * Set the time in milliseconds a connection will remain in the pool before
0528: * being closed.
0529: */
0530: public void setMaxPoolTime(Period maxPoolTime) {
0531: long period = maxPoolTime.getPeriod();
0532:
0533: if (period < 0)
0534: _maxPoolTime = Long.MAX_VALUE / 2;
0535: else if (period == 0)
0536: _maxPoolTime = 1000L;
0537: else
0538: _maxPoolTime = period;
0539: }
0540:
0541: /**
0542: * Get the time in milliseconds a connection can remain active.
0543: */
0544: public long getMaxActiveTime() {
0545: if (_maxActiveTime > Long.MAX_VALUE / 2)
0546: return -1;
0547: else
0548: return _maxActiveTime;
0549: }
0550:
0551: /**
0552: * Set the time in milliseconds a connection can remain active.
0553: */
0554: public void setMaxActiveTime(Period maxActiveTime) {
0555: long period = maxActiveTime.getPeriod();
0556:
0557: if (period < 0)
0558: _maxActiveTime = Long.MAX_VALUE / 2;
0559: else if (period == 0)
0560: _maxActiveTime = 1000L;
0561: else
0562: _maxActiveTime = period;
0563: }
0564:
0565: /**
0566: * Get the table to 'ping' to see if the connection is still live.
0567: */
0568: public String getPingTable() {
0569: return _pingTable;
0570: }
0571:
0572: /**
0573: * Set the table to 'ping' to see if the connection is still live.
0574: *
0575: * @param pingTable name of the SQL table to ping.
0576: */
0577: public void setPingTable(String pingTable) {
0578: _pingTable = pingTable;
0579:
0580: if (pingTable != null)
0581: _pingQuery = "select 1 from " + pingTable + " where 1=0";
0582: else
0583: _pingQuery = null;
0584:
0585: if (_isPing == null)
0586: _isPing = true;
0587: }
0588:
0589: /**
0590: * Returns the ping query.
0591: */
0592: public String getPingQuery() {
0593: return _pingQuery;
0594: }
0595:
0596: /**
0597: * Sets the ping query.
0598: */
0599: public void setPingQuery(String pingQuery) {
0600: _pingQuery = pingQuery;
0601:
0602: if (_isPing == null)
0603: _isPing = true;
0604: }
0605:
0606: /**
0607: * If true, the pool will ping when attempting to reuse a connection.
0608: */
0609: public boolean getPingOnReuse() {
0610: return isPing();
0611: }
0612:
0613: /**
0614: * Set the table to 'ping' to see if the connection is still live.
0615: */
0616: public void setPingOnReuse(boolean pingOnReuse) {
0617: _isPing = pingOnReuse;
0618: }
0619:
0620: /**
0621: * If true, the pool will ping in the idle pool.
0622: */
0623: public boolean getPingOnIdle() {
0624: return _isPing;
0625: }
0626:
0627: /**
0628: * Set the table to 'ping' to see if the connection is still live.
0629: */
0630: public void setPingOnIdle(boolean pingOnIdle) {
0631: _isPing = pingOnIdle;
0632: }
0633:
0634: /**
0635: * Set true if pinging is enabled.
0636: */
0637: public void setPing(boolean ping) {
0638: _isPing = ping;
0639: }
0640:
0641: /**
0642: * Returns true if pinging is enabled.
0643: */
0644: public boolean isPing() {
0645: if (_isPing != null)
0646: return _isPing;
0647: else
0648: return false;
0649: }
0650:
0651: /**
0652: * Sets the time to ping for ping-on-idle
0653: */
0654: public void setPingInterval(Period interval) {
0655: _pingInterval = interval.getPeriod();
0656:
0657: if (_pingInterval < 0)
0658: _pingInterval = Long.MAX_VALUE / 2;
0659: else if (_pingInterval < 1000)
0660: _pingInterval = 1000;
0661:
0662: if (_isPing == null)
0663: _isPing = true;
0664: }
0665:
0666: /**
0667: * Gets how often the ping for ping-on-idle
0668: */
0669: public long getPingInterval() {
0670: return _pingInterval;
0671: }
0672:
0673: /**
0674: * Set the transaction manager for this pool.
0675: */
0676: public void setTransactionManager(TransactionManager tm) {
0677: _tm = tm;
0678: }
0679:
0680: /**
0681: * Returns the transaction manager.
0682: */
0683: /*
0684: public TransactionManager getTransactionManager()
0685: {
0686: return _tm;
0687: }
0688: */
0689:
0690: /**
0691: * Returns true if this is transactional.
0692: */
0693: public boolean isXA() {
0694: return _isTransactional;
0695: }
0696:
0697: /**
0698: * Returns true if this is transactional.
0699: */
0700: public void setXA(boolean isTransactional) {
0701: _isTransactional = isTransactional;
0702: }
0703:
0704: /**
0705: * Returns true if transactions should force isSameRM to be false.
0706: */
0707: public boolean isXAForbidSameRM() {
0708: return _isXAForbidSameRM;
0709: }
0710:
0711: /**
0712: * Returns true if transactions should force isSameRM to be false.
0713: */
0714: public void setXAForbidSameRM(boolean isXAForbidSameRM) {
0715: _isXAForbidSameRM = isXAForbidSameRM;
0716: }
0717:
0718: /**
0719: * Set the output for spying.
0720: */
0721: public void setSpy(boolean isSpy) {
0722: _isSpy = isSpy;
0723: }
0724:
0725: /**
0726: * Return true for a spy.
0727: */
0728: public boolean isSpy() {
0729: return _isSpy;
0730: }
0731:
0732: /**
0733: * Returns the next spy id.
0734: */
0735: public SpyDataSource getSpyDataSource() {
0736: return _spyDataSource;
0737: }
0738:
0739: /**
0740: * Returns the next spy id.
0741: */
0742: public String newSpyId() {
0743: return _spyDataSource.createConnectionId();
0744: }
0745:
0746: /**
0747: * Returns true if the pool supports transactions.
0748: */
0749: public boolean isTransactional() {
0750: return _isTransactional;
0751: }
0752:
0753: /**
0754: * Returns true if there is a valid XAResource associated
0755: * with the database.
0756: */
0757: public boolean isXATransaction() {
0758: if (_connectionConfig.isReadOnly())
0759: return false;
0760: else if (_driverList.size() > 0) {
0761: DriverConfig driver = _driverList.get(0);
0762:
0763: return driver.isXATransaction();
0764: } else
0765: return false;
0766: }
0767:
0768: /**
0769: * Returns true if there is a valid local transactino associated
0770: * with the database.
0771: */
0772: public boolean isLocalTransaction() {
0773: if (_connectionConfig.isReadOnly())
0774: return false;
0775: else if (_driverList.size() > 0) {
0776: DriverConfig driver = _driverList.get(0);
0777:
0778: return driver.isLocalTransaction();
0779: } else
0780: return false;
0781: }
0782:
0783: int createPoolId() {
0784: return _idCount++;
0785: }
0786:
0787: /**
0788: * Sets the timeout for a database login.
0789: */
0790: public void setLoginTimeout(int seconds) throws SQLException {
0791: }
0792:
0793: /**
0794: * Gets the timeout for a database login.
0795: */
0796: public int getLoginTimeout() throws SQLException {
0797: return 0;
0798: }
0799:
0800: /**
0801: * Sets the debugging log for the connection.
0802: */
0803: public void setLogWriter(PrintWriter out) throws SQLException {
0804: }
0805:
0806: /**
0807: * Sets the debugging log for the connection.
0808: */
0809: public PrintWriter getLogWriter() throws SQLException {
0810: return null;
0811: }
0812:
0813: /**
0814: * Initialize the pool.
0815: */
0816: public void init() throws Exception {
0817: Environment.addEnvironmentListener(this );
0818:
0819: // _alarm = new Alarm("db-pool", this, 60000);
0820:
0821: /*
0822: if (_pingInterval > 0 &&
0823: _pingInterval < _maxIdleTime &&
0824: _pingInterval < 60000L)
0825: _alarm.queue(_pingInterval);
0826: else if (_maxIdleTime > 60000)
0827: _alarm.queue(60000);
0828: else
0829: _alarm.queue(_maxIdleTime);
0830: */
0831:
0832: try {
0833: if (_tm == null) {
0834: Object obj = new InitialContext()
0835: .lookup("java:comp/TransactionManager");
0836:
0837: if (obj instanceof TransactionManager)
0838: _tm = (TransactionManager) obj;
0839: }
0840: } catch (Exception e) {
0841: log.log(Level.FINE, e.toString(), e);
0842: }
0843:
0844: /*
0845: if (isXA() && _tm == null)
0846: throw new ConfigException(L.l("Can't find TransactionManager in java:comp/TransactionManager for transaction-enabled DBPool."));
0847: */
0848:
0849: for (int i = 0; i < _driverList.size(); i++) {
0850: DriverConfig driver = _driverList.get(i);
0851:
0852: if (driver.getUser() == null)
0853: driver.setUser(_user);
0854: if (driver.getPassword() == null)
0855: driver.setPassword(_password);
0856:
0857: driver.initDriver();
0858: driver.initDataSource(_isTransactional, _isSpy);
0859:
0860: if (_mcf == null)
0861: _mcf = driver.getManagedConnectionFactory();
0862:
0863: /*
0864: if (driver.getXADataSource() == null)
0865: _isTransactional = false;
0866: */
0867: }
0868:
0869: DriverConfig[] drivers = new DriverConfig[_driverList.size()];
0870: _driverList.toArray(drivers);
0871:
0872: for (int i = 0; i < _backupDriverList.size(); i++) {
0873: DriverConfig driver = _backupDriverList.get(i);
0874:
0875: if (driver.getUser() == null)
0876: driver.setUser(_user);
0877: if (driver.getPassword() == null)
0878: driver.setPassword(_password);
0879:
0880: driver.initDriver();
0881: driver.initDataSource(_isTransactional, _isSpy);
0882: /*
0883: if (driver.getXADataSource() == null)
0884: _isTransactional = false;
0885: */
0886: }
0887:
0888: DriverConfig[] backupDrivers = new DriverConfig[_backupDriverList
0889: .size()];
0890: _backupDriverList.toArray(backupDrivers);
0891:
0892: if (_mcf == null)
0893: _mcf = new ManagedFactoryImpl(this , drivers, backupDrivers);
0894:
0895: if (_name != null) {
0896: String name = _name;
0897: if (!name.startsWith("java:"))
0898: name = "java:comp/env/" + name;
0899:
0900: if (drivers[0].getURL() != null)
0901: log.config("database " + name + " starting (URL:"
0902: + drivers[0].getURL() + ")");
0903: else
0904: log.config("database " + name + " starting");
0905:
0906: // XXX: actually should be proxy
0907: // Jndi.bindDeep(name, this);
0908: }
0909:
0910: _spyDataSource = new SpyDataSource(_name);
0911: }
0912:
0913: /**
0914: * Returns the managed connection factory.
0915: */
0916: ManagedConnectionFactory getManagedConnectionFactory() {
0917: return _mcf;
0918: }
0919:
0920: /**
0921: * Initialize the pool's data source
0922: *
0923: * <ul>
0924: * <li>If data-source is set, look it up in JNDI.
0925: * <li>Else if the driver is a pooled or xa data source, use it.
0926: * <li>Else create wrappers.
0927: * </ul>
0928: */
0929: synchronized void initDataSource() throws SQLException {
0930: if (_isStarted)
0931: return;
0932:
0933: _isStarted = true;
0934:
0935: for (int i = 0; i < _driverList.size(); i++) {
0936: DriverConfig driver = _driverList.get(i);
0937:
0938: driver.initDataSource(_isTransactional, _isSpy);
0939: }
0940:
0941: try {
0942: if (_isTransactional && _tm == null) {
0943: Object obj = new InitialContext()
0944: .lookup("java:comp/TransactionManager");
0945:
0946: if (obj instanceof TransactionManager)
0947: _tm = (TransactionManager) obj;
0948: }
0949: } catch (NamingException e) {
0950: throw new SQLExceptionWrapper(e);
0951: }
0952: }
0953:
0954: /**
0955: * Closes the idle connections in the pool.
0956: */
0957: public void closeIdleConnections() {
0958:
0959: }
0960:
0961: /**
0962: * At the alarm, close all connections which have been sitting in
0963: * the pool for too long.
0964: *
0965: * @param alarm the alarm event.
0966: */
0967: public void handleAlarm(Alarm alarm) {
0968: if (_isClosed)
0969: return;
0970: }
0971:
0972: /**
0973: * Callback when the environment configures.
0974: */
0975: public void environmentConfig(EnvironmentClassLoader loader) {
0976: }
0977:
0978: /**
0979: * Callback when the environment starts.
0980: */
0981: public void environmentStart(EnvironmentClassLoader loader) {
0982: }
0983:
0984: /**
0985: * Callback when the class loader dies.
0986: */
0987: public void environmentStop(EnvironmentClassLoader loader) {
0988: forceClose();
0989: }
0990:
0991: /**
0992: * Returns true if the pool is closed.
0993: */
0994: public boolean isClosed() {
0995: return _isClosed;
0996: }
0997:
0998: /**
0999: * Close the pool, closing the connections.
1000: */
1001: public void close() {
1002: if (_forbidClose)
1003: throw new IllegalStateException(
1004: "illegal to call close() for this DBPool");
1005: forceClose();
1006: }
1007:
1008: /**
1009: * Close all the connections in the pool.
1010: */
1011: public void forceClose() {
1012: if (_isClosed)
1013: return;
1014:
1015: _isClosed = true;
1016:
1017: if (log.isLoggable(Level.FINE))
1018: log.fine("closing pool " + getName());
1019: }
1020:
1021: /**
1022: * Returns a string description of the pool.
1023: */
1024: public String toString() {
1025: return "DBPoolImpl[" + _name + "]";
1026: }
1027: }
|