Modified: tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java URL: http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java?rev=1833804&r1=1833803&r2=1833804&view=diff ============================================================================== --- tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java (original) +++ tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java Tue Jun 19 10:30:31 2018 @@ -37,7 +37,9 @@ import javax.naming.spi.ObjectFactory; import javax.sql.ConnectionPoolDataSource; import javax.sql.PooledConnection; -import org.apache.tomcat.dbcp.dbcp2.PoolablePreparedStatement; +import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement; +import org.apache.tomcat.dbcp.dbcp2.PStmtKey; +import org.apache.tomcat.dbcp.dbcp2.Utils; import org.apache.tomcat.dbcp.pool2.KeyedObjectPool; import org.apache.tomcat.dbcp.pool2.impl.BaseObjectPoolConfig; import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPool; @@ -45,92 +47,79 @@ import org.apache.tomcat.dbcp.pool2.impl /** * <p> - * An adapter for JDBC drivers that do not include an implementation - * of {@link javax.sql.ConnectionPoolDataSource}, but still include a - * {@link java.sql.DriverManager} implementation. - * <code>ConnectionPoolDataSource</code>s are not used within general - * applications. They are used by <code>DataSource</code> implementations - * that pool <code>Connection</code>s, such as - * {@link org.apache.tomcat.dbcp.dbcp2.datasources.SharedPoolDataSource}. A J2EE - * container will normally provide some method of initializing the - * <code>ConnectionPoolDataSource</code> whose attributes are presented - * as bean getters/setters and then deploying it via JNDI. It is then - * available as a source of physical connections to the database, when - * the pooling <code>DataSource</code> needs to create a new - * physical connection. + * An adapter for JDBC drivers that do not include an implementation of {@link javax.sql.ConnectionPoolDataSource}, but + * still include a {@link java.sql.DriverManager} implementation. <code>ConnectionPoolDataSource</code>s are not used + * within general applications. They are used by <code>DataSource</code> implementations that pool + * <code>Connection</code>s, such as {@link org.apache.tomcat.dbcp.dbcp2.datasources.SharedPoolDataSource}. A J2EE container + * will normally provide some method of initializing the <code>ConnectionPoolDataSource</code> whose attributes are + * presented as bean getters/setters and then deploying it via JNDI. It is then available as a source of physical + * connections to the database, when the pooling <code>DataSource</code> needs to create a new physical connection. * </p> - * * <p> - * Although normally used within a JNDI environment, the DriverAdapterCPDS - * can be instantiated and initialized as any bean and then attached - * directly to a pooling <code>DataSource</code>. - * <code>Jdbc2PoolDataSource</code> can use the + * Although normally used within a JNDI environment, the DriverAdapterCPDS can be instantiated and initialized as any + * bean and then attached directly to a pooling <code>DataSource</code>. <code>Jdbc2PoolDataSource</code> can use the * <code>ConnectionPoolDataSource</code> with or without the use of JNDI. * </p> - * * <p> - * The DriverAdapterCPDS also provides <code>PreparedStatement</code> pooling - * which is not generally available in jdbc2 - * <code>ConnectionPoolDataSource</code> implementation, but is - * addressed within the jdbc3 specification. The <code>PreparedStatement</code> - * pool in DriverAdapterCPDS has been in the dbcp package for some time, but - * it has not undergone extensive testing in the configuration used here. - * It should be considered experimental and can be toggled with the - * poolPreparedStatements attribute. + * The DriverAdapterCPDS also provides <code>PreparedStatement</code> pooling which is not generally available in jdbc2 + * <code>ConnectionPoolDataSource</code> implementation, but is addressed within the jdbc3 specification. The + * <code>PreparedStatement</code> pool in DriverAdapterCPDS has been in the dbcp package for some time, but it has not + * undergone extensive testing in the configuration used here. It should be considered experimental and can be toggled + * with the poolPreparedStatements attribute. * </p> - * * <p> - * The <a href="package-summary.html">package documentation</a> contains an - * example using catalina and JNDI. The <a - * href="../datasources/package-summary.html">datasources package documentation</a> - * shows how to use <code>DriverAdapterCPDS</code> as a source for - * <code>Jdbc2PoolDataSource</code> without the use of JNDI. + * The <a href="package-summary.html">package documentation</a> contains an example using catalina and JNDI. The + * <a href="../datasources/package-summary.html">datasources package documentation</a> shows how to use + * <code>DriverAdapterCPDS</code> as a source for <code>Jdbc2PoolDataSource</code> without the use of JNDI. * </p> * - * @author John D. McNally * @since 2.0 */ -public class DriverAdapterCPDS - implements ConnectionPoolDataSource, Referenceable, Serializable, - ObjectFactory { +public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceable, Serializable, ObjectFactory { - private static final long serialVersionUID = -4820523787212147844L; + private static final String KEY_USER = "user"; + private static final String KEY_PASSWORD = "password"; - private static final String GET_CONNECTION_CALLED - = "A PooledConnection was already requested from this source, " + private static final long serialVersionUID = -4820523787212147844L; + + private static final String GET_CONNECTION_CALLED = "A PooledConnection was already requested from this source, " + "further initialization is not allowed."; /** Description */ private String description; - /** Password */ - private String password; + /** Url name */ private String url; + /** User name */ - private String user; + private String userName; + + /** User password */ + private char[] userPassword; + /** Driver class name */ private String driver; /** Login TimeOut in seconds */ private int loginTimeout; + /** Log stream. NOT USED */ - private transient PrintWriter logWriter = null; + private transient PrintWriter logWriter; // PreparedStatement pool properties private boolean poolPreparedStatements; private int maxIdle = 10; - private long _timeBetweenEvictionRunsMillis = - BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; - private int _numTestsPerEvictionRun = -1; - private int _minEvictableIdleTimeMillis = -1; - private int _maxPreparedStatements = -1; + private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; + private int numTestsPerEvictionRun = -1; + private int minEvictableIdleTimeMillis = -1; + private int maxPreparedStatements = -1; /** Whether or not getConnection has been called */ - private volatile boolean getConnectionCalled = false; + private volatile boolean getConnectionCalled; /** Connection properties passed to JDBC Driver */ - private Properties connectionProperties = null; + private Properties connectionProperties; static { // Attempt to prevent deadlocks - see DBCP - 272 @@ -140,7 +129,7 @@ public class DriverAdapterCPDS /** * Controls access to the underlying connection */ - private boolean accessToUnderlyingConnectionAllowed = false; + private boolean accessToUnderlyingConnectionAllowed; /** * Default no-arg constructor for Serialization @@ -149,8 +138,7 @@ public class DriverAdapterCPDS } /** - * Attempt to establish a database connection using the default - * user and password. + * Attempts to establish a database connection using the default user and password. */ @Override public PooledConnection getPooledConnection() throws SQLException { @@ -159,68 +147,65 @@ public class DriverAdapterCPDS /** * Attempt to establish a database connection. - * @param username name to be used for the connection - * @param pass password to be used fur the connection + * + * @param pooledUserName + * name to be used for the connection + * @param pooledUserPassword + * password to be used fur the connection */ @Override - public PooledConnection getPooledConnection(final String username, final String pass) + public PooledConnection getPooledConnection(final String pooledUserName, final String pooledUserPassword) throws SQLException { getConnectionCalled = true; - PooledConnectionImpl pci = null; - // Workaround for buggy WebLogic 5.1 classloader - ignore the - // exception upon first invocation. + PooledConnectionImpl pooledConnection = null; + // Workaround for buggy WebLogic 5.1 classloader - ignore the exception upon first invocation. try { if (connectionProperties != null) { - connectionProperties.put("user", username); - connectionProperties.put("password", pass); - pci = new PooledConnectionImpl(DriverManager.getConnection( - getUrl(), connectionProperties)); + update(connectionProperties, KEY_USER, pooledUserName); + update(connectionProperties, KEY_PASSWORD, pooledUserPassword); + pooledConnection = new PooledConnectionImpl( + DriverManager.getConnection(getUrl(), connectionProperties)); } else { - pci = new PooledConnectionImpl(DriverManager.getConnection( - getUrl(), username, pass)); + pooledConnection = new PooledConnectionImpl( + DriverManager.getConnection(getUrl(), pooledUserName, pooledUserPassword)); } - pci.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); - } - catch (final ClassCircularityError e) - { + pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); + } catch (final ClassCircularityError e) { if (connectionProperties != null) { - pci = new PooledConnectionImpl(DriverManager.getConnection( - getUrl(), connectionProperties)); + pooledConnection = new PooledConnectionImpl( + DriverManager.getConnection(getUrl(), connectionProperties)); } else { - pci = new PooledConnectionImpl(DriverManager.getConnection( - getUrl(), username, pass)); + pooledConnection = new PooledConnectionImpl( + DriverManager.getConnection(getUrl(), pooledUserName, pooledUserPassword)); } - pci.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); + pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); } - KeyedObjectPool<PStmtKeyCPDS, PoolablePreparedStatement<PStmtKeyCPDS>> stmtPool = null; + KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = null; if (isPoolPreparedStatements()) { - final GenericKeyedObjectPoolConfig<PoolablePreparedStatement<PStmtKeyCPDS>> config = new GenericKeyedObjectPoolConfig<>(); + final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig(); config.setMaxTotalPerKey(Integer.MAX_VALUE); config.setBlockWhenExhausted(false); config.setMaxWaitMillis(0); config.setMaxIdlePerKey(getMaxIdle()); - if (getMaxPreparedStatements() <= 0) - { - // since there is no limit, create a prepared statement pool with an eviction thread - // evictor settings are the same as the connection pool settings. + if (getMaxPreparedStatements() <= 0) { + // since there is no limit, create a prepared statement pool with an eviction thread; + // evictor settings are the same as the connection pool settings. config.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis()); config.setNumTestsPerEvictionRun(getNumTestsPerEvictionRun()); config.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis()); - } - else - { - // since there is limit, create a prepared statement pool without an eviction thread - // pool has LRU functionality so when the limit is reached, 15% of the pool is cleared. - // see org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPool.clearOldest method + } else { + // since there is a limit, create a prepared statement pool without an eviction thread; + // pool has LRU functionality so when the limit is reached, 15% of the pool is cleared. + // see org.apache.commons.pool2.impl.GenericKeyedObjectPool.clearOldest method config.setMaxTotal(getMaxPreparedStatements()); config.setTimeBetweenEvictionRunsMillis(-1); config.setNumTestsPerEvictionRun(0); config.setMinEvictableIdleTimeMillis(0); } - stmtPool = new GenericKeyedObjectPool<>(pci, config); - pci.setStatementPool(stmtPool); + stmtPool = new GenericKeyedObjectPool<>(pooledConnection, config); + pooledConnection.setStatementPool(stmtPool); } - return pci; + return pooledConnection; } @Override @@ -243,29 +228,21 @@ public class DriverAdapterCPDS ref.add(new StringRefAddr("description", getDescription())); ref.add(new StringRefAddr("driver", getDriver())); - ref.add(new StringRefAddr("loginTimeout", - String.valueOf(getLoginTimeout()))); - ref.add(new StringRefAddr("password", getPassword())); - ref.add(new StringRefAddr("user", getUser())); + ref.add(new StringRefAddr("loginTimeout", String.valueOf(getLoginTimeout()))); + ref.add(new StringRefAddr(KEY_PASSWORD, getPassword())); + ref.add(new StringRefAddr(KEY_USER, getUser())); ref.add(new StringRefAddr("url", getUrl())); - ref.add(new StringRefAddr("poolPreparedStatements", - String.valueOf(isPoolPreparedStatements()))); - ref.add(new StringRefAddr("maxIdle", - String.valueOf(getMaxIdle()))); - ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis", - String.valueOf(getTimeBetweenEvictionRunsMillis()))); - ref.add(new StringRefAddr("numTestsPerEvictionRun", - String.valueOf(getNumTestsPerEvictionRun()))); - ref.add(new StringRefAddr("minEvictableIdleTimeMillis", - String.valueOf(getMinEvictableIdleTimeMillis()))); - ref.add(new StringRefAddr("maxPreparedStatements", - String.valueOf(getMaxPreparedStatements()))); + ref.add(new StringRefAddr("poolPreparedStatements", String.valueOf(isPoolPreparedStatements()))); + ref.add(new StringRefAddr("maxIdle", String.valueOf(getMaxIdle()))); + ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis", String.valueOf(getTimeBetweenEvictionRunsMillis()))); + ref.add(new StringRefAddr("numTestsPerEvictionRun", String.valueOf(getNumTestsPerEvictionRun()))); + ref.add(new StringRefAddr("minEvictableIdleTimeMillis", String.valueOf(getMinEvictableIdleTimeMillis()))); + ref.add(new StringRefAddr("maxPreparedStatements", String.valueOf(getMaxPreparedStatements()))); return ref; } - // ---------------------------------------------------------------------- // ObjectFactory implementation @@ -273,14 +250,13 @@ public class DriverAdapterCPDS * implements ObjectFactory to create an instance of this class */ @Override - public Object getObjectInstance(final Object refObj, final Name name, - final Context context, final Hashtable<?,?> env) - throws Exception { + public Object getObjectInstance(final Object refObj, final Name name, final Context context, + final Hashtable<?, ?> env) throws Exception { // The spec says to return null if we can't create an instance // of the reference DriverAdapterCPDS cpds = null; if (refObj instanceof Reference) { - final Reference ref = (Reference)refObj; + final Reference ref = (Reference) refObj; if (ref.getClassName().equals(getClass().getName())) { RefAddr ra = ref.get("description"); if (ra != null && ra.getContent() != null) { @@ -295,19 +271,18 @@ public class DriverAdapterCPDS if (ra != null && ra.getContent() != null) { setUrl(ra.getContent().toString()); } - ra = ref.get("user"); + ra = ref.get(KEY_USER); if (ra != null && ra.getContent() != null) { setUser(ra.getContent().toString()); } - ra = ref.get("password"); + ra = ref.get(KEY_PASSWORD); if (ra != null && ra.getContent() != null) { setPassword(ra.getContent().toString()); } ra = ref.get("poolPreparedStatements"); if (ra != null && ra.getContent() != null) { - setPoolPreparedStatements(Boolean.valueOf( - ra.getContent().toString()).booleanValue()); + setPoolPreparedStatements(Boolean.valueOf(ra.getContent().toString()).booleanValue()); } ra = ref.get("maxIdle"); if (ra != null && ra.getContent() != null) { @@ -316,31 +291,26 @@ public class DriverAdapterCPDS ra = ref.get("timeBetweenEvictionRunsMillis"); if (ra != null && ra.getContent() != null) { - setTimeBetweenEvictionRunsMillis( - Integer.parseInt(ra.getContent().toString())); + setTimeBetweenEvictionRunsMillis(Integer.parseInt(ra.getContent().toString())); } ra = ref.get("numTestsPerEvictionRun"); if (ra != null && ra.getContent() != null) { - setNumTestsPerEvictionRun( - Integer.parseInt(ra.getContent().toString())); + setNumTestsPerEvictionRun(Integer.parseInt(ra.getContent().toString())); } ra = ref.get("minEvictableIdleTimeMillis"); if (ra != null && ra.getContent() != null) { - setMinEvictableIdleTimeMillis( - Integer.parseInt(ra.getContent().toString())); + setMinEvictableIdleTimeMillis(Integer.parseInt(ra.getContent().toString())); } ra = ref.get("maxPreparedStatements"); if (ra != null && ra.getContent() != null) { - setMaxPreparedStatements( - Integer.parseInt(ra.getContent().toString())); + setMaxPreparedStatements(Integer.parseInt(ra.getContent().toString())); } ra = ref.get("accessToUnderlyingConnectionAllowed"); if (ra != null && ra.getContent() != null) { - setAccessToUnderlyingConnectionAllowed( - Boolean.valueOf(ra.getContent().toString()).booleanValue()); + setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(ra.getContent().toString()).booleanValue()); } cpds = this; @@ -350,8 +320,7 @@ public class DriverAdapterCPDS } /** - * Throws an IllegalStateException, if a PooledConnection has already - * been requested. + * Throws an IllegalStateException, if a PooledConnection has already been requested. */ private void assertInitializationAllowed() throws IllegalStateException { if (getConnectionCalled) { @@ -372,35 +341,40 @@ public class DriverAdapterCPDS } /** - * <p>Sets the connection properties passed to the JDBC driver.</p> - * - * <p>If <code>props</code> contains "user" and/or "password" - * properties, the corresponding instance properties are set. If these - * properties are not present, they are filled in using - * {@link #getUser()}, {@link #getPassword()} when {@link #getPooledConnection()} - * is called, or using the actual parameters to the method call when - * {@link #getPooledConnection(String, String)} is called. Calls to - * {@link #setUser(String)} or {@link #setPassword(String)} overwrite the values - * of these properties if <code>connectionProperties</code> is not null.</p> + * <p> + * Sets the connection properties passed to the JDBC driver. + * </p> * - * @param props Connection properties to use when creating new connections. - * @throws IllegalStateException if {@link #getPooledConnection()} has been called + * <p> + * If <code>props</code> contains "user" and/or "password" properties, the corresponding instance properties are + * set. If these properties are not present, they are filled in using {@link #getUser()}, {@link #getPassword()} + * when {@link #getPooledConnection()} is called, or using the actual parameters to the method call when + * {@link #getPooledConnection(String, String)} is called. Calls to {@link #setUser(String)} or + * {@link #setPassword(String)} overwrite the values of these properties if <code>connectionProperties</code> is not + * null. + * </p> + * + * @param props + * Connection properties to use when creating new connections. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ public void setConnectionProperties(final Properties props) { assertInitializationAllowed(); connectionProperties = props; - if (connectionProperties.containsKey("user")) { - setUser(connectionProperties.getProperty("user")); - } - if (connectionProperties.containsKey("password")) { - setPassword(connectionProperties.getProperty("password")); + if (connectionProperties != null) { + if (connectionProperties.containsKey(KEY_USER)) { + setUser(connectionProperties.getProperty(KEY_USER)); + } + if (connectionProperties.containsKey(KEY_PASSWORD)) { + setPassword(connectionProperties.getProperty(KEY_PASSWORD)); + } } } /** - * Gets the value of description. This property is here for use by - * the code which will deploy this datasource. It is not used - * internally. + * Gets the value of description. This property is here for use by the code which will deploy this datasource. It is + * not used internally. * * @return value of description, may be null. * @see #setDescription(String) @@ -410,39 +384,66 @@ public class DriverAdapterCPDS } /** - * Sets the value of description. This property is here for use by - * the code which will deploy this datasource. It is not used - * internally. + * Sets the value of description. This property is here for use by the code which will deploy this datasource. It is + * not used internally. * - * @param v Value to assign to description. + * @param v + * Value to assign to description. */ - public void setDescription(final String v) { + public void setDescription(final String v) { this.description = v; } /** * Gets the value of password for the default user. + * + * @return value of password. + * @since 2.4.0 + */ + public char[] getPasswordCharArray() { + return userPassword; + } + + /** + * Gets the value of password for the default user. + * * @return value of password. */ public String getPassword() { - return password; + return Utils.toString(userPassword); } /** * Sets the value of password for the default user. - * @param v Value to assign to password. - * @throws IllegalStateException if {@link #getPooledConnection()} has been called + * + * @param userPassword + * Value to assign to password. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ - public void setPassword(final String v) { + public void setPassword(final char[] userPassword) { assertInitializationAllowed(); - this.password = v; - if (connectionProperties != null) { - connectionProperties.setProperty("password", v); - } + this.userPassword = userPassword; + update(connectionProperties, KEY_PASSWORD, Utils.toString(userPassword)); + } + + /** + * Sets the value of password for the default user. + * + * @param userPassword + * Value to assign to password. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called + */ + public void setPassword(final String userPassword) { + assertInitializationAllowed(); + this.userPassword = Utils.toCharArray(userPassword); + update(connectionProperties, KEY_PASSWORD, userPassword); } /** * Gets the value of url used to locate the database for this datasource. + * * @return value of url. */ public String getUrl() { @@ -451,37 +452,43 @@ public class DriverAdapterCPDS /** * Sets the value of URL string used to locate the database for this datasource. - * @param v Value to assign to url. - * @throws IllegalStateException if {@link #getPooledConnection()} has been called - */ + * + * @param v + * Value to assign to url. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called + */ public void setUrl(final String v) { assertInitializationAllowed(); this.url = v; } /** - * Gets the value of default user (login or username). + * Gets the value of default user (login or user name). + * * @return value of user. */ public String getUser() { - return user; + return userName; } /** - * Sets the value of default user (login or username). - * @param v Value to assign to user. - * @throws IllegalStateException if {@link #getPooledConnection()} has been called + * Sets the value of default user (login or user name). + * + * @param v + * Value to assign to user. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ public void setUser(final String v) { assertInitializationAllowed(); - this.user = v; - if (connectionProperties != null) { - connectionProperties.setProperty("user", v); - } + this.userName = v; + update(connectionProperties, KEY_USER, v); } /** - * Gets the driver classname. + * Gets the driver class name. + * * @return value of driver. */ public String getDriver() { @@ -489,11 +496,15 @@ public class DriverAdapterCPDS } /** - * Sets the driver classname. Setting the driver classname cause the - * driver to be registered with the DriverManager. - * @param v Value to assign to driver. - * @throws ClassNotFoundException Driver class was not found - * @throws IllegalStateException if {@link #getPooledConnection()} has been called + * Sets the driver class name. Setting the driver class name cause the driver to be registered with the + * DriverManager. + * + * @param v + * Value to assign to driver. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called + * @throws ClassNotFoundException + * if the class cannot be located */ public void setDriver(final String v) throws ClassNotFoundException { assertInitializationAllowed(); @@ -503,8 +514,8 @@ public class DriverAdapterCPDS } /** - * Gets the maximum time in seconds that this data source can wait - * while attempting to connect to a database. NOT USED. + * Gets the maximum time in seconds that this data source can wait while attempting to connect to a database. NOT + * USED. */ @Override public int getLoginTimeout() { @@ -520,8 +531,8 @@ public class DriverAdapterCPDS } /** - * Sets the maximum time in seconds that this data source will wait - * while attempting to connect to a database. NOT USED. + * Sets the maximum time in seconds that this data source will wait while attempting to connect to a database. NOT + * USED. */ @Override public void setLoginTimeout(final int seconds) { @@ -536,13 +547,12 @@ public class DriverAdapterCPDS logWriter = out; } - // ------------------------------------------------------------------ // PreparedStatement pool properties - /** * Flag to toggle the pooling of <code>PreparedStatement</code>s + * * @return value of poolPreparedStatements. */ public boolean isPoolPreparedStatements() { @@ -551,17 +561,21 @@ public class DriverAdapterCPDS /** * Flag to toggle the pooling of <code>PreparedStatement</code>s - * @param v true to pool statements. - * @throws IllegalStateException if {@link #getPooledConnection()} has been called + * + * @param poolPreparedStatements + * true to pool statements. + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ - public void setPoolPreparedStatements(final boolean v) { + public void setPoolPreparedStatements(final boolean poolPreparedStatements) { assertInitializationAllowed(); - this.poolPreparedStatements = v; + this.poolPreparedStatements = poolPreparedStatements; } /** - * Gets the maximum number of statements that can remain idle in the - * pool, without extra ones being released, or negative for no limit. + * Gets the maximum number of statements that can remain idle in the pool, without extra ones being released, or + * negative for no limit. + * * @return the value of maxIdle */ public int getMaxIdle() { @@ -569,11 +583,13 @@ public class DriverAdapterCPDS } /** - * Gets the maximum number of statements that can remain idle in the - * pool, without extra ones being released, or negative for no limit. + * Gets the maximum number of statements that can remain idle in the pool, without extra ones being released, or + * negative for no limit. * - * @param maxIdle The maximum number of statements that can remain idle - * @throws IllegalStateException if {@link #getPooledConnection()} has been called + * @param maxIdle + * The maximum number of statements that can remain idle + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ public void setMaxIdle(final int maxIdle) { assertInitializationAllowed(); @@ -581,107 +597,106 @@ public class DriverAdapterCPDS } /** - * Gets the number of milliseconds to sleep between runs of the - * idle object evictor thread. - * When non-positive, no idle object evictor thread will be - * run. + * Gets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no + * idle object evictor thread will be run. + * * @return the value of the evictor thread timer * @see #setTimeBetweenEvictionRunsMillis(long) */ public long getTimeBetweenEvictionRunsMillis() { - return _timeBetweenEvictionRunsMillis; + return timeBetweenEvictionRunsMillis; } /** - * Sets the number of milliseconds to sleep between runs of the - * idle object evictor thread. - * When non-positive, no idle object evictor thread will be - * run. - * @param timeBetweenEvictionRunsMillis The time between runs + * Sets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no + * idle object evictor thread will be run. + * + * @param timeBetweenEvictionRunsMillis + * The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, + * no idle object evictor thread will be run. * @see #getTimeBetweenEvictionRunsMillis() - * @throws IllegalStateException if {@link #getPooledConnection()} has been called + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ - public void setTimeBetweenEvictionRunsMillis( - final long timeBetweenEvictionRunsMillis) { + public void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { assertInitializationAllowed(); - _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; } /** - * Gets the number of statements to examine during each run of the - * idle object evictor thread (if any). + * Gets the number of statements to examine during each run of the idle object evictor thread (if any.) * - * @see #setNumTestsPerEvictionRun(int) - * @see #setTimeBetweenEvictionRunsMillis(long) - * @return the number of statements + * @see #setNumTestsPerEvictionRun + * @see #setTimeBetweenEvictionRunsMillis + * @return the number of statements to examine during each run of the idle object evictor thread (if any.) */ public int getNumTestsPerEvictionRun() { - return _numTestsPerEvictionRun; + return numTestsPerEvictionRun; } /** - * Sets the number of statements to examine during each run of the - * idle object evictor thread (if any). + * Sets the number of statements to examine during each run of the idle object evictor thread (if any). * <p> - * When a negative value is supplied, <tt>ceil({*link #numIdle})/abs({*link #getNumTestsPerEvictionRun})</tt> - * tests will be run. I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the - * idle objects will be tested per run. + * When a negative value is supplied, <tt>ceil({*link #numIdle})/abs({*link #getNumTestsPerEvictionRun})</tt> tests + * will be run. I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the idle objects will be tested per + * run. + * </p> * - * @param numTestsPerEvictionRun number of statements to examine per run + * @param numTestsPerEvictionRun + * number of statements to examine per run * @see #getNumTestsPerEvictionRun() * @see #setTimeBetweenEvictionRunsMillis(long) - * @throws IllegalStateException if {@link #getPooledConnection()} has been called + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) { assertInitializationAllowed(); - _numTestsPerEvictionRun = numTestsPerEvictionRun; + this.numTestsPerEvictionRun = numTestsPerEvictionRun; } /** - * Gets the minimum amount of time a statement may sit idle in the pool - * before it is eligible for eviction by the idle object evictor - * (if any). + * Gets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the + * idle object evictor (if any). * - * @see #setMinEvictableIdleTimeMillis(int) - * @see #setTimeBetweenEvictionRunsMillis(long) - * @return the amount of time + * @see #setMinEvictableIdleTimeMillis + * @see #setTimeBetweenEvictionRunsMillis + * @return the minimum amount of time a statement may sit idle in the pool. */ public int getMinEvictableIdleTimeMillis() { - return _minEvictableIdleTimeMillis; + return minEvictableIdleTimeMillis; } /** - * Sets the minimum amount of time a statement may sit idle in the pool - * before it is eligible for eviction by the idle object evictor - * (if any). - * When non-positive, no objects will be evicted from the pool - * due to idle time alone. - * @param minEvictableIdleTimeMillis minimum time to set (in ms) + * Sets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the + * idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle time alone. + * + * @param minEvictableIdleTimeMillis + * minimum time to set (in ms) * @see #getMinEvictableIdleTimeMillis() * @see #setTimeBetweenEvictionRunsMillis(long) - * @throws IllegalStateException if {@link #getPooledConnection()} has been called + * @throws IllegalStateException + * if {@link #getPooledConnection()} has been called */ public void setMinEvictableIdleTimeMillis(final int minEvictableIdleTimeMillis) { assertInitializationAllowed(); - _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; } /** * Returns the value of the accessToUnderlyingConnectionAllowed property. * - * @return <code>true</code> if access to the underlying is allowed, - * <code>false</code> otherwise. + * @return true if access to the underlying is allowed, false otherwise. */ public synchronized boolean isAccessToUnderlyingConnectionAllowed() { return this.accessToUnderlyingConnectionAllowed; } /** - * Sets the value of the accessToUnderlyingConnectionAllowed property. - * It controls if the PoolGuard allows access to the underlying connection. - * (Default: false) + * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to + * the underlying connection. (Default: false) * - * @param allow Access to the underlying connection is granted when true. + * @param allow + * Access to the underlying connection is granted when true. */ public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { this.accessToUnderlyingConnectionAllowed = allow; @@ -692,18 +707,27 @@ public class DriverAdapterCPDS * * @return maxPrepartedStatements value */ - public int getMaxPreparedStatements() - { - return _maxPreparedStatements; + public int getMaxPreparedStatements() { + return maxPreparedStatements; } /** * Sets the maximum number of prepared statements. - * @param maxPreparedStatements the new maximum number of prepared - * statements + * + * @param maxPreparedStatements + * the new maximum number of prepared statements */ - public void setMaxPreparedStatements(final int maxPreparedStatements) - { - _maxPreparedStatements = maxPreparedStatements; + public void setMaxPreparedStatements(final int maxPreparedStatements) { + this.maxPreparedStatements = maxPreparedStatements; + } + + private void update(final Properties properties, final String key, final String value) { + if (properties != null) { + if (value == null) { + properties.remove(key); + } else { + properties.setProperty(key, value); + } + } } }
Modified: tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java URL: http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java?rev=1833804&r1=1833803&r2=1833804&view=diff ============================================================================== --- tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java (original) +++ tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java Tue Jun 19 10:30:31 2018 @@ -16,122 +16,38 @@ */ package org.apache.tomcat.dbcp.dbcp2.cpdsadapter; -import java.util.Arrays; - import org.apache.tomcat.dbcp.dbcp2.PStmtKey; /** * A key uniquely identifying a {@link java.sql.PreparedStatement PreparedStatement}. + * * @since 2.0 + * @deprecated Use {@link PStmtKey}. */ +@Deprecated public class PStmtKeyCPDS extends PStmtKey { - private final Integer _resultSetHoldability; - private final int _columnIndexes[]; - private final String _columnNames[]; - public PStmtKeyCPDS(final String sql) { super(sql); - _resultSetHoldability = null; - _columnIndexes = null; - _columnNames = null; } public PStmtKeyCPDS(final String sql, final int autoGeneratedKeys) { super(sql, null, autoGeneratedKeys); - _resultSetHoldability = null; - _columnIndexes = null; - _columnNames = null; } public PStmtKeyCPDS(final String sql, final int resultSetType, final int resultSetConcurrency) { super(sql, resultSetType, resultSetConcurrency); - _resultSetHoldability = null; - _columnIndexes = null; - _columnNames = null; } public PStmtKeyCPDS(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) { super(sql, resultSetType, resultSetConcurrency); - _resultSetHoldability = Integer.valueOf(resultSetHoldability); - _columnIndexes = null; - _columnNames = null; } public PStmtKeyCPDS(final String sql, final int columnIndexes[]) { - super(sql); - _columnIndexes = Arrays.copyOf(columnIndexes, columnIndexes.length); - _resultSetHoldability = null; - _columnNames = null; + super(sql, null, columnIndexes); } public PStmtKeyCPDS(final String sql, final String columnNames[]) { - super(sql); - _columnNames = Arrays.copyOf(columnNames, columnNames.length); - _resultSetHoldability = null; - _columnIndexes = null; - } - - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final PStmtKeyCPDS other = (PStmtKeyCPDS) obj; - if (!Arrays.equals(_columnIndexes, other._columnIndexes)) { - return false; - } - if (!Arrays.equals(_columnNames, other._columnNames)) { - return false; - } - if (_resultSetHoldability == null) { - if (other._resultSetHoldability != null) { - return false; - } - } else if (!_resultSetHoldability.equals(other._resultSetHoldability)) { - return false; - } - return true; - } - - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + Arrays.hashCode(_columnIndexes); - result = prime * result + Arrays.hashCode(_columnNames); - result = prime * result + (_resultSetHoldability == null ? 0 : _resultSetHoldability.hashCode()); - return result; - } - - - @Override - public String toString() { - final StringBuffer buf = new StringBuffer(); - buf.append("PStmtKey: sql="); - buf.append(getSql()); - buf.append(", catalog="); - buf.append(getCatalog()); - buf.append(", resultSetType="); - buf.append(getResultSetType()); - buf.append(", resultSetConcurrency="); - buf.append(getResultSetConcurrency()); - buf.append(", statementType="); - buf.append(getStmtType()); - buf.append(", resultSetHoldability="); - buf.append(_resultSetHoldability); - buf.append(", columnIndexes="); - buf.append(Arrays.toString(_columnIndexes)); - buf.append(", columnNames="); - buf.append(Arrays.toString(_columnNames)); - return buf.toString(); + super(sql, null, columnNames); } } Modified: tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java URL: http://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java?rev=1833804&r1=1833803&r2=1833804&view=diff ============================================================================== --- tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java (original) +++ tomcat/tc8.5.x/trunk/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java Tue Jun 19 10:30:31 2018 @@ -17,6 +17,7 @@ package org.apache.tomcat.dbcp.dbcp2.cpdsadapter; +import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -28,67 +29,69 @@ import javax.sql.PooledConnection; import javax.sql.StatementEventListener; import org.apache.tomcat.dbcp.dbcp2.DelegatingConnection; +import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement; +import org.apache.tomcat.dbcp.dbcp2.PStmtKey; +import org.apache.tomcat.dbcp.dbcp2.PoolableCallableStatement; import org.apache.tomcat.dbcp.dbcp2.PoolablePreparedStatement; +import org.apache.tomcat.dbcp.dbcp2.PoolingConnection.StatementType; import org.apache.tomcat.dbcp.pool2.KeyedObjectPool; import org.apache.tomcat.dbcp.pool2.KeyedPooledObjectFactory; import org.apache.tomcat.dbcp.pool2.PooledObject; import org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject; /** - * Implementation of PooledConnection that is returned by - * PooledConnectionDataSource. + * Implementation of PooledConnection that is returned by PooledConnectionDataSource. * - * @author John D. McNally * @since 2.0 */ class PooledConnectionImpl - implements PooledConnection, KeyedPooledObjectFactory<PStmtKeyCPDS, PoolablePreparedStatement<PStmtKeyCPDS>> { + implements PooledConnection, KeyedPooledObjectFactory<PStmtKey, DelegatingPreparedStatement> { - private static final String CLOSED - = "Attempted to use PooledConnection after closed() was called."; + private static final String CLOSED = "Attempted to use PooledConnection after closed() was called."; /** * The JDBC database connection that represents the physical db connection. */ - private Connection connection = null; + private Connection connection; /** - * A DelegatingConnection used to create a PoolablePreparedStatementStub + * A DelegatingConnection used to create a PoolablePreparedStatementStub. */ private final DelegatingConnection<?> delegatingConnection; /** * The JDBC database logical connection. */ - private Connection logicalConnection = null; + private Connection logicalConnection; /** - * ConnectionEventListeners + * ConnectionEventListeners. */ private final Vector<ConnectionEventListener> eventListeners; /** - * StatementEventListeners + * StatementEventListeners. */ - private final Vector<StatementEventListener> statementEventListeners = - new Vector<>(); + private final Vector<StatementEventListener> statementEventListeners = new Vector<>(); /** - * flag set to true, once close() is called. + * Flag set to true, once {@link #close()} is called. */ - private boolean isClosed; + private boolean closed; /** My pool of {@link PreparedStatement}s. */ - private KeyedObjectPool<PStmtKeyCPDS, PoolablePreparedStatement<PStmtKeyCPDS>> pstmtPool = null; + private KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pStmtPool; /** - * Controls access to the underlying connection + * Controls access to the underlying connection. */ - private boolean accessToUnderlyingConnectionAllowed = false; + private boolean accessToUnderlyingConnectionAllowed; /** - * Wrap the real connection. - * @param connection the connection to be wrapped + * Wraps the real connection. + * + * @param connection + * the connection to be wrapped. */ PooledConnectionImpl(final Connection connection) { this.connection = connection; @@ -98,12 +101,21 @@ class PooledConnectionImpl this.delegatingConnection = new DelegatingConnection<>(connection); } eventListeners = new Vector<>(); - isClosed = false; + closed = false; } - public void setStatementPool( - final KeyedObjectPool<PStmtKeyCPDS, PoolablePreparedStatement<PStmtKeyCPDS>> statementPool) { - pstmtPool = statementPool; + /** + * My {@link KeyedPooledObjectFactory} method for activating {@link PreparedStatement}s. + * + * @param key + * Ignored. + * @param pooledObject + * Ignored. + */ + @Override + public void activateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) + throws Exception { + pooledObject.getObject().activate(); } /** @@ -126,22 +138,31 @@ class PooledConnectionImpl /* JDBC_4_ANT_KEY_END */ /** - * Closes the physical connection and marks this - * <code>PooledConnection</code> so that it may not be used - * to generate any more logical <code>Connection</code>s. + * Throws an SQLException, if isClosed is true + */ + private void assertOpen() throws SQLException { + if (closed) { + throw new SQLException(CLOSED); + } + } + + /** + * Closes the physical connection and marks this <code>PooledConnection</code> so that it may not be used to + * generate any more logical <code>Connection</code>s. * - * @throws SQLException if an error occurs or the connection is already closed + * @throws SQLException + * Thrown when an error occurs or the connection is already closed. */ @Override public void close() throws SQLException { assertOpen(); - isClosed = true; + closed = true; try { - if (pstmtPool != null) { + if (pStmtPool != null) { try { - pstmtPool.close(); + pStmtPool.close(); } finally { - pstmtPool = null; + pStmtPool = null; } } } catch (final RuntimeException e) { @@ -158,11 +179,115 @@ class PooledConnectionImpl } /** - * Throws an SQLException, if isClosed is true + * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments. */ - private void assertOpen() throws SQLException { - if (isClosed) { - throw new SQLException(CLOSED); + protected PStmtKey createKey(final String sql) { + return new PStmtKey(normalizeSQL(sql), getCatalogOrNull()); + } + + /** + * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments. + */ + protected PStmtKey createKey(final String sql, final int autoGeneratedKeys) { + return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), autoGeneratedKeys); + } + + /** + * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments. + */ + protected PStmtKey createKey(final String sql, final int columnIndexes[]) { + return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), columnIndexes); + } + + /** + * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments. + */ + protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency) { + return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), resultSetType, resultSetConcurrency); + } + + /** + * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments. + */ + protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability) { + return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), resultSetType, resultSetConcurrency, + resultSetHoldability); + } + + /** + * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments. + * + * @since 2.4.0 + */ + protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability, final StatementType statementType) { + return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), resultSetType, resultSetConcurrency, + resultSetHoldability, statementType); + } + + /** + * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments. + * + * @since 2.4.0 + */ + protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, + final StatementType statementType) { + return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), resultSetType, resultSetConcurrency, statementType); + } + + /** + * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments. + */ + protected PStmtKey createKey(final String sql, final StatementType statementType) { + return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), statementType); + } + + /** + * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments. + */ + protected PStmtKey createKey(final String sql, final String columnNames[]) { + return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), columnNames); + } + + /** + * My {@link KeyedPooledObjectFactory} method for destroying {@link PreparedStatement}s. + * + * @param key + * ignored + * @param pooledObject + * the wrapped {@link PreparedStatement} to be destroyed. + */ + @Override + public void destroyObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) + throws Exception { + pooledObject.getObject().getInnermostDelegate().close(); + } + + /** + * Closes the physical connection and checks that the logical connection was closed as well. + */ + @Override + protected void finalize() throws Throwable { + // Closing the Connection ensures that if anyone tries to use it, + // an error will occur. + try { + connection.close(); + } catch (final Exception ignored) { + // ignore + } + + // make sure the last connection is marked as closed + if (logicalConnection != null && !logicalConnection.isClosed()) { + throw new SQLException("PooledConnection was gc'ed, without its last Connection being closed."); + } + } + + private String getCatalogOrNull() { + try { + return connection == null ? null : connection.getCatalog(); + } catch (final SQLException e) { + return null; } } @@ -170,7 +295,8 @@ class PooledConnectionImpl * Returns a JDBC connection. * * @return The database connection. - * @throws SQLException if the connection is not open or the previous logical connection is still open + * @throws SQLException + * if the connection is not open or the previous logical connection is still open */ @Override public Connection getConnection() throws SQLException { @@ -179,54 +305,58 @@ class PooledConnectionImpl if (logicalConnection != null && !logicalConnection.isClosed()) { // should notify pool of error so the pooled connection can // be removed !FIXME! - throw new SQLException("PooledConnection was reused, without " - + "its previous Connection being closed."); + throw new SQLException("PooledConnection was reused, without its previous Connection being closed."); } // the spec requires that this return a new Connection instance. - logicalConnection = new ConnectionImpl( - this, connection, isAccessToUnderlyingConnectionAllowed()); + logicalConnection = new ConnectionImpl(this, connection, isAccessToUnderlyingConnectionAllowed()); return logicalConnection; } /** - * {@inheritDoc} + * Returns the value of the accessToUnderlyingConnectionAllowed property. + * + * @return true if access to the underlying is allowed, false otherwise. */ - @Override - public void removeConnectionEventListener( - final ConnectionEventListener listener) { - eventListeners.remove(listener); - } - - /* JDBC_4_ANT_KEY_BEGIN */ - @Override - public void removeStatementEventListener(final StatementEventListener listener) { - statementEventListeners.remove(listener); + public synchronized boolean isAccessToUnderlyingConnectionAllowed() { + return this.accessToUnderlyingConnectionAllowed; } - /* JDBC_4_ANT_KEY_END */ /** - * Closes the physical connection and checks that the logical connection - * was closed as well. + * My {@link KeyedPooledObjectFactory} method for creating {@link PreparedStatement}s. + * + * @param key + * The key for the {@link PreparedStatement} to be created. */ + @SuppressWarnings("resource") @Override - protected void finalize() throws Throwable { - // Closing the Connection ensures that if anyone tries to use it, - // an error will occur. - try { - connection.close(); - } catch (final Exception ignored) { + public PooledObject<DelegatingPreparedStatement> makeObject(final PStmtKey key) throws Exception { + if (null == key) { + throw new IllegalArgumentException("Prepared statement key is null or invalid."); } - - // make sure the last connection is marked as closed - if (logicalConnection != null && !logicalConnection.isClosed()) { - throw new SQLException("PooledConnection was gc'ed, without" - + "its last Connection being closed."); + if (key.getStmtType() == StatementType.PREPARED_STATEMENT) { + final PreparedStatement statement = (PreparedStatement) key.createStatement(connection); + @SuppressWarnings({"rawtypes", "unchecked" }) // Unable to find way to avoid this + final PoolablePreparedStatement pps = new PoolablePreparedStatement(statement, key, pStmtPool, + delegatingConnection); + return new DefaultPooledObject<DelegatingPreparedStatement>(pps); } + final CallableStatement statement = (CallableStatement) key.createStatement(connection); + @SuppressWarnings("unchecked") + final PoolableCallableStatement pcs = new PoolableCallableStatement(statement, key, pStmtPool, + (DelegatingConnection<Connection>) delegatingConnection); + return new DefaultPooledObject<DelegatingPreparedStatement>(pcs); } /** - * sends a connectionClosed event. + * Normalizes the given SQL statement, producing a canonical form that is semantically equivalent to the original. + */ + protected String normalizeSQL(final String sql) { + return sql.trim(); + } + + /** + * Sends a connectionClosed event. */ void notifyListeners() { final ConnectionEvent event = new ConnectionEvent(this); @@ -236,52 +366,132 @@ class PooledConnectionImpl } } - // ------------------------------------------------------------------- - // The following code implements a PreparedStatement pool + /** + * My {@link KeyedPooledObjectFactory} method for passivating {@link PreparedStatement}s. Currently invokes + * {@link PreparedStatement#clearParameters}. + * + * @param key + * ignored + * @param pooledObject + * a wrapped {@link PreparedStatement} + */ + @Override + public void passivateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) + throws Exception { + @SuppressWarnings("resource") + final DelegatingPreparedStatement dps = pooledObject.getObject(); + dps.clearParameters(); + dps.passivate(); + } /** - * Create or obtain a {@link PreparedStatement} from my pool. - * @param sql the SQL statement - * @return a {@link PoolablePreparedStatement} + * Creates or obtains a {@link CallableStatement} from my pool. + * + * @param sql + * an SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is + * specified using JDBC call escape syntax. + * @return a default <code>CallableStatement</code> object containing the pre-compiled SQL statement. + * @exception SQLException + * Thrown if a database access error occurs or this method is called on a closed connection. + * @since 2.4.0 + */ + CallableStatement prepareCall(final String sql) throws SQLException { + if (pStmtPool == null) { + return connection.prepareCall(sql); + } + try { + return (CallableStatement) pStmtPool.borrowObject(createKey(sql, StatementType.CALLABLE_STATEMENT)); + } catch (final RuntimeException e) { + throw e; + } catch (final Exception e) { + throw new SQLException("Borrow prepareCall from pool failed", e); + } + } + + /** + * Creates or obtains a {@link CallableStatement} from my pool. + * + * @param sql + * a <code>String</code> object that is the SQL statement to be sent to the database; may contain on or + * more '?' parameters. + * @param resultSetType + * a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>. + * @param resultSetConcurrency + * a concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or + * <code>ResultSet.CONCUR_UPDATABLE</code>. + * @return a <code>CallableStatement</code> object containing the pre-compiled SQL statement that will produce + * <code>ResultSet</code> objects with the given type and concurrency. + * @throws SQLException + * Thrown if a database access error occurs, this method is called on a closed connection or the given + * parameters are not <code>ResultSet</code> constants indicating type and concurrency. + * @since 2.4.0 */ - PreparedStatement prepareStatement(final String sql) throws SQLException { - if (pstmtPool == null) { - return connection.prepareStatement(sql); + CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) + throws SQLException { + if (pStmtPool == null) { + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); } try { - return pstmtPool.borrowObject(createKey(sql)); + return (CallableStatement) pStmtPool.borrowObject( + createKey(sql, resultSetType, resultSetConcurrency, StatementType.CALLABLE_STATEMENT)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { - throw new SQLException("Borrow prepareStatement from pool failed", e); + throw new SQLException("Borrow prepareCall from pool failed", e); } } /** - * Create or obtain a {@link PreparedStatement} from my pool. - * @param sql a <code>String</code> object that is the SQL statement to - * be sent to the database; may contain one or more '?' IN - * parameters - * @param resultSetType a result set type; one of - * <code>ResultSet.TYPE_FORWARD_ONLY</code>, - * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or - * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> - * @param resultSetConcurrency a concurrency type; one of - * <code>ResultSet.CONCUR_READ_ONLY</code> or - * <code>ResultSet.CONCUR_UPDATABLE</code> + * Creates or obtains a {@link CallableStatement} from my pool. * + * @param sql + * a <code>String</code> object that is the SQL statement to be sent to the database; may contain on or + * more '?' parameters. + * @param resultSetType + * one of the following <code>ResultSet</code> constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>. + * @param resultSetConcurrency + * one of the following <code>ResultSet</code> constants: <code>ResultSet.CONCUR_READ_ONLY</code> or + * <code>ResultSet.CONCUR_UPDATABLE</code>. + * @param resultSetHoldability + * one of the following <code>ResultSet</code> constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> + * or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>. + * @return a new <code>CallableStatement</code> object, containing the pre-compiled SQL statement, that will + * generate <code>ResultSet</code> objects with the given type, concurrency, and holdability. + * @throws SQLException + * Thrown if a database access error occurs, this method is called on a closed connection or the given + * parameters are not <code>ResultSet</code> constants indicating type, concurrency, and holdability. + * @since 2.4.0 + */ + CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability) throws SQLException { + if (pStmtPool == null) { + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + try { + return (CallableStatement) pStmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency, + resultSetHoldability, StatementType.CALLABLE_STATEMENT)); + } catch (final RuntimeException e) { + throw e; + } catch (final Exception e) { + throw new SQLException("Borrow prepareCall from pool failed", e); + } + } + + /** + * Creates or obtains a {@link PreparedStatement} from my pool. + * + * @param sql + * the SQL statement. * @return a {@link PoolablePreparedStatement} - * @see Connection#prepareStatement(String, int, int) */ - PreparedStatement prepareStatement(final String sql, final int resultSetType, - final int resultSetConcurrency) - throws SQLException { - if (pstmtPool == null) { - return connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + PreparedStatement prepareStatement(final String sql) throws SQLException { + if (pStmtPool == null) { + return connection.prepareStatement(sql); } try { - return pstmtPool.borrowObject( - createKey(sql,resultSetType,resultSetConcurrency)); + return pStmtPool.borrowObject(createKey(sql)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { @@ -290,23 +500,22 @@ class PooledConnectionImpl } /** - * Create or obtain a {@link PreparedStatement} from my pool. - * @param sql an SQL statement that may contain one or more '?' IN - * parameter placeholders - * @param autoGeneratedKeys a flag indicating whether auto-generated keys - * should be returned; one of - * <code>Statement.RETURN_GENERATED_KEYS</code> or - * <code>Statement.NO_GENERATED_KEYS</code> + * Creates or obtains a {@link PreparedStatement} from my pool. + * + * @param sql + * an SQL statement that may contain one or more '?' IN parameter placeholders. + * @param autoGeneratedKeys + * a flag indicating whether auto-generated keys should be returned; one of + * <code>Statement.RETURN_GENERATED_KEYS</code> or <code>Statement.NO_GENERATED_KEYS</code>. * @return a {@link PoolablePreparedStatement} * @see Connection#prepareStatement(String, int) */ - PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) - throws SQLException { - if (pstmtPool == null) { + PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { + if (pStmtPool == null) { return connection.prepareStatement(sql, autoGeneratedKeys); } try { - return pstmtPool.borrowObject(createKey(sql,autoGeneratedKeys)); + return pStmtPool.borrowObject(createKey(sql, autoGeneratedKeys)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { @@ -314,16 +523,12 @@ class PooledConnectionImpl } } - PreparedStatement prepareStatement(final String sql, final int resultSetType, - final int resultSetConcurrency, final int resultSetHoldability) - throws SQLException { - if (pstmtPool == null) { - return connection.prepareStatement(sql, resultSetType, - resultSetConcurrency, resultSetHoldability); + PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException { + if (pStmtPool == null) { + return connection.prepareStatement(sql, columnIndexes); } try { - return pstmtPool.borrowObject(createKey(sql, resultSetType, - resultSetConcurrency, resultSetHoldability)); + return pStmtPool.borrowObject(createKey(sql, columnIndexes)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { @@ -331,13 +536,29 @@ class PooledConnectionImpl } } - PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) - throws SQLException { - if (pstmtPool == null) { - return connection.prepareStatement(sql, columnIndexes); + /** + * Creates or obtains a {@link PreparedStatement} from my pool. + * + * @param sql + * a <code>String</code> object that is the SQL statement to be sent to the database; may contain one or + * more '?' IN parameters. + * @param resultSetType + * a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>, + * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>. + * @param resultSetConcurrency + * a concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or + * <code>ResultSet.CONCUR_UPDATABLE</code>. + * + * @return a {@link PoolablePreparedStatement}. + * @see Connection#prepareStatement(String, int, int) + */ + PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) + throws SQLException { + if (pStmtPool == null) { + return connection.prepareStatement(sql, resultSetType, resultSetConcurrency); } try { - return pstmtPool.borrowObject(createKey(sql, columnIndexes)); + return pStmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { @@ -345,13 +566,13 @@ class PooledConnectionImpl } } - PreparedStatement prepareStatement(final String sql, final String columnNames[]) - throws SQLException { - if (pstmtPool == null) { - return connection.prepareStatement(sql, columnNames); + PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, + final int resultSetHoldability) throws SQLException { + if (pStmtPool == null) { + return connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } try { - return pstmtPool.borrowObject(createKey(sql, columnNames)); + return pStmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { @@ -359,161 +580,60 @@ class PooledConnectionImpl } } - /** - * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments. - */ - protected PStmtKeyCPDS createKey(final String sql, final int autoGeneratedKeys) { - return new PStmtKeyCPDS(normalizeSQL(sql), autoGeneratedKeys); - } - - /** - * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments. - */ - protected PStmtKeyCPDS createKey(final String sql, final int resultSetType, - final int resultSetConcurrency, final int resultSetHoldability) { - return new PStmtKeyCPDS(normalizeSQL(sql), resultSetType, - resultSetConcurrency, resultSetHoldability); - } - - /** - * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments. - */ - protected PStmtKeyCPDS createKey(final String sql, final int columnIndexes[]) { - return new PStmtKeyCPDS(normalizeSQL(sql), columnIndexes); - } - - /** - * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments. - */ - protected PStmtKeyCPDS createKey(final String sql, final String columnNames[]) { - return new PStmtKeyCPDS(normalizeSQL(sql), columnNames); - } - - /** - * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments. - */ - protected PStmtKeyCPDS createKey(final String sql, final int resultSetType, - final int resultSetConcurrency) { - return new PStmtKeyCPDS(normalizeSQL(sql), resultSetType, - resultSetConcurrency); - } - - /** - * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments. - */ - protected PStmtKeyCPDS createKey(final String sql) { - return new PStmtKeyCPDS(normalizeSQL(sql)); - } - - /** - * Normalize the given SQL statement, producing a - * canonical form that is semantically equivalent to the original. - */ - protected String normalizeSQL(final String sql) { - return sql.trim(); - } - - /** - * My {@link KeyedPooledObjectFactory} method for creating - * {@link PreparedStatement}s. - * @param key the key for the {@link PreparedStatement} to be created - */ - @Override - public PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> makeObject(final PStmtKeyCPDS key) throws Exception { - if (null == key) { - throw new IllegalArgumentException(); + PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException { + if (pStmtPool == null) { + return connection.prepareStatement(sql, columnNames); } - // _openPstmts++; - if (null == key.getResultSetType() - && null == key.getResultSetConcurrency()) { - if (null == key.getAutoGeneratedKeys()) { - return new DefaultPooledObject<>(new PoolablePreparedStatement<>( - connection.prepareStatement(key.getSql()), - key, pstmtPool, delegatingConnection)); - } - return new DefaultPooledObject<>(new PoolablePreparedStatement<>( - connection.prepareStatement(key.getSql(), - key.getAutoGeneratedKeys().intValue()), - key, pstmtPool, delegatingConnection)); + try { + return pStmtPool.borrowObject(createKey(sql, columnNames)); + } catch (final RuntimeException e) { + throw e; + } catch (final Exception e) { + throw new SQLException("Borrow prepareStatement from pool failed", e); } - return new DefaultPooledObject<>(new PoolablePreparedStatement<>( - connection.prepareStatement(key.getSql(), - key.getResultSetType().intValue(), - key.getResultSetConcurrency().intValue()), - key, pstmtPool, delegatingConnection)); - } - - /** - * My {@link KeyedPooledObjectFactory} method for destroying - * {@link PreparedStatement}s. - * @param key ignored - * @param p the wrapped {@link PreparedStatement} to be destroyed. - */ - @Override - public void destroyObject(final PStmtKeyCPDS key, - final PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> p) - throws Exception { - p.getObject().getInnermostDelegate().close(); } /** - * My {@link KeyedPooledObjectFactory} method for validating - * {@link PreparedStatement}s. - * @param key ignored - * @param p ignored - * @return {@code true} + * {@inheritDoc} */ @Override - public boolean validateObject(final PStmtKeyCPDS key, - final PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> p) { - return true; + public void removeConnectionEventListener(final ConnectionEventListener listener) { + eventListeners.remove(listener); } - /** - * My {@link KeyedPooledObjectFactory} method for activating - * {@link PreparedStatement}s. - * @param key ignored - * @param p ignored - */ + /* JDBC_4_ANT_KEY_BEGIN */ @Override - public void activateObject(final PStmtKeyCPDS key, - final PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> p) - throws Exception { - p.getObject().activate(); + public void removeStatementEventListener(final StatementEventListener listener) { + statementEventListeners.remove(listener); } + /* JDBC_4_ANT_KEY_END */ /** - * My {@link KeyedPooledObjectFactory} method for passivating - * {@link PreparedStatement}s. Currently invokes {@link PreparedStatement#clearParameters}. - * @param key ignored - * @param p a wrapped {@link PreparedStatement} + * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to + * the underlying connection. (Default: false.) + * + * @param allow + * Access to the underlying connection is granted when true. */ - @Override - public void passivateObject(final PStmtKeyCPDS key, - final PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> p) - throws Exception { - final PoolablePreparedStatement<PStmtKeyCPDS> ppss = p.getObject(); - ppss.clearParameters(); - ppss.passivate(); + public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { + this.accessToUnderlyingConnectionAllowed = allow; } - /** - * Returns the value of the accessToUnderlyingConnectionAllowed property. - * - * @return true if access to the underlying is allowed, false otherwise. - */ - public synchronized boolean isAccessToUnderlyingConnectionAllowed() { - return this.accessToUnderlyingConnectionAllowed; + public void setStatementPool(final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> statementPool) { + pStmtPool = statementPool; } /** - * Sets the value of the accessToUnderlyingConnectionAllowed property. - * It controls if the PoolGuard allows access to the underlying connection. - * (Default: false) + * My {@link KeyedPooledObjectFactory} method for validating {@link PreparedStatement}s. * - * @param allow Access to the underlying connection is granted when true. + * @param key + * Ignored. + * @param pooledObject + * Ignored. + * @return {@code true} */ - public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { - this.accessToUnderlyingConnectionAllowed = allow; + @Override + public boolean validateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) { + return true; } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org