| /* |
| * 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.commons.dbcp2.cpdsadapter; |
| |
| import java.io.PrintWriter; |
| import java.io.Serializable; |
| import java.sql.DriverManager; |
| import java.sql.SQLException; |
| import java.sql.SQLFeatureNotSupportedException; |
| import java.util.Hashtable; |
| import java.util.Properties; |
| import java.util.logging.Logger; |
| |
| import javax.naming.Context; |
| import javax.naming.Name; |
| import javax.naming.NamingException; |
| import javax.naming.RefAddr; |
| import javax.naming.Reference; |
| import javax.naming.Referenceable; |
| import javax.naming.StringRefAddr; |
| import javax.naming.spi.ObjectFactory; |
| import javax.sql.ConnectionPoolDataSource; |
| import javax.sql.PooledConnection; |
| |
| import org.apache.commons.dbcp2.DelegatingPreparedStatement; |
| import org.apache.commons.dbcp2.PStmtKey; |
| import org.apache.commons.dbcp2.Utils; |
| import org.apache.commons.pool2.KeyedObjectPool; |
| import org.apache.commons.pool2.impl.BaseObjectPoolConfig; |
| import org.apache.commons.pool2.impl.GenericKeyedObjectPool; |
| import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; |
| |
| /** |
| * <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.commons.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 |
| * <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. |
| * </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. |
| * </p> |
| * |
| * @since 2.0 |
| */ |
| public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceable, Serializable, ObjectFactory { |
| |
| private static final String KEY_USER = "user"; |
| |
| private static final String KEY_PASSWORD = "password"; |
| |
| 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."; |
| |
| static { |
| // Attempt to prevent deadlocks - see DBCP - 272 |
| DriverManager.getDrivers(); |
| } |
| |
| /** Description */ |
| private String description; |
| |
| /** Url name */ |
| private String url; |
| |
| /** User name */ |
| 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; |
| // 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; |
| |
| /** Whether or not getConnection has been called */ |
| private volatile boolean getConnectionCalled; |
| |
| /** Connection properties passed to JDBC Driver */ |
| private Properties connectionProperties; |
| |
| /** |
| * Controls access to the underlying connection |
| */ |
| private boolean accessToUnderlyingConnectionAllowed; |
| |
| /** |
| * Default no-arg constructor for Serialization |
| */ |
| public DriverAdapterCPDS() { |
| } |
| |
| /** |
| * Throws an IllegalStateException, if a PooledConnection has already been requested. |
| */ |
| private void assertInitializationAllowed() throws IllegalStateException { |
| if (getConnectionCalled) { |
| throw new IllegalStateException(GET_CONNECTION_CALLED); |
| } |
| } |
| |
| private boolean getBooleanContentString(RefAddr ra) { |
| return Boolean.valueOf(getStringContent(ra)).booleanValue(); |
| } |
| |
| /** |
| * Gets the connection properties passed to the JDBC driver. |
| * |
| * @return the JDBC connection properties used when creating connections. |
| */ |
| public Properties getConnectionProperties() { |
| return connectionProperties; |
| } |
| |
| /** |
| * 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) |
| */ |
| public String getDescription() { |
| return description; |
| } |
| |
| /** |
| * Gets the driver class name. |
| * |
| * @return value of driver. |
| */ |
| public String getDriver() { |
| return driver; |
| } |
| |
| private int getIntegerStringContent(final RefAddr ra) { |
| return Integer.parseInt(getStringContent(ra)); |
| } |
| |
| /** |
| * 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() { |
| return loginTimeout; |
| } |
| |
| /** |
| * Gets the log writer for this data source. NOT USED. |
| */ |
| @Override |
| public PrintWriter getLogWriter() { |
| return logWriter; |
| } |
| |
| /** |
| * 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() { |
| return this.maxIdle; |
| } |
| |
| /** |
| * Gets the maximum number of prepared statements. |
| * |
| * @return maxPrepartedStatements value |
| */ |
| public int getMaxPreparedStatements() { |
| return maxPreparedStatements; |
| } |
| |
| /** |
| * 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 |
| * @see #setTimeBetweenEvictionRunsMillis |
| * @return the minimum amount of time a statement may sit idle in the pool. |
| */ |
| public int getMinEvictableIdleTimeMillis() { |
| return minEvictableIdleTimeMillis; |
| } |
| |
| /** |
| * Gets the number of statements to examine during each run of the idle object evictor thread (if any.) |
| * |
| * @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; |
| } |
| |
| /** |
| * Implements {@link 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 { |
| // 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; |
| if (ref.getClassName().equals(getClass().getName())) { |
| RefAddr ra = ref.get("description"); |
| if (isNotEmpty(ra)) { |
| setDescription(getStringContent(ra)); |
| } |
| |
| ra = ref.get("driver"); |
| if (isNotEmpty(ra)) { |
| setDriver(getStringContent(ra)); |
| } |
| ra = ref.get("url"); |
| if (isNotEmpty(ra)) { |
| setUrl(getStringContent(ra)); |
| } |
| ra = ref.get(KEY_USER); |
| if (isNotEmpty(ra)) { |
| setUser(getStringContent(ra)); |
| } |
| ra = ref.get(KEY_PASSWORD); |
| if (isNotEmpty(ra)) { |
| setPassword(getStringContent(ra)); |
| } |
| |
| ra = ref.get("poolPreparedStatements"); |
| if (isNotEmpty(ra)) { |
| setPoolPreparedStatements(getBooleanContentString(ra)); |
| } |
| ra = ref.get("maxIdle"); |
| if (isNotEmpty(ra)) { |
| setMaxIdle(getIntegerStringContent(ra)); |
| } |
| |
| ra = ref.get("timeBetweenEvictionRunsMillis"); |
| if (isNotEmpty(ra)) { |
| setTimeBetweenEvictionRunsMillis(getIntegerStringContent(ra)); |
| } |
| |
| ra = ref.get("numTestsPerEvictionRun"); |
| if (isNotEmpty(ra)) { |
| setNumTestsPerEvictionRun(getIntegerStringContent(ra)); |
| } |
| |
| ra = ref.get("minEvictableIdleTimeMillis"); |
| if (isNotEmpty(ra)) { |
| setMinEvictableIdleTimeMillis(getIntegerStringContent(ra)); |
| } |
| ra = ref.get("maxPreparedStatements"); |
| if (isNotEmpty(ra)) { |
| setMaxPreparedStatements(getIntegerStringContent(ra)); |
| } |
| |
| ra = ref.get("accessToUnderlyingConnectionAllowed"); |
| if (isNotEmpty(ra)) { |
| setAccessToUnderlyingConnectionAllowed(getBooleanContentString(ra)); |
| } |
| |
| cpds = this; |
| } |
| } |
| return cpds; |
| } |
| |
| @Override |
| public Logger getParentLogger() throws SQLFeatureNotSupportedException { |
| throw new SQLFeatureNotSupportedException(); |
| } |
| |
| /** |
| * Gets the value of password for the default user. |
| * |
| * @return value of password. |
| */ |
| public String getPassword() { |
| return Utils.toString(userPassword); |
| } |
| |
| /** |
| * Gets the value of password for the default user. |
| * |
| * @return value of password. |
| * @since 2.4.0 |
| */ |
| public char[] getPasswordCharArray() { |
| return userPassword; |
| } |
| |
| /** |
| * Attempts to establish a database connection using the default user and password. |
| */ |
| @Override |
| public PooledConnection getPooledConnection() throws SQLException { |
| return getPooledConnection(getUser(), getPassword()); |
| } |
| |
| /** |
| * Attempts to establish a database 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 pooledUserName, final String pooledUserPassword) |
| throws SQLException { |
| getConnectionCalled = true; |
| PooledConnectionImpl pooledConnection = null; |
| // Workaround for buggy WebLogic 5.1 classloader - ignore the exception upon first invocation. |
| try { |
| if (connectionProperties != null) { |
| update(connectionProperties, KEY_USER, pooledUserName); |
| update(connectionProperties, KEY_PASSWORD, pooledUserPassword); |
| pooledConnection = new PooledConnectionImpl( |
| DriverManager.getConnection(getUrl(), connectionProperties)); |
| } else { |
| pooledConnection = new PooledConnectionImpl( |
| DriverManager.getConnection(getUrl(), pooledUserName, pooledUserPassword)); |
| } |
| pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); |
| } catch (final ClassCircularityError e) { |
| if (connectionProperties != null) { |
| pooledConnection = new PooledConnectionImpl( |
| DriverManager.getConnection(getUrl(), connectionProperties)); |
| } else { |
| pooledConnection = new PooledConnectionImpl( |
| DriverManager.getConnection(getUrl(), pooledUserName, pooledUserPassword)); |
| } |
| pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); |
| } |
| KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = null; |
| if (isPoolPreparedStatements()) { |
| final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> 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. |
| config.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis()); |
| config.setNumTestsPerEvictionRun(getNumTestsPerEvictionRun()); |
| config.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis()); |
| } 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<>(pooledConnection, config); |
| pooledConnection.setStatementPool(stmtPool); |
| } |
| return pooledConnection; |
| } |
| |
| /** |
| * Implements {@link Referenceable}. |
| */ |
| @Override |
| public Reference getReference() throws NamingException { |
| // this class implements its own factory |
| final String factory = getClass().getName(); |
| |
| final Reference ref = new Reference(getClass().getName(), factory, null); |
| |
| ref.add(new StringRefAddr("description", getDescription())); |
| ref.add(new StringRefAddr("driver", getDriver())); |
| 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()))); |
| |
| return ref; |
| } |
| |
| private String getStringContent(RefAddr ra) { |
| return ra.getContent().toString(); |
| } |
| |
| /** |
| * 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; |
| } |
| |
| /** |
| * Gets the value of url used to locate the database for this datasource. |
| * |
| * @return value of url. |
| */ |
| public String getUrl() { |
| return url; |
| } |
| |
| /** |
| * Gets the value of default user (login or user name). |
| * |
| * @return value of user. |
| */ |
| public String getUser() { |
| return userName; |
| } |
| |
| /** |
| * 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; |
| } |
| |
| private boolean isNotEmpty(RefAddr ra) { |
| return ra != null && ra.getContent() != null; |
| } |
| |
| /** |
| * Whether to toggle the pooling of <code>PreparedStatement</code>s |
| * |
| * @return value of poolPreparedStatements. |
| */ |
| public boolean isPoolPreparedStatements() { |
| return poolPreparedStatements; |
| } |
| |
| /** |
| * 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. |
| */ |
| public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { |
| this.accessToUnderlyingConnectionAllowed = allow; |
| } |
| |
| /** |
| * Sets the connection properties passed to the JDBC driver. |
| * <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 != null) { |
| if (connectionProperties.containsKey(KEY_USER)) { |
| setUser(connectionProperties.getProperty(KEY_USER)); |
| } |
| if (connectionProperties.containsKey(KEY_PASSWORD)) { |
| setPassword(connectionProperties.getProperty(KEY_PASSWORD)); |
| } |
| } |
| } |
| |
| /** |
| * 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. |
| */ |
| public void setDescription(final String v) { |
| this.description = v; |
| } |
| |
| /** |
| * 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(); |
| this.driver = v; |
| // make sure driver is registered |
| Class.forName(v); |
| } |
| |
| /** |
| * 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) { |
| loginTimeout = seconds; |
| } |
| |
| /** |
| * Sets the log writer for this data source. NOT USED. |
| */ |
| @Override |
| public void setLogWriter(final PrintWriter out) { |
| logWriter = out; |
| } |
| |
| /** |
| * 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 |
| */ |
| public void setMaxIdle(final int maxIdle) { |
| assertInitializationAllowed(); |
| this.maxIdle = maxIdle; |
| } |
| |
| /** |
| * Sets the maximum number of prepared statements. |
| * |
| * @param maxPreparedStatements |
| * the new maximum number of prepared statements |
| */ |
| public void setMaxPreparedStatements(final int maxPreparedStatements) { |
| this.maxPreparedStatements = maxPreparedStatements; |
| } |
| |
| /** |
| * 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 |
| */ |
| public void setMinEvictableIdleTimeMillis(final int minEvictableIdleTimeMillis) { |
| assertInitializationAllowed(); |
| this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; |
| } |
| |
| /** |
| * 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. |
| * </p> |
| * |
| * @param numTestsPerEvictionRun |
| * number of statements to examine per run |
| * @see #getNumTestsPerEvictionRun() |
| * @see #setTimeBetweenEvictionRunsMillis(long) |
| * @throws IllegalStateException |
| * if {@link #getPooledConnection()} has been called |
| */ |
| public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) { |
| assertInitializationAllowed(); |
| this.numTestsPerEvictionRun = numTestsPerEvictionRun; |
| } |
| |
| /** |
| * 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 char[] userPassword) { |
| assertInitializationAllowed(); |
| this.userPassword = Utils.clone(userPassword); |
| update(connectionProperties, KEY_PASSWORD, Utils.toString(this.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); |
| } |
| |
| /** |
| * Whether to toggle the pooling of <code>PreparedStatement</code>s |
| * |
| * @param poolPreparedStatements |
| * true to pool statements. |
| * @throws IllegalStateException |
| * if {@link #getPooledConnection()} has been called |
| */ |
| public void setPoolPreparedStatements(final boolean poolPreparedStatements) { |
| assertInitializationAllowed(); |
| this.poolPreparedStatements = poolPreparedStatements; |
| } |
| |
| /** |
| * 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 |
| */ |
| public void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) { |
| assertInitializationAllowed(); |
| this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; |
| } |
| |
| /** |
| * 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 |
| */ |
| public void setUrl(final String v) { |
| assertInitializationAllowed(); |
| this.url = v; |
| } |
| |
| /** |
| * 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.userName = v; |
| update(connectionProperties, KEY_USER, v); |
| } |
| |
| /** |
| * Does not print the userName and userPassword field nor the 'user' or 'password' in the connectionProperties. |
| * |
| * @since 2.6.0 |
| */ |
| @Override |
| public synchronized String toString() { |
| final StringBuilder builder = new StringBuilder(super.toString()); |
| builder.append("[description="); |
| builder.append(description); |
| builder.append(", url="); |
| // TODO What if the connection string contains a 'user' or 'password' query parameter but that connection string is not in a legal URL format? |
| builder.append(url); |
| builder.append(", driver="); |
| builder.append(driver); |
| builder.append(", loginTimeout="); |
| builder.append(loginTimeout); |
| builder.append(", poolPreparedStatements="); |
| builder.append(poolPreparedStatements); |
| builder.append(", maxIdle="); |
| builder.append(maxIdle); |
| builder.append(", timeBetweenEvictionRunsMillis="); |
| builder.append(timeBetweenEvictionRunsMillis); |
| builder.append(", numTestsPerEvictionRun="); |
| builder.append(numTestsPerEvictionRun); |
| builder.append(", minEvictableIdleTimeMillis="); |
| builder.append(minEvictableIdleTimeMillis); |
| builder.append(", maxPreparedStatements="); |
| builder.append(maxPreparedStatements); |
| builder.append(", getConnectionCalled="); |
| builder.append(getConnectionCalled); |
| builder.append(", connectionProperties="); |
| Properties tmpProps = connectionProperties; |
| final String pwdKey = "password"; |
| if (connectionProperties != null && connectionProperties.contains(pwdKey)) { |
| tmpProps = (Properties) connectionProperties.clone(); |
| tmpProps.remove(pwdKey); |
| } |
| builder.append(tmpProps); |
| builder.append(", accessToUnderlyingConnectionAllowed="); |
| builder.append(accessToUnderlyingConnectionAllowed); |
| builder.append("]"); |
| return builder.toString(); |
| } |
| |
| private void update(final Properties properties, final String key, final String value) { |
| if (properties != null && key != null) { |
| if (value == null) { |
| properties.remove(key); |
| } else { |
| properties.setProperty(key, value); |
| } |
| } |
| } |
| } |