diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataAbstractSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataAbstractSource.java index 4e588236be..e17cef8802 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataAbstractSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataAbstractSource.java @@ -1,498 +1,501 @@ /* - * Copyright 2011 Alibaba Group. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2011 Alibaba Group. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and limitations under the + * License. */ -package com.alibaba.druid.pool; - -import java.io.PrintWriter; -import java.io.Serializable; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.sql.DataSource; - -import com.alibaba.druid.filter.Filter; -import com.alibaba.druid.filter.FilterChainImpl; -import com.alibaba.druid.proxy.jdbc.DataSourceProxy; - -/** - * @author wenshao - */ -public abstract class DruidDataAbstractSource implements DataSource, DataSourceProxy, Serializable { - - private static final long serialVersionUID = 1L; - - public final static int DEFAULT_INITIAL_SIZE = 0; - public final static int DEFAULT_MAX_ACTIVE_SIZE = 8; - public final static int DEFAULT_MAX_IDLE = 8; - public final static int DEFAULT_MIN_IDLE = 0; - public final static int DEFAULT_MAX_WAIT = -1; - public final static String DEFAULT_VALIDATION_QUERY = "SELECT 1"; - public final static boolean DEFAULT_TEST_ON_BORROW = true; - public final static boolean DEFAULT_TEST_ON_RETURN = false; - public final static boolean DEFAULT_WHILE_IDLE = false; - - private boolean defaultAutoCommit = false; - private Boolean defaultReadOnly; - private Integer defaultTransactionIsolation; - private String defaultCatalog = null; - - protected String name; - - protected String user; - protected String password; - protected String jdbcUrl; - protected String driverClass; - protected Properties properties = new Properties(); - - protected PasswordCallback passwordCallback; - protected NameCallback userCallback; - - protected ConnectionFactory connectionFactory; - - protected int initialSize = DEFAULT_INITIAL_SIZE; - protected int maxActive = DEFAULT_MAX_ACTIVE_SIZE; - protected int minIdle = DEFAULT_MIN_IDLE; - protected int maxIdle = DEFAULT_MAX_IDLE; - protected long maxWait = DEFAULT_MAX_WAIT; - - protected String validationQuery = DEFAULT_VALIDATION_QUERY; - private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; - private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; - private boolean testWhileIdle = DEFAULT_WHILE_IDLE; - protected boolean poolPreparedStatements = false; - - protected boolean inited = false; - - protected PrintWriter logWriter = new PrintWriter(System.out); - - private final List filters = new ArrayList(); - - protected Driver driver; - - protected int queryTimeout; - - protected long createErrorCount; - - protected long createTimespan; - - public String getValidationQuery() { - return validationQuery; - } - - public void setValidationQuery(String validationQuery) { - this.validationQuery = validationQuery; - } - - public boolean isTestOnBorrow() { - return testOnBorrow; - } - - public void setTestOnBorrow(boolean testOnBorrow) { - this.testOnBorrow = testOnBorrow; - } - - public boolean isTestOnReturn() { - return testOnReturn; - } - - public void setTestOnReturn(boolean testOnReturn) { - this.testOnReturn = testOnReturn; - } - - public boolean isTestWhileIdle() { - return testWhileIdle; - } - - public void setTestWhileIdle(boolean testWhileIdle) { - this.testWhileIdle = testWhileIdle; - } - - public boolean isDefaultAutoCommit() { - return defaultAutoCommit; - } - - public void setDefaultAutoCommit(boolean defaultAutoCommit) { - this.defaultAutoCommit = defaultAutoCommit; - } - - public Boolean getDefaultReadOnly() { - return defaultReadOnly; - } - - public void setDefaultReadOnly(Boolean defaultReadOnly) { - this.defaultReadOnly = defaultReadOnly; - } - - public Integer getDefaultTransactionIsolation() { - return defaultTransactionIsolation; - } - - public void setDefaultTransactionIsolation(Integer defaultTransactionIsolation) { - this.defaultTransactionIsolation = defaultTransactionIsolation; - } - - public String getDefaultCatalog() { - return defaultCatalog; - } - - public void setDefaultCatalog(String defaultCatalog) { - this.defaultCatalog = defaultCatalog; - } - - public PasswordCallback getPasswordCallback() { - return passwordCallback; - } - - public void setPasswordCallback(PasswordCallback passwordCallback) { - this.passwordCallback = passwordCallback; - } - - public NameCallback getUserCallback() { - return userCallback; - } - - public void setUserCallback(NameCallback userCallback) { - this.userCallback = userCallback; - } - - /** - * Retrieves the number of seconds the driver will wait for a Statement object to execute. If the limit - * is exceeded, a SQLException is thrown. - * - * @return the current query timeout limit in seconds; zero means there is no limit - * @exception SQLException if a database access error occurs or this method is called on a closed - * Statement - * @see #setQueryTimeout - */ - public int getQueryTimeout() { - return queryTimeout; - } - - /** - * Sets the number of seconds the driver will wait for a Statement object to execute to the given - * number of seconds. If the limit is exceeded, an SQLException is thrown. A JDBC driver must apply - * this limit to the execute, executeQuery and executeUpdate methods. JDBC - * driver implementations may also apply this limit to ResultSet methods (consult your driver vendor - * documentation for details). - * - * @param seconds the new query timeout limit in seconds; zero means there is no limit - * @exception SQLException if a database access error occurs, this method is called on a closed - * Statement or the condition seconds >= 0 is not satisfied - * @see #getQueryTimeout - */ - public void setQueryTimeout(int seconds) { - this.queryTimeout = seconds; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public boolean isPoolPreparedStatements() { - return poolPreparedStatements; - } - - public void setPoolPreparedStatements(boolean poolPreparedStatements) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.poolPreparedStatements = poolPreparedStatements; - } - - public long getMaxWait() { - return maxWait; - } - - public void setMaxWait(long maxWait) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.maxWait = maxWait; - } - - public int getMinIdle() { - return minIdle; - } - - public void setMinIdle(int minIdle) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.minIdle = minIdle; - } - - public int getMaxIdle() { - return maxIdle; - } - - public void setMaxIdle(int maxIdle) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.maxIdle = maxIdle; - } - - public int getInitialSize() { - return initialSize; - } - - public void setInitialSize(int initialSize) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.initialSize = initialSize; - } - - public long getCreateErrorCount() { - return createErrorCount; - } - - public int getMaxActive() { - return maxActive; - } - - public void setMaxActive(int maxActive) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.maxActive = maxActive; - } - - public String getUsername() { - return user; - } - - public void setUsername(String user) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.user = user; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.password = password; - } - - public Properties getProperties() { - return properties; - } - - public void setProperties(Properties properties) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.properties = properties; - } - - public String getUrl() { - return jdbcUrl; - } - - public String getRawJdbcUrl() { - return jdbcUrl; - } - - public void setUrl(String jdbcUrl) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.jdbcUrl = jdbcUrl; - } - - public String getDriverClassName() { - return driverClass; - } - - public void setDriverClassName(String driverClass) { - if (inited) { - throw new UnsupportedOperationException(); - } - - this.driverClass = driverClass; - } - - @Override - public PrintWriter getLogWriter() throws SQLException { - return logWriter; - } - - @Override - public void setLogWriter(PrintWriter out) throws SQLException { - this.logWriter = out; - } - - @Override - public void setLoginTimeout(int seconds) throws SQLException { - - } - - @Override - public int getLoginTimeout() throws SQLException { - return 0; - } - - @Override - public T unwrap(Class iface) throws SQLException { - return null; - } - - @Override - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } - - protected void initConnectionFactory() { - connectionFactory = new DruidPoolConnectionFactory(this); - } - - public Driver getDriver() { - return driver; - } - - @Override - public List getFilters() { - return filters; - } - - public long getCreateTimespanNano() { - return createTimespan; - } - - public long getCreateTimespanMillis() { - return createTimespan / (1000 * 1000); - } - - abstract void incrementCreateCount(); - - public static class DruidPoolConnectionFactory implements ConnectionFactory { - - private final String url; - private final Properties info; - private final DruidDataAbstractSource dataSource; - - public DruidPoolConnectionFactory(DruidDataAbstractSource dataSource){ - this.dataSource = dataSource; - this.url = dataSource.getUrl(); - - Properties properties = dataSource.getProperties(); - String user; - if (dataSource.getUserCallback() != null) { - user = dataSource.getUserCallback().getName(); - } else { - user = dataSource.getUsername(); - } - - String password; - if (dataSource.getPasswordCallback() != null) { - password = new String(dataSource.getPasswordCallback().getPassword()); - } else { - password = dataSource.getPassword(); - } - - this.info = new Properties(dataSource.getProperties()); - - if (properties != null) { - info.putAll(properties); - } - - if ((!info.contains("user")) && user != null) { - info.put("user", user); - } - - if ((!info.contains("password")) && password != null) { - info.put("password", password); - } - } - - public String getUrl() { - return url; - } - - public Properties getInfo() { - return info; - } - - @Override - public Connection createConnection() throws SQLException { - Connection conn; - - long startNano = System.nanoTime(); - - try { - if (dataSource.getFilters().size() != 0) { - conn = new FilterChainImpl(dataSource).connection_connect(info); - } else { - conn = dataSource.getDriver().connect(url, info); - } - - conn.setAutoCommit(dataSource.isDefaultAutoCommit()); - if (dataSource.getDefaultReadOnly() != null) { - conn.setReadOnly(dataSource.getDefaultReadOnly()); - } - - if (dataSource.getDefaultTransactionIsolation() != null) { - conn.setTransactionIsolation(dataSource.getDefaultTransactionIsolation()); - } - - if (dataSource.getDefaultCatalog() != null && dataSource.getDefaultCatalog().length() != 0) { - conn.setCatalog(dataSource.getDefaultCatalog()); - } - } catch (SQLException ex) { - dataSource.createErrorCount++; - throw ex; - } catch (RuntimeException ex) { - dataSource.createErrorCount++; - throw ex; - } catch (Error ex) { - dataSource.createErrorCount++; - throw ex; - } finally { - long nano = System.nanoTime() - startNano; - dataSource.createTimespan += nano; - } - - dataSource.incrementCreateCount(); - - return conn; - } - } -} +package com.alibaba.druid.pool; + +import java.io.PrintWriter; +import java.io.Serializable; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.sql.DataSource; + +import com.alibaba.druid.filter.Filter; +import com.alibaba.druid.filter.FilterChainImpl; +import com.alibaba.druid.proxy.jdbc.DataSourceProxy; + +/** + * @author wenshao + */ +public abstract class DruidDataAbstractSource implements DataSource, DataSourceProxy, Serializable { + + private static final long serialVersionUID = 1L; + + public final static int DEFAULT_INITIAL_SIZE = 0; + public final static int DEFAULT_MAX_ACTIVE_SIZE = 8; + public final static int DEFAULT_MAX_IDLE = 8; + public final static int DEFAULT_MIN_IDLE = 0; + public final static int DEFAULT_MAX_WAIT = -1; + public final static String DEFAULT_VALIDATION_QUERY = "SELECT 1"; + public final static boolean DEFAULT_TEST_ON_BORROW = true; + public final static boolean DEFAULT_TEST_ON_RETURN = false; + public final static boolean DEFAULT_WHILE_IDLE = false; + + private boolean defaultAutoCommit = false; + private Boolean defaultReadOnly; + private Integer defaultTransactionIsolation; + private String defaultCatalog = null; + + protected String name; + + protected String user; + protected String password; + protected String jdbcUrl; + protected String driverClass; + protected Properties properties = new Properties(); + + protected PasswordCallback passwordCallback; + protected NameCallback userCallback; + + protected ConnectionFactory connectionFactory; + + protected int initialSize = DEFAULT_INITIAL_SIZE; + protected int maxActive = DEFAULT_MAX_ACTIVE_SIZE; + protected int minIdle = DEFAULT_MIN_IDLE; + protected int maxIdle = DEFAULT_MAX_IDLE; + protected long maxWait = DEFAULT_MAX_WAIT; + + protected String validationQuery = DEFAULT_VALIDATION_QUERY; + private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; + private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; + private boolean testWhileIdle = DEFAULT_WHILE_IDLE; + protected boolean poolPreparedStatements = false; + + protected boolean inited = false; + + protected PrintWriter logWriter = new PrintWriter(System.out); + + private final List filters = new ArrayList(); + + protected Driver driver; + + protected int queryTimeout; + + protected long createErrorCount; + + protected long createTimespan; + + protected int maxWaitThreadCount = -1; + + public int getMaxWaitThreadCount() { + return maxWaitThreadCount; + } + + public void setMaxWaitThreadCount(int maxWaithThreadCount) { + this.maxWaitThreadCount = maxWaithThreadCount; + } + + public String getValidationQuery() { + return validationQuery; + } + + public void setValidationQuery(String validationQuery) { + this.validationQuery = validationQuery; + } + + public boolean isTestOnBorrow() { + return testOnBorrow; + } + + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public boolean isTestOnReturn() { + return testOnReturn; + } + + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + public boolean isTestWhileIdle() { + return testWhileIdle; + } + + public void setTestWhileIdle(boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + public boolean isDefaultAutoCommit() { + return defaultAutoCommit; + } + + public void setDefaultAutoCommit(boolean defaultAutoCommit) { + this.defaultAutoCommit = defaultAutoCommit; + } + + public Boolean getDefaultReadOnly() { + return defaultReadOnly; + } + + public void setDefaultReadOnly(Boolean defaultReadOnly) { + this.defaultReadOnly = defaultReadOnly; + } + + public Integer getDefaultTransactionIsolation() { + return defaultTransactionIsolation; + } + + public void setDefaultTransactionIsolation(Integer defaultTransactionIsolation) { + this.defaultTransactionIsolation = defaultTransactionIsolation; + } + + public String getDefaultCatalog() { + return defaultCatalog; + } + + public void setDefaultCatalog(String defaultCatalog) { + this.defaultCatalog = defaultCatalog; + } + + public PasswordCallback getPasswordCallback() { + return passwordCallback; + } + + public void setPasswordCallback(PasswordCallback passwordCallback) { + this.passwordCallback = passwordCallback; + } + + public NameCallback getUserCallback() { + return userCallback; + } + + public void setUserCallback(NameCallback userCallback) { + this.userCallback = userCallback; + } + + /** + * Retrieves the number of seconds the driver will wait for a Statement object to execute. If the limit + * is exceeded, a SQLException is thrown. + * + * @return the current query timeout limit in seconds; zero means there is no limit + * @exception SQLException if a database access error occurs or this method is called on a closed + * Statement + * @see #setQueryTimeout + */ + public int getQueryTimeout() { + return queryTimeout; + } + + /** + * Sets the number of seconds the driver will wait for a Statement object to execute to the given + * number of seconds. If the limit is exceeded, an SQLException is thrown. A JDBC driver must apply + * this limit to the execute, executeQuery and executeUpdate methods. JDBC + * driver implementations may also apply this limit to ResultSet methods (consult your driver vendor + * documentation for details). + * + * @param seconds the new query timeout limit in seconds; zero means there is no limit + * @exception SQLException if a database access error occurs, this method is called on a closed + * Statement or the condition seconds >= 0 is not satisfied + * @see #getQueryTimeout + */ + public void setQueryTimeout(int seconds) { + this.queryTimeout = seconds; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isPoolPreparedStatements() { + return poolPreparedStatements; + } + + public void setPoolPreparedStatements(boolean poolPreparedStatements) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.poolPreparedStatements = poolPreparedStatements; + } + + public long getMaxWait() { + return maxWait; + } + + public void setMaxWait(long maxWait) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.maxWait = maxWait; + } + + public int getMinIdle() { + return minIdle; + } + + public void setMinIdle(int minIdle) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.minIdle = minIdle; + } + + public int getMaxIdle() { + return maxIdle; + } + + public void setMaxIdle(int maxIdle) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.maxIdle = maxIdle; + } + + public int getInitialSize() { + return initialSize; + } + + public void setInitialSize(int initialSize) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.initialSize = initialSize; + } + + public long getCreateErrorCount() { + return createErrorCount; + } + + public int getMaxActive() { + return maxActive; + } + + public void setMaxActive(int maxActive) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.maxActive = maxActive; + } + + public String getUsername() { + return user; + } + + public void setUsername(String user) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.user = user; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.password = password; + } + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties properties) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.properties = properties; + } + + public String getUrl() { + return jdbcUrl; + } + + public String getRawJdbcUrl() { + return jdbcUrl; + } + + public void setUrl(String jdbcUrl) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.jdbcUrl = jdbcUrl; + } + + public String getDriverClassName() { + return driverClass; + } + + public void setDriverClassName(String driverClass) { + if (inited) { + throw new UnsupportedOperationException(); + } + + this.driverClass = driverClass; + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return logWriter; + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + this.logWriter = out; + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + + } + + @Override + public int getLoginTimeout() throws SQLException { + return 0; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + protected void initConnectionFactory() { + connectionFactory = new DruidPoolConnectionFactory(this); + } + + public Driver getDriver() { + return driver; + } + + @Override + public List getFilters() { + return filters; + } + + public long getCreateTimespanNano() { + return createTimespan; + } + + public long getCreateTimespanMillis() { + return createTimespan / (1000 * 1000); + } + + abstract void incrementCreateCount(); + + public static class DruidPoolConnectionFactory implements ConnectionFactory { + + private final String url; + private final Properties info; + private final DruidDataAbstractSource dataSource; + + public DruidPoolConnectionFactory(DruidDataAbstractSource dataSource){ + this.dataSource = dataSource; + this.url = dataSource.getUrl(); + + Properties properties = dataSource.getProperties(); + String user; + if (dataSource.getUserCallback() != null) { + user = dataSource.getUserCallback().getName(); + } else { + user = dataSource.getUsername(); + } + + String password; + if (dataSource.getPasswordCallback() != null) { + password = new String(dataSource.getPasswordCallback().getPassword()); + } else { + password = dataSource.getPassword(); + } + + this.info = new Properties(dataSource.getProperties()); + + if (properties != null) { + info.putAll(properties); + } + + if ((!info.contains("user")) && user != null) { + info.put("user", user); + } + + if ((!info.contains("password")) && password != null) { + info.put("password", password); + } + } + + public String getUrl() { + return url; + } + + public Properties getInfo() { + return info; + } + + @Override + public Connection createConnection() throws SQLException { + Connection conn; + + long startNano = System.nanoTime(); + + try { + if (dataSource.getFilters().size() != 0) { + conn = new FilterChainImpl(dataSource).connection_connect(info); + } else { + conn = dataSource.getDriver().connect(url, info); + } + + conn.setAutoCommit(dataSource.isDefaultAutoCommit()); + if (dataSource.getDefaultReadOnly() != null) { + conn.setReadOnly(dataSource.getDefaultReadOnly()); + } + + if (dataSource.getDefaultTransactionIsolation() != null) { + conn.setTransactionIsolation(dataSource.getDefaultTransactionIsolation()); + } + + if (dataSource.getDefaultCatalog() != null && dataSource.getDefaultCatalog().length() != 0) { + conn.setCatalog(dataSource.getDefaultCatalog()); + } + } catch (SQLException ex) { + dataSource.createErrorCount++; + throw ex; + } catch (RuntimeException ex) { + dataSource.createErrorCount++; + throw ex; + } catch (Error ex) { + dataSource.createErrorCount++; + throw ex; + } finally { + long nano = System.nanoTime() - startNano; + dataSource.createTimespan += nano; + } + + dataSource.incrementCreateCount(); + + return conn; + } + } +} diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index e5a628c050..77d143db4d 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -1,611 +1,612 @@ /* - * Copyright 2011 Alibaba Group. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2011 Alibaba Group. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this + * file except in compliance with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and limitations under the + * License. */ -package com.alibaba.druid.pool; - -import java.sql.Connection; -import java.sql.Driver; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -import javax.naming.NamingException; -import javax.naming.Reference; -import javax.naming.Referenceable; -import javax.naming.StringRefAddr; - -import com.alibaba.druid.proxy.jdbc.DataSourceProxyConfig; -import com.alibaba.druid.util.JdbcUtils; - -/** - * @author wenshao - */ -public class DruidDataSource extends DruidDataAbstractSource implements DruidDataSourceMBean, Referenceable { - - private static final long serialVersionUID = 1L; - - private final ReentrantLock lock = new ReentrantLock(); - - private final Condition notEmpty = lock.newCondition(); - private final Condition notFullActive = lock.newCondition(); - private final Condition lowWater = lock.newCondition(); - private final Condition highWater = lock.newCondition(); - private final Condition idleTimeout = lock.newCondition(); - - // stats - private long connectCount = 0; - private long closeCount = 0; - private long connectErrorCount = 0; - private long recycleCount = 0; - private long createConnectionCount = 0L; - private long destroyCount = 0; - - // store - private ConnectionHolder[] connections; - private int count = 0; - private int activeCount = 0; - - // threads - private CreateConnectionThread createConnectionThread; - private DestroyConnectionThread destoryConnectionThread; - - private boolean activeConnectionTraceEnable = false; - - private final IdentityHashMap activeConnections = new IdentityHashMap(); - - public DruidDataSource(){ - } - - private void init() throws SQLException { - if (inited) { - return; - } - - try { - lock.lockInterruptibly(); - - if (inited) { - return; - } - - if (this.driverClass != null) { - this.driverClass = driverClass.trim(); - } - - if (this.jdbcUrl != null) { - this.jdbcUrl = this.jdbcUrl.trim(); - } - - if (this.driverClass == null || this.driverClass.isEmpty()) { - this.driverClass = JdbcUtils.getDriverClassName(this.jdbcUrl); - } - - try { - driver = (Driver) Class.forName(this.driverClass).newInstance(); - } catch (IllegalAccessException e) { - throw new SQLException(e.getMessage(), e); - } catch (InstantiationException e) { - throw new SQLException(e.getMessage(), e); - } catch (ClassNotFoundException e) { - throw new SQLException(e.getMessage(), e); - } - - initConnectionFactory(); - - if (maxIdle <= 0 || maxIdle < minIdle) { - throw new IllegalArgumentException("illegal maxPoolSize"); - } - - int capacity = maxIdle + maxActive; - - if (capacity < getInitialSize()) { - capacity = getInitialSize(); - } - - connections = new ConnectionHolder[capacity]; - // pool = new ConnectionPool(this, this.minIdle, this.maxIdle, - // this.maxActive, this.maxIdleTimeMillis); - - for (int i = 0, size = getInitialSize(); i < size; ++i) { - Connection conn = connectionFactory.createConnection(); - conn.setAutoCommit(true); - connections[count++] = new ConnectionHolder(this, conn); - } - - createConnectionThread = new CreateConnectionThread("Druid-ConnectionPool-Create"); - destoryConnectionThread = new DestroyConnectionThread("Druid-ConnectionPool-Destory"); - - createConnectionThread.start(); - destoryConnectionThread.start(); - - inited = true; - } catch (InterruptedException e) { - throw new SQLException(e.getMessage(), e); - } finally { - lock.unlock(); - } - } - - public boolean isActiveConnectionTraceEnable() { - return activeConnectionTraceEnable; - } - - public void setActiveConnectionTraceEnable(boolean connectionTraceEnable) { - this.activeConnectionTraceEnable = connectionTraceEnable; - } - - public Set getActiveConnections() { - return this.activeConnections.keySet(); - } - - private boolean testConnection(Connection conn) { - String query = getValidationQuery(); - if (query == null || query.length() == 0) { - return true; - } - - Statement stmt = null; - ResultSet rs = null; - try { - stmt = conn.createStatement(); - rs = stmt.executeQuery(query); - if (rs.next()) { - return true; - } else { - return false; - } - } catch (SQLException e) { - return false; - } finally { - JdbcUtils.close(rs); - JdbcUtils.close(stmt); - } - } - - @Override - public Connection getConnection() throws SQLException { - init(); - - try { - lock.lockInterruptibly(); - - connectCount++; - - ConnectionHolder holder; - for (;;) { - if (maxWait > 0) { - holder = pollLast(maxWait, TimeUnit.MILLISECONDS); - } else { - holder = takeLast(); - } - - if (holder == null) { - throw new SQLException("can not get connection"); - } - - if (isTestOnBorrow()) { - boolean validate = testConnection(holder.getConnection()); - if (!validate) { - continue; - } - } - - break; - } - - holder.incrementUseCount(); - activeCount++; - - PoolableConnection poolalbeConnection = new PoolableConnection(holder); - - if (activeConnectionTraceEnable) { - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - activeConnections.put(poolalbeConnection, - new ActiveConnectionTraceInfo(poolalbeConnection, System.currentTimeMillis(), - stackTrace)); - } - - return poolalbeConnection; - } catch (InterruptedException e) { - connectErrorCount++; - throw new SQLException(e.getMessage(), e); - } catch (SQLException e) { - connectErrorCount++; - throw e; - } finally { - lock.unlock(); - } - } - - /** - * 回收连接 - */ - void recycle(PoolableConnection pooledConnection) throws SQLException { - final Connection conn = pooledConnection.getConnection(); - try { - if (activeConnectionTraceEnable) { - activeConnections.remove(pooledConnection); - } - - // 第一步,检查连接是否关闭 - if (conn == null || conn.isClosed()) { - lock.lock(); - try { - decrementActiveCount(); - closeCount++; - } finally { - lock.unlock(); - } - return; - } - - if (isTestOnReturn()) { - boolean validate = testConnection(conn); - if (!validate) { - return; - } - } - - boolean isAutoCommit = conn.getAutoCommit(); - boolean isReadOnly = conn.isReadOnly(); - - // 第二步,检查是否需要回滚 - if ((!isAutoCommit) && (!isReadOnly)) { - conn.rollback(); - } - - // 第三步,清楚警告信息,重设autoCommit为true - conn.clearWarnings(); - if (!isAutoCommit) { - conn.setAutoCommit(true); - } - - lock.lockInterruptibly(); - try { - decrementActiveCount(); - closeCount++; - - // 第四部,加入队列中(putLast) - putLast(pooledConnection.getConnectionHolder()); - recycleCount++; - } finally { - lock.unlock(); - } - } catch (InterruptedException e) { - if (!conn.isClosed()) { - conn.close(); - } - - throw new SQLException(e.getMessage(), e); - } catch (SQLException e) { - lock.lock(); - try { - decrementActiveCount(); - closeCount++; - } finally { - lock.unlock(); - } - - throw e; - } - } - - /** - * close datasource - */ - public void close() { - lock.lock(); - try { - createConnectionThread.interrupt(); - destoryConnectionThread.interrupt(); - - for (int i = 0; i < count; ++i) { - try { - connections[i].getConnection().close(); - connections[i] = null; - destroyCount++; - } catch (Exception ex) { - // skip it - } - } - count = 0; - } finally { - lock.unlock(); - } - } - - void incrementCreateCount() { - createConnectionCount++; - } - - void decrementActiveCount() { - activeCount--; - notFullActive.signal(); - } - - void decrementActiveCountWithLock() { - lock.lock(); - try { - decrementActiveCount(); - } finally { - lock.unlock(); - } - } - - void putLast(ConnectionHolder e) throws InterruptedException { - if (e == null) { - throw new NullPointerException(); - } - - connections[count++] = e; - - if (count == maxIdle + 1) { - highWater.signal(); - } - - notEmpty.signal(); - } - - ConnectionHolder takeLast() throws InterruptedException { - while (activeCount >= maxActive) { - notFullActive.await(); - } - - try { - while (count == 0) { - notEmpty.await(); - } - } catch (InterruptedException ie) { - notEmpty.signal(); // propagate to non-interrupted thread - throw ie; - } - - int lastIndex = count - 1; - ConnectionHolder last = connections[lastIndex]; - connections[lastIndex] = null; - count--; - - if (lastIndex <= minIdle - 1) { - lowWater.signal(); - } - - return last; - } - - ConnectionHolder pollLast(long timeout, TimeUnit unit) throws InterruptedException { - long nanos = unit.toNanos(timeout); - - for (;;) { - if (activeCount == maxActive) { - long startNano = System.nanoTime(); - notFullActive.awaitNanos(nanos); - nanos -= (System.nanoTime() - startNano); - } - - if (count == 0) { - notEmpty.awaitNanos(nanos); - - if (count == 0) { - return null; - } - } - - int lastIndex = count - 1; - ConnectionHolder last = connections[lastIndex]; - connections[lastIndex] = null; - count--; - - if (lastIndex == minIdle - 1) { - lowWater.signal(); - } - - return last; - } - } - - @Override - public Connection getConnection(String username, String password) throws SQLException { - throw new UnsupportedOperationException("Not supported by DruidDataSource"); - } - - public long getCreateCount() { - return createConnectionCount; - } - - public long getDestroyCount() { - return destroyCount; - } - - public long getConnectCount() { - return connectCount; - } - - public long getCloseCount() { - return closeCount; - } - - public long getConnectErrorCount() { - return connectErrorCount; - } - - @Override - public int getPoolingSize() { - return count; - } - - public long getRecycleCount() { - return recycleCount; - } - - public int getActiveCount() { - return activeCount; - } - - public class CreateConnectionThread extends Thread { - - public CreateConnectionThread(String name){ - super(name); - } - - public void run() { - for (;;) { - // addLast - lock.lock(); - try { - if (count >= minIdle) { - lowWater.await(); - } - - Connection connection = connectionFactory.createConnection(); - ConnectionHolder poolableConnection = new ConnectionHolder(DruidDataSource.this, connection); - connections[count++] = poolableConnection; - - if (count == 1) { - notEmpty.signal(); - } - - } catch (InterruptedException e) { - break; - } catch (SQLException e) { - e.printStackTrace(); - } finally { - lock.unlock(); - } - } - } - } - - public class DestroyConnectionThread extends Thread { - - public DestroyConnectionThread(String name){ - super(name); - } - - public void run() { - for (;;) { - // 从前面开始删除 - - try { - ConnectionHolder first = null; - lock.lock(); - try { - if (count <= maxIdle) { - highWater.await(); - continue; - } - - first = connections[0]; - - long millis = System.currentTimeMillis() - first.getTimeMillis(); - if (millis > 0) { - idleTimeout.await(millis, TimeUnit.MILLISECONDS); - continue; - } - - System.arraycopy(connections, 1, connections, 0, count - 1); - connections[count - 1] = null; - } finally { - lock.unlock(); - } - - Connection connection = first.getConnection(); - try { - connection.close(); - } catch (SQLException e) { - e.printStackTrace(); // TODO - } - - destroyCount++; - } catch (InterruptedException e) { - break; - } - } - } - } - - public DataSourceProxyConfig getConfig() { - return null; - } - - @Override - public Driver getRawDriver() { - return driver; - } - - void initStatement(Statement stmt) throws SQLException { - if (queryTimeout > 0) { - stmt.setQueryTimeout(queryTimeout); - } - } - - /** Instance key */ - protected String instanceKey = null; - - public Reference getReference() throws NamingException { - final String className = getClass().getName(); - final String factoryName = className + "Factory"; // XXX: not robust - Reference ref = new Reference(className, factoryName, null); - ref.add(new StringRefAddr("instanceKey", instanceKey)); - return ref; - } - - static class ActiveConnectionTraceInfo { - - private final PoolableConnection connection; - private final long connectTime; - private final StackTraceElement[] stackTrace; - - public ActiveConnectionTraceInfo(PoolableConnection connection, long connectTime, StackTraceElement[] stackTrace){ - super(); - this.connection = connection; - this.connectTime = connectTime; - this.stackTrace = stackTrace; - } - - public PoolableConnection getConnection() { - return connection; - } - - public long getConnectTime() { - return connectTime; - } - - public StackTraceElement[] getStackTrace() { - return stackTrace; - } - } - - @Override - public List getActiveConnectionStackTrace() { - List list = new ArrayList(); - for (ActiveConnectionTraceInfo traceInfo : this.activeConnections.values()) { - StringBuilder buf = new StringBuilder(); - for (StackTraceElement item : traceInfo.getStackTrace()) { - buf.append(item.toString()); - buf.append("\n"); - } - list.add(buf.toString()); - } - - return list; - } -} +package com.alibaba.druid.pool; + +import java.sql.Connection; +import java.sql.Driver; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.Referenceable; +import javax.naming.StringRefAddr; + +import com.alibaba.druid.proxy.jdbc.DataSourceProxyConfig; +import com.alibaba.druid.util.JdbcUtils; + +/** + * @author wenshao + */ +public class DruidDataSource extends DruidDataAbstractSource implements DruidDataSourceMBean, Referenceable { + + private static final long serialVersionUID = 1L; + + private final ReentrantLock lock = new ReentrantLock(); + + private final Condition notEmpty = lock.newCondition(); + private final Condition notFullActive = lock.newCondition(); + private final Condition lowWater = lock.newCondition(); + private final Condition highWater = lock.newCondition(); + private final Condition idleTimeout = lock.newCondition(); + + // stats + private long connectCount = 0; + private long closeCount = 0; + private long connectErrorCount = 0; + private long recycleCount = 0; + private long createConnectionCount = 0L; + private long destroyCount = 0; + + // store + private ConnectionHolder[] connections; + private int count = 0; + private int activeCount = 0; + + // threads + private CreateConnectionThread createConnectionThread; + private DestroyConnectionThread destoryConnectionThread; + + private boolean activeConnectionTraceEnable = false; + + private final IdentityHashMap activeConnections = new IdentityHashMap(); + + public DruidDataSource(){ + } + + private void init() throws SQLException { + if (inited) { + return; + } + + try { + int maxWaitThreadCount = getMaxWaitThreadCount(); + if (maxWaitThreadCount > 0) { + if (lock.getQueueLength() > maxWaitThreadCount) { + throw new SQLException("maxWaitThreadCount " + maxWaitThreadCount + ", current wait Thread count " + + lock.getQueueLength()); + } + } + + lock.lockInterruptibly(); + + if (inited) { + return; + } + + if (this.driverClass != null) { + this.driverClass = driverClass.trim(); + } + + if (this.jdbcUrl != null) { + this.jdbcUrl = this.jdbcUrl.trim(); + } + + if (this.driverClass == null || this.driverClass.isEmpty()) { + this.driverClass = JdbcUtils.getDriverClassName(this.jdbcUrl); + } + + try { + driver = (Driver) Class.forName(this.driverClass).newInstance(); + } catch (IllegalAccessException e) { + throw new SQLException(e.getMessage(), e); + } catch (InstantiationException e) { + throw new SQLException(e.getMessage(), e); + } catch (ClassNotFoundException e) { + throw new SQLException(e.getMessage(), e); + } + + initConnectionFactory(); + + if (maxIdle <= 0 || maxIdle < minIdle) { + throw new IllegalArgumentException("illegal maxPoolSize"); + } + + int capacity = maxIdle + maxActive; + + if (capacity < getInitialSize()) { + capacity = getInitialSize(); + } + + connections = new ConnectionHolder[capacity]; + // pool = new ConnectionPool(this, this.minIdle, this.maxIdle, + // this.maxActive, this.maxIdleTimeMillis); + + for (int i = 0, size = getInitialSize(); i < size; ++i) { + Connection conn = connectionFactory.createConnection(); + conn.setAutoCommit(true); + connections[count++] = new ConnectionHolder(this, conn); + } + + createConnectionThread = new CreateConnectionThread("Druid-ConnectionPool-Create"); + destoryConnectionThread = new DestroyConnectionThread("Druid-ConnectionPool-Destory"); + + createConnectionThread.start(); + destoryConnectionThread.start(); + + inited = true; + } catch (InterruptedException e) { + throw new SQLException(e.getMessage(), e); + } finally { + lock.unlock(); + } + } + + public boolean isActiveConnectionTraceEnable() { + return activeConnectionTraceEnable; + } + + public void setActiveConnectionTraceEnable(boolean connectionTraceEnable) { + this.activeConnectionTraceEnable = connectionTraceEnable; + } + + public Set getActiveConnections() { + return this.activeConnections.keySet(); + } + + private boolean testConnection(Connection conn) { + String query = getValidationQuery(); + if (query == null || query.length() == 0) { + return true; + } + + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(query); + if (rs.next()) { + return true; + } else { + return false; + } + } catch (SQLException e) { + return false; + } finally { + JdbcUtils.close(rs); + JdbcUtils.close(stmt); + } + } + + @Override + public Connection getConnection() throws SQLException { + init(); + + try { + lock.lockInterruptibly(); + + connectCount++; + + ConnectionHolder holder; + for (;;) { + if (maxWait > 0) { + holder = pollLast(maxWait, TimeUnit.MILLISECONDS); + } else { + holder = takeLast(); + } + + if (holder == null) { + throw new SQLException("can not get connection"); + } + + if (isTestOnBorrow()) { + boolean validate = testConnection(holder.getConnection()); + if (!validate) { + continue; + } + } + + break; + } + + holder.incrementUseCount(); + activeCount++; + + PoolableConnection poolalbeConnection = new PoolableConnection(holder); + + if (activeConnectionTraceEnable) { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + activeConnections.put(poolalbeConnection, + new ActiveConnectionTraceInfo(poolalbeConnection, System.currentTimeMillis(), + stackTrace)); + } + + return poolalbeConnection; + } catch (InterruptedException e) { + connectErrorCount++; + throw new SQLException(e.getMessage(), e); + } catch (SQLException e) { + connectErrorCount++; + throw e; + } finally { + lock.unlock(); + } + } + + /** + * 回收连接 + */ + void recycle(PoolableConnection pooledConnection) throws SQLException { + final Connection conn = pooledConnection.getConnection(); + try { + if (activeConnectionTraceEnable) { + activeConnections.remove(pooledConnection); + } + + // 第一步,检查连接是否关闭 + if (conn == null || conn.isClosed()) { + lock.lock(); + try { + decrementActiveCount(); + closeCount++; + } finally { + lock.unlock(); + } + return; + } + + if (isTestOnReturn()) { + boolean validate = testConnection(conn); + if (!validate) { + return; + } + } + + boolean isAutoCommit = conn.getAutoCommit(); + boolean isReadOnly = conn.isReadOnly(); + + // 第二步,检查是否需要回滚 + if ((!isAutoCommit) && (!isReadOnly)) { + conn.rollback(); + } + + // 第三步,清楚警告信息,重设autoCommit为true + conn.clearWarnings(); + if (!isAutoCommit) { + conn.setAutoCommit(true); + } + + lock.lockInterruptibly(); + try { + decrementActiveCount(); + closeCount++; + + // 第四部,加入队列中(putLast) + putLast(pooledConnection.getConnectionHolder()); + recycleCount++; + } finally { + lock.unlock(); + } + } catch (InterruptedException e) { + if (!conn.isClosed()) { + conn.close(); + } + + throw new SQLException(e.getMessage(), e); + } catch (SQLException e) { + lock.lock(); + try { + decrementActiveCount(); + closeCount++; + } finally { + lock.unlock(); + } + + throw e; + } + } + + /** + * close datasource + */ + public void close() { + lock.lock(); + try { + createConnectionThread.interrupt(); + destoryConnectionThread.interrupt(); + + for (int i = 0; i < count; ++i) { + try { + connections[i].getConnection().close(); + connections[i] = null; + destroyCount++; + } catch (Exception ex) { + // skip it + } + } + count = 0; + } finally { + lock.unlock(); + } + } + + void incrementCreateCount() { + createConnectionCount++; + } + + void decrementActiveCount() { + activeCount--; + notFullActive.signal(); + } + + void decrementActiveCountWithLock() { + lock.lock(); + try { + decrementActiveCount(); + } finally { + lock.unlock(); + } + } + + void putLast(ConnectionHolder e) throws InterruptedException { + if (e == null) { + throw new NullPointerException(); + } + + connections[count++] = e; + + if (count == maxIdle + 1) { + highWater.signal(); + } + + notEmpty.signal(); + } + + ConnectionHolder takeLast() throws InterruptedException { + while (activeCount >= maxActive) { + notFullActive.await(); + } + + try { + while (count == 0) { + notEmpty.await(); + } + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + throw ie; + } + + int lastIndex = count - 1; + ConnectionHolder last = connections[lastIndex]; + connections[lastIndex] = null; + count--; + + if (lastIndex <= minIdle - 1) { + lowWater.signal(); + } + + return last; + } + + ConnectionHolder pollLast(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + + for (;;) { + if (activeCount == maxActive) { + long startNano = System.nanoTime(); + notFullActive.awaitNanos(nanos); + nanos -= (System.nanoTime() - startNano); + } + + if (count == 0) { + notEmpty.awaitNanos(nanos); + + if (count == 0) { + return null; + } + } + + int lastIndex = count - 1; + ConnectionHolder last = connections[lastIndex]; + connections[lastIndex] = null; + count--; + + if (lastIndex == minIdle - 1) { + lowWater.signal(); + } + + return last; + } + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + throw new UnsupportedOperationException("Not supported by DruidDataSource"); + } + + public long getCreateCount() { + return createConnectionCount; + } + + public long getDestroyCount() { + return destroyCount; + } + + public long getConnectCount() { + return connectCount; + } + + public long getCloseCount() { + return closeCount; + } + + public long getConnectErrorCount() { + return connectErrorCount; + } + + @Override + public int getPoolingSize() { + return count; + } + + public long getRecycleCount() { + return recycleCount; + } + + public int getActiveCount() { + return activeCount; + } + + public class CreateConnectionThread extends Thread { + + public CreateConnectionThread(String name){ + super(name); + } + + public void run() { + for (;;) { + // addLast + lock.lock(); + try { + if (count >= minIdle) { + lowWater.await(); + } + + Connection connection = connectionFactory.createConnection(); + ConnectionHolder poolableConnection = new ConnectionHolder(DruidDataSource.this, connection); + connections[count++] = poolableConnection; + + if (count == 1) { + notEmpty.signal(); + } + + } catch (InterruptedException e) { + break; + } catch (SQLException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + } + } + + public class DestroyConnectionThread extends Thread { + + public DestroyConnectionThread(String name){ + super(name); + } + + public void run() { + for (;;) { + // 从前面开始删除 + + try { + ConnectionHolder first = null; + lock.lock(); + try { + if (count <= maxIdle) { + highWater.await(); + continue; + } + + first = connections[0]; + + long millis = System.currentTimeMillis() - first.getTimeMillis(); + if (millis > 0) { + idleTimeout.await(millis, TimeUnit.MILLISECONDS); + continue; + } + + System.arraycopy(connections, 1, connections, 0, count - 1); + connections[count - 1] = null; + } finally { + lock.unlock(); + } + + Connection connection = first.getConnection(); + try { + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); // TODO + } + + destroyCount++; + } catch (InterruptedException e) { + break; + } + } + } + } + + public DataSourceProxyConfig getConfig() { + return null; + } + + @Override + public Driver getRawDriver() { + return driver; + } + + void initStatement(Statement stmt) throws SQLException { + if (queryTimeout > 0) { + stmt.setQueryTimeout(queryTimeout); + } + } + + /** Instance key */ + protected String instanceKey = null; + + public Reference getReference() throws NamingException { + final String className = getClass().getName(); + final String factoryName = className + "Factory"; // XXX: not robust + Reference ref = new Reference(className, factoryName, null); + ref.add(new StringRefAddr("instanceKey", instanceKey)); + return ref; + } + + static class ActiveConnectionTraceInfo { + + private final PoolableConnection connection; + private final long connectTime; + private final StackTraceElement[] stackTrace; + + public ActiveConnectionTraceInfo(PoolableConnection connection, long connectTime, StackTraceElement[] stackTrace){ + super(); + this.connection = connection; + this.connectTime = connectTime; + this.stackTrace = stackTrace; + } + + public PoolableConnection getConnection() { + return connection; + } + + public long getConnectTime() { + return connectTime; + } + + public StackTraceElement[] getStackTrace() { + return stackTrace; + } + } + + @Override + public List getActiveConnectionStackTrace() { + List list = new ArrayList(); + for (ActiveConnectionTraceInfo traceInfo : this.activeConnections.values()) { + StringBuilder buf = new StringBuilder(); + for (StackTraceElement item : traceInfo.getStackTrace()) { + buf.append(item.toString()); + buf.append("\n"); + } + list.add(buf.toString()); + } + + return list; + } +}