aboutsummaryrefslogtreecommitdiffstats
path: root/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
diff options
context:
space:
mode:
Diffstat (limited to 'dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java')
-rw-r--r--dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java795
1 files changed, 795 insertions, 0 deletions
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
new file mode 100644
index 0000000..b704c7f
--- /dev/null
+++ b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
@@ -0,0 +1,795 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openecomp
+ * ================================================================================
+ * Copyright (C) 2016 - 2017 AT&T
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.jdbc.pool;
+
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
+
+import com.mysql.jdbc.Driver;
+
+/**
+ * Represents a pooled connection
+ * and holds a reference to the {@link java.sql.Connection} object
+ * @version 1.0
+ */
+public class PooledConnection {
+ /**
+ * Logger
+ */
+ private static final Log log = LogFactory.getLog(PooledConnection.class);
+
+ public static final String PROP_USER = PoolUtilities.PROP_USER;
+
+ public static final String PROP_PASSWORD = PoolUtilities.PROP_PASSWORD;
+
+ /**
+ * Validate when connection is borrowed flag
+ */
+ public static final int VALIDATE_BORROW = 1;
+ /**
+ * Validate when connection is returned flag
+ */
+ public static final int VALIDATE_RETURN = 2;
+ /**
+ * Validate when connection is idle flag
+ */
+ public static final int VALIDATE_IDLE = 3;
+ /**
+ * Validate when connection is initialized flag
+ */
+ public static final int VALIDATE_INIT = 4;
+ /**
+ * The properties for the connection pool
+ */
+ protected PoolConfiguration poolProperties;
+ /**
+ * The underlying database connection
+ */
+ private volatile java.sql.Connection connection;
+
+ /**
+ * If using a XAConnection underneath.
+ */
+ protected volatile javax.sql.XAConnection xaConnection;
+ /**
+ * When we track abandon traces, this string holds the thread dump
+ */
+ private String abandonTrace = null;
+ /**
+ * Timestamp the connection was last 'touched' by the pool
+ */
+ private volatile long timestamp;
+ /**
+ * Lock for this connection only
+ */
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
+ /**
+ * Set to true if this connection has been discarded by the pool
+ */
+ private volatile boolean discarded = false;
+ /**
+ * The Timestamp when the last time the connect() method was called successfully
+ */
+ private volatile long lastConnected = -1;
+ /**
+ * timestamp to keep track of validation intervals
+ */
+ private volatile long lastValidated = System.currentTimeMillis();
+ /**
+ * The parent
+ */
+ protected ConnectionPool parent;
+
+ private HashMap<Object, Object> attributes = new HashMap<>();
+
+ private volatile long connectionVersion=0;
+
+ /**
+ * Weak reference to cache the list of interceptors for this connection
+ * so that we don't create a new list of interceptors each time we borrow
+ * the connection
+ */
+ private volatile JdbcInterceptor handler = null;
+
+ private AtomicBoolean released = new AtomicBoolean(false);
+
+ private volatile boolean suspect = false;
+
+ private java.sql.Driver driver = null;
+
+ /**
+ * Constructor
+ * @param prop - pool properties
+ * @param parent - the parent connection pool
+ */
+ public PooledConnection(PoolConfiguration prop, ConnectionPool parent) {
+ poolProperties = prop;
+ this.parent = parent;
+ connectionVersion = parent.getPoolVersion();
+ }
+
+ public long getConnectionVersion() {
+ return connectionVersion;
+ }
+
+ /**
+ * @deprecated use {@link #shouldForceReconnect(String, String)}
+ * method kept since it was public, to avoid changing interface.
+ * @param username The user name
+ * @param password The password
+ * @return <code>true</code>if the pool does not need to reconnect
+ */
+ @Deprecated
+ public boolean checkUser(String username, String password) {
+ return !shouldForceReconnect(username, password);
+ }
+
+ /**
+ * Returns true if we must force reconnect based on credentials passed in.
+ * Returns false if {@link PoolConfiguration#isAlternateUsernameAllowed()} method returns false.
+ * Returns false if the username/password has not changed since this connection was connected
+ * @param username the username you wish to connect with, pass in null to accept the default username from {@link PoolConfiguration#getUsername()}
+ * @param password the password you wish to connect with, pass in null to accept the default username from {@link org.apache.tomcat.jdbc.pool.PoolConfiguration#getPassword()}
+ * @return true is the pool must reconnect
+ */
+ public boolean shouldForceReconnect(String username, String password) {
+
+ if (!getPoolProperties().isAlternateUsernameAllowed()) return false;
+
+ if (username==null) username = poolProperties.getUsername();
+ if (password==null) password = poolProperties.getPassword();
+
+ String storedUsr = (String)getAttributes().get(PROP_USER);
+ String storedPwd = (String)getAttributes().get(PROP_PASSWORD);
+
+ boolean noChangeInCredentials = (username==null && storedUsr==null);
+ noChangeInCredentials = (noChangeInCredentials || (username!=null && username.equals(storedUsr)));
+
+ noChangeInCredentials = noChangeInCredentials && ((password==null && storedPwd==null) || (password!=null && password.equals(storedPwd)));
+
+ if (username==null) getAttributes().remove(PROP_USER); else getAttributes().put(PROP_USER, username);
+ if (password==null) getAttributes().remove(PROP_PASSWORD); else getAttributes().put(PROP_PASSWORD, password);
+
+ return !noChangeInCredentials;
+ }
+
+ /**
+ * Connects the underlying connection to the database.
+ * @throws SQLException if the method {@link #release()} has been called.
+ * @throws SQLException if driver instantiation fails
+ * @throws SQLException if a call to {@link java.sql.Driver#connect(String, java.util.Properties)} fails.
+ * @throws SQLException if default properties are configured and a call to
+ * {@link java.sql.Connection#setAutoCommit(boolean)}, {@link java.sql.Connection#setCatalog(String)},
+ * {@link java.sql.Connection#setTransactionIsolation(int)} or {@link java.sql.Connection#setReadOnly(boolean)} fails.
+ */
+ public void connect() throws SQLException {
+ if (released.get()) throw new SQLException("A connection once released, can't be reestablished.");
+ if (connection != null) {
+ try {
+ this.disconnect(false);
+ } catch (Exception x) {
+ log.debug("Unable to disconnect previous connection.", x);
+ } //catch
+ } //end if
+ if (poolProperties.getDataSource()==null && poolProperties.getDataSourceJNDI()!=null) {
+ //TODO lookup JNDI name
+ }
+
+ if (poolProperties.getDataSource()!=null) {
+ connectUsingDataSource();
+ } else {
+ connectUsingDriver();
+ }
+
+ //set up the default state, unless we expect the interceptor to do it
+ if (poolProperties.getJdbcInterceptors()==null || poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getName())<0 ||
+ poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getSimpleName())<0) {
+ if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation());
+ if (poolProperties.getDefaultReadOnly()!=null) connection.setReadOnly(poolProperties.getDefaultReadOnly().booleanValue());
+ if (poolProperties.getDefaultAutoCommit()!=null) connection.setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue());
+ if (poolProperties.getDefaultCatalog()!=null) connection.setCatalog(poolProperties.getDefaultCatalog());
+ }
+ this.discarded = false;
+ this.lastConnected = System.currentTimeMillis();
+ }
+
+ protected void connectUsingDataSource() throws SQLException {
+ String usr = null;
+ String pwd = null;
+ if (getAttributes().containsKey(PROP_USER)) {
+ usr = (String) getAttributes().get(PROP_USER);
+ } else {
+ usr = poolProperties.getUsername();
+ getAttributes().put(PROP_USER, usr);
+ }
+ if (getAttributes().containsKey(PROP_PASSWORD)) {
+ pwd = (String) getAttributes().get(PROP_PASSWORD);
+ } else {
+ pwd = poolProperties.getPassword();
+ getAttributes().put(PROP_PASSWORD, pwd);
+ }
+ if (poolProperties.getDataSource() instanceof javax.sql.XADataSource) {
+ javax.sql.XADataSource xds = (javax.sql.XADataSource)poolProperties.getDataSource();
+ if (usr!=null && pwd!=null) {
+ xaConnection = xds.getXAConnection(usr, pwd);
+ connection = xaConnection.getConnection();
+ } else {
+ xaConnection = xds.getXAConnection();
+ connection = xaConnection.getConnection();
+ }
+ } else if (poolProperties.getDataSource() instanceof javax.sql.DataSource){
+ javax.sql.DataSource ds = (javax.sql.DataSource)poolProperties.getDataSource();
+ if (usr!=null && pwd!=null) {
+ connection = ds.getConnection(usr, pwd);
+ } else {
+ connection = ds.getConnection();
+ }
+ } else if (poolProperties.getDataSource() instanceof javax.sql.ConnectionPoolDataSource){
+ javax.sql.ConnectionPoolDataSource ds = (javax.sql.ConnectionPoolDataSource)poolProperties.getDataSource();
+ if (usr!=null && pwd!=null) {
+ connection = ds.getPooledConnection(usr, pwd).getConnection();
+ } else {
+ connection = ds.getPooledConnection().getConnection();
+ }
+ } else {
+ throw new SQLException("DataSource is of unknown class:"+(poolProperties.getDataSource()!=null?poolProperties.getDataSource().getClass():"null"));
+ }
+ }
+ protected void connectUsingDriver() throws SQLException {
+
+ try {
+ Class.forName("com.mysql.jdbc.Driver") ;
+ Driver dr = new com.mysql.jdbc.Driver();
+ if(dr == null)
+ log.warn("Driver NOT CREATED");
+ } catch (ClassNotFoundException e) {
+ log.warn("Driver NOT CREATED", e);
+ }
+
+ try {
+ if (driver==null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Instantiating driver using class: "+poolProperties.getDriverClassName()+" [url="+poolProperties.getUrl()+"]");
+ }
+ if (poolProperties.getDriverClassName()==null) {
+ //rely on DriverManager
+ log.warn("Not loading a JDBC driver as driverClassName property is null.");
+ } else {
+ driver = (java.sql.Driver)
+ ClassLoaderUtil.loadClass(
+ poolProperties.getDriverClassName(),
+ PooledConnection.class.getClassLoader(),
+ Thread.currentThread().getContextClassLoader()
+ ).newInstance();
+ }
+ }
+ } catch (java.lang.Exception cn) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to instantiate JDBC driver.", cn);
+ }
+ SQLException ex = new SQLException(cn.getMessage());
+ ex.initCause(cn);
+ throw ex;
+ }
+ String driverURL = poolProperties.getUrl();
+ String usr = null;
+ String pwd = null;
+ if (getAttributes().containsKey(PROP_USER)) {
+ usr = (String) getAttributes().get(PROP_USER);
+ } else {
+ usr = poolProperties.getUsername();
+ getAttributes().put(PROP_USER, usr);
+ }
+ if (getAttributes().containsKey(PROP_PASSWORD)) {
+ pwd = (String) getAttributes().get(PROP_PASSWORD);
+ } else {
+ pwd = poolProperties.getPassword();
+ getAttributes().put(PROP_PASSWORD, pwd);
+ }
+ Properties properties = PoolUtilities.clone(poolProperties.getDbProperties());
+ if (usr != null) properties.setProperty(PROP_USER, usr);
+ if (pwd != null) properties.setProperty(PROP_PASSWORD, pwd);
+
+ try {
+ if (driver==null) {
+ connection = DriverManager.getConnection(driverURL, properties);
+ } else {
+ connection = driver.connect(driverURL, properties);
+ }
+ } catch (Exception x) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to connect to database.", x);
+ }
+ if (parent.jmxPool!=null) {
+ parent.jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_CONNECT,
+ ConnectionPool.getStackTrace(x));
+ }
+ if (x instanceof SQLException) {
+ throw (SQLException)x;
+ } else {
+ SQLException ex = new SQLException(x.getMessage());
+ ex.initCause(x);
+ throw ex;
+ }
+ }
+ if (connection==null) {
+ throw new SQLException("Driver:"+driver+" returned null for URL:"+driverURL);
+ }
+ }
+
+ /**
+ *
+ * @return true if connect() was called successfully and disconnect has not yet been called
+ */
+ public boolean isInitialized() {
+ return connection!=null;
+ }
+
+ /**
+ * Returns true if the connection has been connected more than
+ * {@link PoolConfiguration#getMaxAge()} milliseconds. false otherwise.
+ * @return Returns true if the connection has been connected more than
+ * {@link PoolConfiguration#getMaxAge()} milliseconds. false otherwise.
+ */
+ public boolean isMaxAgeExpired() {
+ if (getPoolProperties().getMaxAge()>0 ) {
+ return (System.currentTimeMillis() - getLastConnected()) > getPoolProperties().getMaxAge();
+ } else {
+ return false;
+ }
+ }
+ /**
+ * Issues a call to {@link #disconnect(boolean)} with the argument false followed by a call to
+ * {@link #connect()}
+ * @throws SQLException if the call to {@link #connect()} fails.
+ */
+ public void reconnect() throws SQLException {
+ this.disconnect(false);
+ this.connect();
+ } //reconnect
+
+ /**
+ * Disconnects the connection. All exceptions are logged using debug level.
+ * @param finalize if set to true, a call to {@link ConnectionPool#finalize(PooledConnection)} is called.
+ */
+ private void disconnect(boolean finalize) {
+ if (isDiscarded() && connection == null) {
+ return;
+ }
+ setDiscarded(true);
+ if (connection != null) {
+ try {
+ parent.disconnectEvent(this, finalize);
+ if (xaConnection == null) {
+ connection.close();
+ } else {
+ xaConnection.close();
+ }
+ }catch (Exception ignore) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to close underlying SQL connection",ignore);
+ }
+ }
+ }
+ connection = null;
+ xaConnection = null;
+ lastConnected = -1;
+ if (finalize) parent.finalize(this);
+ }
+
+
+//============================================================================
+//
+//============================================================================
+
+ /**
+ * Returns abandon timeout in milliseconds
+ * @return abandon timeout in milliseconds
+ */
+ public long getAbandonTimeout() {
+ if (poolProperties.getRemoveAbandonedTimeout() <= 0) {
+ return Long.MAX_VALUE;
+ } else {
+ return poolProperties.getRemoveAbandonedTimeout() * 1000L;
+ } //end if
+ }
+
+ /**
+ * Returns <code>true</code> if the connection pool is configured
+ * to do validation for a certain action.
+ * @param action The validation action
+ */
+ private boolean doValidate(int action) {
+ if (action == PooledConnection.VALIDATE_BORROW &&
+ poolProperties.isTestOnBorrow())
+ return true;
+ else if (action == PooledConnection.VALIDATE_RETURN &&
+ poolProperties.isTestOnReturn())
+ return true;
+ else if (action == PooledConnection.VALIDATE_IDLE &&
+ poolProperties.isTestWhileIdle())
+ return true;
+ else if (action == PooledConnection.VALIDATE_INIT &&
+ poolProperties.isTestOnConnect())
+ return true;
+ else if (action == PooledConnection.VALIDATE_INIT &&
+ poolProperties.getInitSQL()!=null)
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Returns <code>true</code> if the object is still valid. if not
+ * the pool will call the getExpiredAction() and follow up with one
+ * of the four expired methods
+ * @param validateAction The value
+ * @return <code>true</code> if the connection is valid
+ */
+ public boolean validate(int validateAction) {
+ return validate(validateAction,null);
+ }
+
+ /**
+ * Validates a connection.
+ * @param validateAction the action used. One of {@link #VALIDATE_BORROW}, {@link #VALIDATE_IDLE},
+ * {@link #VALIDATE_INIT} or {@link #VALIDATE_RETURN}
+ * @param sql the SQL to be used during validation. If the {@link PoolConfiguration#setInitSQL(String)} has been called with a non null
+ * value and the action is {@link #VALIDATE_INIT} the init SQL will be used for validation.
+ *
+ * @return true if the connection was validated successfully. It returns true even if validation was not performed, such as when
+ * {@link PoolConfiguration#setValidationInterval(long)} has been called with a positive value.
+ * <p>
+ * false if the validation failed. The caller should close the connection if false is returned since a session could have been left in
+ * an unknown state during initialization.
+ */
+ public boolean validate(int validateAction,String sql) {
+ if (this.isDiscarded()) {
+ return false;
+ }
+
+ if (!doValidate(validateAction)) {
+ //no validation required, no init sql and props not set
+ return true;
+ }
+
+ //Don't bother validating if already have recently enough
+ long now = System.currentTimeMillis();
+ if (validateAction!=VALIDATE_INIT &&
+ poolProperties.getValidationInterval() > 0 &&
+ (now - this.lastValidated) <
+ poolProperties.getValidationInterval()) {
+ return true;
+ }
+
+ if (poolProperties.getValidator() != null) {
+ if (poolProperties.getValidator().validate(connection, validateAction)) {
+ this.lastValidated = now;
+ return true;
+ } else {
+ if (getPoolProperties().getLogValidationErrors()) {
+ log.error("Custom validation through "+poolProperties.getValidator()+" failed.");
+ }
+ return false;
+ }
+ }
+
+ String query = sql;
+
+ if (validateAction == VALIDATE_INIT && poolProperties.getInitSQL() != null) {
+ query = poolProperties.getInitSQL();
+ }
+
+ if (query == null) {
+ query = poolProperties.getValidationQuery();
+ }
+
+ if (query == null) {
+ int validationQueryTimeout = poolProperties.getValidationQueryTimeout();
+ if (validationQueryTimeout < 0) validationQueryTimeout = 0;
+ try {
+ if (connection.isValid(validationQueryTimeout)) {
+ this.lastValidated = now;
+ return true;
+ } else {
+ if (getPoolProperties().getLogValidationErrors()) {
+ log.error("isValid() returned false.");
+ }
+ return false;
+ }
+ } catch (SQLException e) {
+ if (getPoolProperties().getLogValidationErrors()) {
+ log.error("isValid() failed.", e);
+ } else if (log.isDebugEnabled()) {
+ log.debug("isValid() failed.", e);
+ }
+ return false;
+ }
+ }
+
+ Statement stmt = null;
+ try {
+ stmt = connection.createStatement();
+
+ int validationQueryTimeout = poolProperties.getValidationQueryTimeout();
+ if (validationQueryTimeout > 0) {
+ stmt.setQueryTimeout(validationQueryTimeout);
+ }
+
+ stmt.execute(query);
+ stmt.close();
+ this.lastValidated = now;
+ return true;
+ } catch (Exception ex) {
+ if (getPoolProperties().getLogValidationErrors()) {
+ log.warn("SQL Validation error", ex);
+ } else if (log.isDebugEnabled()) {
+ log.debug("Unable to validate object:",ex);
+ }
+ if (stmt!=null)
+ try { stmt.close();} catch (Exception ignore2){/*NOOP*/}
+ }
+ return false;
+ } //validate
+
+ /**
+ * The time limit for how long the object
+ * can remain unused before it is released
+ * @return {@link PoolConfiguration#getMinEvictableIdleTimeMillis()}
+ */
+ public long getReleaseTime() {
+ return this.poolProperties.getMinEvictableIdleTimeMillis();
+ }
+
+ /**
+ * This method is called if (Now - timeCheckedIn &gt; getReleaseTime())
+ * This method disconnects the connection, logs an error in debug mode if it happens
+ * then sets the {@link #released} flag to false. Any attempts to connect this cached object again
+ * will fail per {@link #connect()}
+ * The connection pool uses the atomic return value to decrement the pool size counter.
+ * @return true if this is the first time this method has been called. false if this method has been called before.
+ */
+ public boolean release() {
+ try {
+ disconnect(true);
+ } catch (Exception x) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unable to close SQL connection",x);
+ }
+ }
+ return released.compareAndSet(false, true);
+
+ }
+
+ /**
+ * The pool will set the stack trace when it is check out and
+ * checked in
+ * @param trace the stack trace for this connection
+ */
+
+ public void setStackTrace(String trace) {
+ abandonTrace = trace;
+ }
+
+ /**
+ * Returns the stack trace from when this connection was borrowed. Can return null if no stack trace was set.
+ * @return the stack trace or null of no trace was set
+ */
+ public String getStackTrace() {
+ return abandonTrace;
+ }
+
+ /**
+ * Sets a timestamp on this connection. A timestamp usually means that some operation
+ * performed successfully.
+ * @param timestamp the timestamp as defined by {@link System#currentTimeMillis()}
+ */
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ setSuspect(false);
+ }
+
+
+ public boolean isSuspect() {
+ return suspect;
+ }
+
+ public void setSuspect(boolean suspect) {
+ this.suspect = suspect;
+ }
+
+ /**
+ * An interceptor can call this method with the value true, and the connection will be closed when it is returned to the pool.
+ * @param discarded - only valid value is true
+ * @throws IllegalStateException if this method is called with the value false and the value true has already been set.
+ */
+ public void setDiscarded(boolean discarded) {
+ if (this.discarded && !discarded) throw new IllegalStateException("Unable to change the state once the connection has been discarded");
+ this.discarded = discarded;
+ }
+
+ /**
+ * Set the timestamp the connection was last validated.
+ * This flag is used to keep track when we are using a {@link PoolConfiguration#setValidationInterval(long) validation-interval}.
+ * @param lastValidated a timestamp as defined by {@link System#currentTimeMillis()}
+ */
+ public void setLastValidated(long lastValidated) {
+ this.lastValidated = lastValidated;
+ }
+
+ /**
+ * Sets the pool configuration for this connection and connection pool.
+ * Object is shared with the {@link ConnectionPool}
+ * @param poolProperties The pool properties
+ */
+ public void setPoolProperties(PoolConfiguration poolProperties) {
+ this.poolProperties = poolProperties;
+ }
+
+ /**
+ * Return the timestamps of last pool action. Timestamps are typically set when connections
+ * are borrowed from the pool. It is used to keep track of {@link PoolConfiguration#setRemoveAbandonedTimeout(int) abandon-timeouts}.
+ * This timestamp can also be reset by the {@link org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer#invoke(Object, java.lang.reflect.Method, Object[])}
+ * @return the timestamp of the last pool action as defined by {@link System#currentTimeMillis()}
+ */
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ /**
+ * Returns the discarded flag.
+ * @return the discarded flag. If the value is true,
+ * either {@link #disconnect(boolean)} has been called or it will be called when the connection is returned to the pool.
+ */
+ public boolean isDiscarded() {
+ return discarded;
+ }
+
+ /**
+ * Returns the timestamp of the last successful validation query execution.
+ * @return the timestamp of the last successful validation query execution as defined by {@link System#currentTimeMillis()}
+ */
+ public long getLastValidated() {
+ return lastValidated;
+ }
+
+ /**
+ * Returns the configuration for this connection and pool
+ * @return the configuration for this connection and pool
+ */
+ public PoolConfiguration getPoolProperties() {
+ return poolProperties;
+ }
+
+ /**
+ * Locks the connection only if either {@link PoolConfiguration#isPoolSweeperEnabled()} or
+ * {@link PoolConfiguration#getUseLock()} return true. The per connection lock ensures thread safety is
+ * multiple threads are performing operations on the connection.
+ * Otherwise this is a noop for performance
+ */
+ public void lock() {
+ if (poolProperties.getUseLock() || this.poolProperties.isPoolSweeperEnabled()) {
+ //optimized, only use a lock when there is concurrency
+ lock.writeLock().lock();
+ }
+ }
+
+ /**
+ * Unlocks the connection only if the sweeper is enabled
+ * Otherwise this is a noop for performance
+ */
+ public void unlock() {
+ if (poolProperties.getUseLock() || this.poolProperties.isPoolSweeperEnabled()) {
+ //optimized, only use a lock when there is concurrency
+ lock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Returns the underlying connection
+ * @return the underlying JDBC connection as it was returned from the JDBC driver
+ * @see javax.sql.PooledConnection#getConnection()
+ */
+ public java.sql.Connection getConnection() {
+ return this.connection;
+ }
+
+ /**
+ * Returns the underlying XA connection
+ * @return the underlying XA connection as it was returned from the Datasource
+ */
+ public javax.sql.XAConnection getXAConnection() {
+ return this.xaConnection;
+ }
+
+
+ /**
+ * Returns the timestamp of when the connection was last connected to the database.
+ * ie, a successful call to {@link java.sql.Driver#connect(String, java.util.Properties)}.
+ * @return the timestamp when this connection was created as defined by {@link System#currentTimeMillis()}
+ */
+ public long getLastConnected() {
+ return lastConnected;
+ }
+
+ /**
+ * Returns the first handler in the interceptor chain
+ * @return the first interceptor for this connection
+ */
+ public JdbcInterceptor getHandler() {
+ return handler;
+ }
+
+ public void setHandler(JdbcInterceptor handler) {
+ if (this.handler!=null && this.handler!=handler) {
+ JdbcInterceptor interceptor = this.handler;
+ while (interceptor!=null) {
+ interceptor.reset(null, null);
+ interceptor = interceptor.getNext();
+ }//while
+ }//end if
+ this.handler = handler;
+ }
+
+ @Override
+ public String toString() {
+ return "PooledConnection["+(connection!=null?connection.toString():"null")+"]";
+ }
+
+ /**
+ * Returns true if this connection has been released and wont be reused.
+ * @return true if the method {@link #release()} has been called
+ */
+ public boolean isReleased() {
+ return released.get();
+ }
+
+ public HashMap<Object,Object> getAttributes() {
+ return attributes;
+ }
+
+}