init
This commit is contained in:
180
java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
Normal file
180
java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.TrackedUse;
|
||||
|
||||
/**
|
||||
* Tracks db connection usage for recovering and reporting abandoned db connections.
|
||||
* <p>
|
||||
* The JDBC Connection, Statement, and ResultSet classes extend this class.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AbandonedTrace implements TrackedUse {
|
||||
|
||||
/** A list of objects created by children of this object. */
|
||||
private final List<WeakReference<AbandonedTrace>> traceList = new ArrayList<>();
|
||||
|
||||
/** Last time this connection was used. */
|
||||
private volatile long lastUsedMillis = 0;
|
||||
|
||||
/**
|
||||
* Creates a new AbandonedTrace without config and without doing abandoned tracing.
|
||||
*/
|
||||
public AbandonedTrace() {
|
||||
init(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new AbandonedTrace with a parent object.
|
||||
*
|
||||
* @param parent
|
||||
* AbandonedTrace parent object.
|
||||
*/
|
||||
public AbandonedTrace(final AbandonedTrace parent) {
|
||||
init(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an object to the list of objects being traced.
|
||||
*
|
||||
* @param trace
|
||||
* AbandonedTrace object to add.
|
||||
*/
|
||||
protected void addTrace(final AbandonedTrace trace) {
|
||||
synchronized (this.traceList) {
|
||||
this.traceList.add(new WeakReference<>(trace));
|
||||
}
|
||||
setLastUsed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the list of objects being traced by this object.
|
||||
*/
|
||||
protected void clearTrace() {
|
||||
synchronized (this.traceList) {
|
||||
this.traceList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last time this object was used in milliseconds.
|
||||
*
|
||||
* @return long time in milliseconds.
|
||||
*/
|
||||
@Override
|
||||
public long getLastUsed() {
|
||||
return lastUsedMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of objects being traced by this object.
|
||||
*
|
||||
* @return List of objects.
|
||||
*/
|
||||
protected List<AbandonedTrace> getTrace() {
|
||||
final int size = traceList.size();
|
||||
if (size == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final ArrayList<AbandonedTrace> result = new ArrayList<>(size);
|
||||
synchronized (this.traceList) {
|
||||
final Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final AbandonedTrace trace = iter.next().get();
|
||||
if (trace == null) {
|
||||
// Clean-up since we are here anyway
|
||||
iter.remove();
|
||||
} else {
|
||||
result.add(trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes abandoned tracing for this object.
|
||||
*
|
||||
* @param parent
|
||||
* AbandonedTrace parent object.
|
||||
*/
|
||||
private void init(final AbandonedTrace parent) {
|
||||
if (parent != null) {
|
||||
parent.addTrace(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this object the source object is tracing.
|
||||
*
|
||||
* @param source The object tracing
|
||||
* @since 2.7.0
|
||||
*/
|
||||
protected void removeThisTrace(final Object source) {
|
||||
if (source instanceof AbandonedTrace) {
|
||||
AbandonedTrace.class.cast(source).removeTrace(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a child object this object is tracing.
|
||||
*
|
||||
* @param trace
|
||||
* AbandonedTrace object to remove.
|
||||
*/
|
||||
protected void removeTrace(final AbandonedTrace trace) {
|
||||
synchronized (this.traceList) {
|
||||
final Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final AbandonedTrace traceInList = iter.next().get();
|
||||
if (trace != null && trace.equals(traceInList)) {
|
||||
iter.remove();
|
||||
break;
|
||||
} else if (traceInList == null) {
|
||||
// Clean-up since we are here anyway
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time this object was last used to the current time in milliseconds.
|
||||
*/
|
||||
protected void setLastUsed() {
|
||||
lastUsedMillis = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time in milliseconds this object was last used.
|
||||
*
|
||||
* @param lastUsedMillis
|
||||
* time in milliseconds.
|
||||
*/
|
||||
protected void setLastUsed(final long lastUsedMillis) {
|
||||
this.lastUsedMillis = lastUsedMillis;
|
||||
}
|
||||
}
|
||||
2460
java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
Normal file
2460
java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
Normal file
File diff suppressed because it is too large
Load Diff
602
java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
Normal file
602
java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Connection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.RefAddr;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.spi.ObjectFactory;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.dbcp.pool2.impl.BaseObjectPoolConfig;
|
||||
import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPoolConfig;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* JNDI object factory that creates an instance of <code>BasicDataSource</code> that has been configured based on the
|
||||
* <code>RefAddr</code> values of the specified <code>Reference</code>, which must match the names and data types of the
|
||||
* <code>BasicDataSource</code> bean properties with the following exceptions:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><code>connectionInitSqls</code> must be passed to this factory as a single String using semi-colon to delimit the
|
||||
* statements whereas <code>BasicDataSource</code> requires a collection of Strings.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class BasicDataSourceFactory implements ObjectFactory {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BasicDataSourceFactory.class);
|
||||
|
||||
private static final String PROP_DEFAULT_AUTO_COMMIT = "defaultAutoCommit";
|
||||
private static final String PROP_DEFAULT_READ_ONLY = "defaultReadOnly";
|
||||
private static final String PROP_DEFAULT_TRANSACTION_ISOLATION = "defaultTransactionIsolation";
|
||||
private static final String PROP_DEFAULT_CATALOG = "defaultCatalog";
|
||||
private static final String PROP_DEFAULT_SCHEMA = "defaultSchema";
|
||||
private static final String PROP_CACHE_STATE = "cacheState";
|
||||
private static final String PROP_DRIVER_CLASS_NAME = "driverClassName";
|
||||
private static final String PROP_LIFO = "lifo";
|
||||
private static final String PROP_MAX_TOTAL = "maxTotal";
|
||||
private static final String PROP_MAX_IDLE = "maxIdle";
|
||||
private static final String PROP_MIN_IDLE = "minIdle";
|
||||
private static final String PROP_INITIAL_SIZE = "initialSize";
|
||||
private static final String PROP_MAX_WAIT_MILLIS = "maxWaitMillis";
|
||||
private static final String PROP_TEST_ON_CREATE = "testOnCreate";
|
||||
private static final String PROP_TEST_ON_BORROW = "testOnBorrow";
|
||||
private static final String PROP_TEST_ON_RETURN = "testOnReturn";
|
||||
private static final String PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS = "timeBetweenEvictionRunsMillis";
|
||||
private static final String PROP_NUM_TESTS_PER_EVICTION_RUN = "numTestsPerEvictionRun";
|
||||
private static final String PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS = "minEvictableIdleTimeMillis";
|
||||
private static final String PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = "softMinEvictableIdleTimeMillis";
|
||||
private static final String PROP_EVICTION_POLICY_CLASS_NAME = "evictionPolicyClassName";
|
||||
private static final String PROP_TEST_WHILE_IDLE = "testWhileIdle";
|
||||
private static final String PROP_PASSWORD = "password";
|
||||
private static final String PROP_URL = "url";
|
||||
private static final String PROP_USER_NAME = "username";
|
||||
private static final String PROP_VALIDATION_QUERY = "validationQuery";
|
||||
private static final String PROP_VALIDATION_QUERY_TIMEOUT = "validationQueryTimeout";
|
||||
private static final String PROP_JMX_NAME = "jmxName";
|
||||
private static final String PROP_CONNECTION_FACTORY_CLASS_NAME = "connectionFactoryClassName";
|
||||
|
||||
/**
|
||||
* The property name for connectionInitSqls. The associated value String must be of the form [query;]*
|
||||
*/
|
||||
private static final String PROP_CONNECTION_INIT_SQLS = "connectionInitSqls";
|
||||
private static final String PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED = "accessToUnderlyingConnectionAllowed";
|
||||
private static final String PROP_REMOVE_ABANDONED_ON_BORROW = "removeAbandonedOnBorrow";
|
||||
private static final String PROP_REMOVE_ABANDONED_ON_MAINTENANCE = "removeAbandonedOnMaintenance";
|
||||
private static final String PROP_REMOVE_ABANDONED_TIMEOUT = "removeAbandonedTimeout";
|
||||
private static final String PROP_LOG_ABANDONED = "logAbandoned";
|
||||
private static final String PROP_ABANDONED_USAGE_TRACKING = "abandonedUsageTracking";
|
||||
private static final String PROP_POOL_PREPARED_STATEMENTS = "poolPreparedStatements";
|
||||
private static final String PROP_MAX_OPEN_PREPARED_STATEMENTS = "maxOpenPreparedStatements";
|
||||
private static final String PROP_CONNECTION_PROPERTIES = "connectionProperties";
|
||||
private static final String PROP_MAX_CONN_LIFETIME_MILLIS = "maxConnLifetimeMillis";
|
||||
private static final String PROP_LOG_EXPIRED_CONNECTIONS = "logExpiredConnections";
|
||||
private static final String PROP_ROLLBACK_ON_RETURN = "rollbackOnReturn";
|
||||
private static final String PROP_ENABLE_AUTO_COMMIT_ON_RETURN = "enableAutoCommitOnReturn";
|
||||
private static final String PROP_DEFAULT_QUERY_TIMEOUT = "defaultQueryTimeout";
|
||||
private static final String PROP_FAST_FAIL_VALIDATION = "fastFailValidation";
|
||||
|
||||
/**
|
||||
* Value string must be of the form [STATE_CODE,]*
|
||||
*/
|
||||
private static final String PROP_DISCONNECTION_SQL_CODES = "disconnectionSqlCodes";
|
||||
|
||||
/*
|
||||
* Block with obsolete properties from DBCP 1.x. Warn users that these are ignored and they should use the 2.x
|
||||
* properties.
|
||||
*/
|
||||
private static final String NUPROP_MAX_ACTIVE = "maxActive";
|
||||
private static final String NUPROP_REMOVE_ABANDONED = "removeAbandoned";
|
||||
private static final String NUPROP_MAXWAIT = "maxWait";
|
||||
|
||||
/*
|
||||
* Block with properties expected in a DataSource This props will not be listed as ignored - we know that they may
|
||||
* appear in Resource, and not listing them as ignored.
|
||||
*/
|
||||
private static final String SILENT_PROP_FACTORY = "factory";
|
||||
private static final String SILENT_PROP_SCOPE = "scope";
|
||||
private static final String SILENT_PROP_SINGLETON = "singleton";
|
||||
private static final String SILENT_PROP_AUTH = "auth";
|
||||
|
||||
private static final String[] ALL_PROPERTIES = {PROP_DEFAULT_AUTO_COMMIT, PROP_DEFAULT_READ_ONLY,
|
||||
PROP_DEFAULT_TRANSACTION_ISOLATION, PROP_DEFAULT_CATALOG, PROP_DEFAULT_SCHEMA, PROP_CACHE_STATE,
|
||||
PROP_DRIVER_CLASS_NAME, PROP_LIFO, PROP_MAX_TOTAL, PROP_MAX_IDLE, PROP_MIN_IDLE, PROP_INITIAL_SIZE,
|
||||
PROP_MAX_WAIT_MILLIS, PROP_TEST_ON_CREATE, PROP_TEST_ON_BORROW, PROP_TEST_ON_RETURN,
|
||||
PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS, PROP_NUM_TESTS_PER_EVICTION_RUN, PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS,
|
||||
PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS, PROP_EVICTION_POLICY_CLASS_NAME, PROP_TEST_WHILE_IDLE, PROP_PASSWORD,
|
||||
PROP_URL, PROP_USER_NAME, PROP_VALIDATION_QUERY, PROP_VALIDATION_QUERY_TIMEOUT, PROP_CONNECTION_INIT_SQLS,
|
||||
PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED, PROP_REMOVE_ABANDONED_ON_BORROW, PROP_REMOVE_ABANDONED_ON_MAINTENANCE,
|
||||
PROP_REMOVE_ABANDONED_TIMEOUT, PROP_LOG_ABANDONED, PROP_ABANDONED_USAGE_TRACKING, PROP_POOL_PREPARED_STATEMENTS,
|
||||
PROP_MAX_OPEN_PREPARED_STATEMENTS, PROP_CONNECTION_PROPERTIES, PROP_MAX_CONN_LIFETIME_MILLIS,
|
||||
PROP_LOG_EXPIRED_CONNECTIONS, PROP_ROLLBACK_ON_RETURN, PROP_ENABLE_AUTO_COMMIT_ON_RETURN,
|
||||
PROP_DEFAULT_QUERY_TIMEOUT, PROP_FAST_FAIL_VALIDATION, PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME,
|
||||
PROP_CONNECTION_FACTORY_CLASS_NAME };
|
||||
|
||||
/**
|
||||
* Obsolete properties from DBCP 1.x. with warning strings suggesting new properties. LinkedHashMap will guarantee
|
||||
* that properties will be listed to output in order of insertion into map.
|
||||
*/
|
||||
private static final Map<String, String> NUPROP_WARNTEXT = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
NUPROP_WARNTEXT.put(NUPROP_MAX_ACTIVE,
|
||||
"Property " + NUPROP_MAX_ACTIVE + " is not used in DBCP2, use " + PROP_MAX_TOTAL + " instead. "
|
||||
+ PROP_MAX_TOTAL + " default value is " + GenericObjectPoolConfig.DEFAULT_MAX_TOTAL + ".");
|
||||
NUPROP_WARNTEXT.put(NUPROP_REMOVE_ABANDONED,
|
||||
"Property " + NUPROP_REMOVE_ABANDONED + " is not used in DBCP2," + " use one or both of "
|
||||
+ PROP_REMOVE_ABANDONED_ON_BORROW + " or " + PROP_REMOVE_ABANDONED_ON_MAINTENANCE + " instead. "
|
||||
+ "Both have default value set to false.");
|
||||
NUPROP_WARNTEXT.put(NUPROP_MAXWAIT,
|
||||
"Property " + NUPROP_MAXWAIT + " is not used in DBCP2" + " , use " + PROP_MAX_WAIT_MILLIS + " instead. "
|
||||
+ PROP_MAX_WAIT_MILLIS + " default value is " + BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS
|
||||
+ ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Silent Properties. These properties will not be listed as ignored - we know that they may appear in JDBC Resource
|
||||
* references, and we will not list them as ignored.
|
||||
*/
|
||||
private static final List<String> SILENT_PROPERTIES = new ArrayList<>();
|
||||
|
||||
static {
|
||||
SILENT_PROPERTIES.add(SILENT_PROP_FACTORY);
|
||||
SILENT_PROPERTIES.add(SILENT_PROP_SCOPE);
|
||||
SILENT_PROPERTIES.add(SILENT_PROP_SINGLETON);
|
||||
SILENT_PROPERTIES.add(SILENT_PROP_AUTH);
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------- ObjectFactory Methods
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Create and return a new <code>BasicDataSource</code> instance. If no instance can be created, return
|
||||
* <code>null</code> instead.
|
||||
* </p>
|
||||
*
|
||||
* @param obj
|
||||
* The possibly null object containing location or reference information that can be used in creating an
|
||||
* object
|
||||
* @param name
|
||||
* The name of this object relative to <code>nameCtx</code>
|
||||
* @param nameCtx
|
||||
* The context relative to which the <code>name</code> parameter is specified, or <code>null</code> if
|
||||
* <code>name</code> is relative to the default initial context
|
||||
* @param environment
|
||||
* The possibly null environment that is used in creating this object
|
||||
*
|
||||
* @throws Exception
|
||||
* if an exception occurs creating the instance
|
||||
*/
|
||||
@Override
|
||||
public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx,
|
||||
final Hashtable<?, ?> environment) throws Exception {
|
||||
|
||||
// We only know how to deal with <code>javax.naming.Reference</code>s
|
||||
// that specify a class name of "javax.sql.DataSource"
|
||||
if (obj == null || !(obj instanceof Reference)) {
|
||||
return null;
|
||||
}
|
||||
final Reference ref = (Reference) obj;
|
||||
if (!"javax.sql.DataSource".equals(ref.getClassName())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check property names and log warnings about obsolete and / or unknown properties
|
||||
final List<String> warnings = new ArrayList<>();
|
||||
final List<String> infoMessages = new ArrayList<>();
|
||||
validatePropertyNames(ref, name, warnings, infoMessages);
|
||||
for (final String warning : warnings) {
|
||||
log.warn(warning);
|
||||
}
|
||||
for (final String infoMessage : infoMessages) {
|
||||
log.info(infoMessage);
|
||||
}
|
||||
|
||||
final Properties properties = new Properties();
|
||||
for (final String propertyName : ALL_PROPERTIES) {
|
||||
final RefAddr ra = ref.get(propertyName);
|
||||
if (ra != null) {
|
||||
final String propertyValue = ra.getContent().toString();
|
||||
properties.setProperty(propertyName, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
return createDataSource(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects warnings and info messages. Warnings are generated when an obsolete property is set. Unknown properties
|
||||
* generate info messages.
|
||||
*
|
||||
* @param ref
|
||||
* Reference to check properties of
|
||||
* @param name
|
||||
* Name provided to getObject
|
||||
* @param warnings
|
||||
* container for warning messages
|
||||
* @param infoMessages
|
||||
* container for info messages
|
||||
*/
|
||||
private void validatePropertyNames(final Reference ref, final Name name, final List<String> warnings,
|
||||
final List<String> infoMessages) {
|
||||
final List<String> allPropsAsList = Arrays.asList(ALL_PROPERTIES);
|
||||
final String nameString = name != null ? "Name = " + name.toString() + " " : "";
|
||||
if (NUPROP_WARNTEXT != null && !NUPROP_WARNTEXT.keySet().isEmpty()) {
|
||||
for (final String propertyName : NUPROP_WARNTEXT.keySet()) {
|
||||
final RefAddr ra = ref.get(propertyName);
|
||||
if (ra != null && !allPropsAsList.contains(ra.getType())) {
|
||||
final StringBuilder stringBuilder = new StringBuilder(nameString);
|
||||
final String propertyValue = ra.getContent().toString();
|
||||
stringBuilder.append(NUPROP_WARNTEXT.get(propertyName)).append(" You have set value of \"")
|
||||
.append(propertyValue).append("\" for \"").append(propertyName)
|
||||
.append("\" property, which is being ignored.");
|
||||
warnings.add(stringBuilder.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Enumeration<RefAddr> allRefAddrs = ref.getAll();
|
||||
while (allRefAddrs.hasMoreElements()) {
|
||||
final RefAddr ra = allRefAddrs.nextElement();
|
||||
final String propertyName = ra.getType();
|
||||
// If property name is not in the properties list, we haven't warned on it
|
||||
// and it is not in the "silent" list, tell user we are ignoring it.
|
||||
if (!(allPropsAsList.contains(propertyName) || NUPROP_WARNTEXT.keySet().contains(propertyName)
|
||||
|| SILENT_PROPERTIES.contains(propertyName))) {
|
||||
final String propertyValue = ra.getContent().toString();
|
||||
final StringBuilder stringBuilder = new StringBuilder(nameString);
|
||||
stringBuilder.append("Ignoring unknown property: ").append("value of \"").append(propertyValue)
|
||||
.append("\" for \"").append(propertyName).append("\" property");
|
||||
infoMessages.add(stringBuilder.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and configures a {@link BasicDataSource} instance based on the given properties.
|
||||
*
|
||||
* @param properties
|
||||
* The data source configuration properties.
|
||||
* @return A new a {@link BasicDataSource} instance based on the given properties.
|
||||
* @throws Exception
|
||||
* Thrown when an error occurs creating the data source.
|
||||
*/
|
||||
public static BasicDataSource createDataSource(final Properties properties) throws Exception {
|
||||
final BasicDataSource dataSource = new BasicDataSource();
|
||||
String value = null;
|
||||
|
||||
value = properties.getProperty(PROP_DEFAULT_AUTO_COMMIT);
|
||||
if (value != null) {
|
||||
dataSource.setDefaultAutoCommit(Boolean.valueOf(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_DEFAULT_READ_ONLY);
|
||||
if (value != null) {
|
||||
dataSource.setDefaultReadOnly(Boolean.valueOf(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_DEFAULT_TRANSACTION_ISOLATION);
|
||||
if (value != null) {
|
||||
int level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
|
||||
if ("NONE".equalsIgnoreCase(value)) {
|
||||
level = Connection.TRANSACTION_NONE;
|
||||
} else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
|
||||
level = Connection.TRANSACTION_READ_COMMITTED;
|
||||
} else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
|
||||
level = Connection.TRANSACTION_READ_UNCOMMITTED;
|
||||
} else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
|
||||
level = Connection.TRANSACTION_REPEATABLE_READ;
|
||||
} else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
|
||||
level = Connection.TRANSACTION_SERIALIZABLE;
|
||||
} else {
|
||||
try {
|
||||
level = Integer.parseInt(value);
|
||||
} catch (final NumberFormatException e) {
|
||||
System.err.println("Could not parse defaultTransactionIsolation: " + value);
|
||||
System.err.println("WARNING: defaultTransactionIsolation not set");
|
||||
System.err.println("using default value of database driver");
|
||||
level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
|
||||
}
|
||||
}
|
||||
dataSource.setDefaultTransactionIsolation(level);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_DEFAULT_CATALOG);
|
||||
if (value != null) {
|
||||
dataSource.setDefaultCatalog(value);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_DEFAULT_SCHEMA);
|
||||
if (value != null) {
|
||||
dataSource.setDefaultSchema(value);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_CACHE_STATE);
|
||||
if (value != null) {
|
||||
dataSource.setCacheState(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_DRIVER_CLASS_NAME);
|
||||
if (value != null) {
|
||||
dataSource.setDriverClassName(value);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_LIFO);
|
||||
if (value != null) {
|
||||
dataSource.setLifo(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_MAX_TOTAL);
|
||||
if (value != null) {
|
||||
dataSource.setMaxTotal(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_MAX_IDLE);
|
||||
if (value != null) {
|
||||
dataSource.setMaxIdle(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_MIN_IDLE);
|
||||
if (value != null) {
|
||||
dataSource.setMinIdle(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_INITIAL_SIZE);
|
||||
if (value != null) {
|
||||
dataSource.setInitialSize(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_MAX_WAIT_MILLIS);
|
||||
if (value != null) {
|
||||
dataSource.setMaxWaitMillis(Long.parseLong(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_TEST_ON_CREATE);
|
||||
if (value != null) {
|
||||
dataSource.setTestOnCreate(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_TEST_ON_BORROW);
|
||||
if (value != null) {
|
||||
dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_TEST_ON_RETURN);
|
||||
if (value != null) {
|
||||
dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS);
|
||||
if (value != null) {
|
||||
dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_NUM_TESTS_PER_EVICTION_RUN);
|
||||
if (value != null) {
|
||||
dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS);
|
||||
if (value != null) {
|
||||
dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
|
||||
if (value != null) {
|
||||
dataSource.setSoftMinEvictableIdleTimeMillis(Long.parseLong(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_EVICTION_POLICY_CLASS_NAME);
|
||||
if (value != null) {
|
||||
dataSource.setEvictionPolicyClassName(value);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_TEST_WHILE_IDLE);
|
||||
if (value != null) {
|
||||
dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_PASSWORD);
|
||||
if (value != null) {
|
||||
dataSource.setPassword(value);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_URL);
|
||||
if (value != null) {
|
||||
dataSource.setUrl(value);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_USER_NAME);
|
||||
if (value != null) {
|
||||
dataSource.setUsername(value);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_VALIDATION_QUERY);
|
||||
if (value != null) {
|
||||
dataSource.setValidationQuery(value);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_VALIDATION_QUERY_TIMEOUT);
|
||||
if (value != null) {
|
||||
dataSource.setValidationQueryTimeout(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED);
|
||||
if (value != null) {
|
||||
dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_REMOVE_ABANDONED_ON_BORROW);
|
||||
if (value != null) {
|
||||
dataSource.setRemoveAbandonedOnBorrow(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_REMOVE_ABANDONED_ON_MAINTENANCE);
|
||||
if (value != null) {
|
||||
dataSource.setRemoveAbandonedOnMaintenance(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_REMOVE_ABANDONED_TIMEOUT);
|
||||
if (value != null) {
|
||||
dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_LOG_ABANDONED);
|
||||
if (value != null) {
|
||||
dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_ABANDONED_USAGE_TRACKING);
|
||||
if (value != null) {
|
||||
dataSource.setAbandonedUsageTracking(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_POOL_PREPARED_STATEMENTS);
|
||||
if (value != null) {
|
||||
dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_MAX_OPEN_PREPARED_STATEMENTS);
|
||||
if (value != null) {
|
||||
dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_CONNECTION_INIT_SQLS);
|
||||
if (value != null) {
|
||||
dataSource.setConnectionInitSqls(parseList(value, ';'));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_CONNECTION_PROPERTIES);
|
||||
if (value != null) {
|
||||
final Properties p = getProperties(value);
|
||||
final Enumeration<?> e = p.propertyNames();
|
||||
while (e.hasMoreElements()) {
|
||||
final String propertyName = (String) e.nextElement();
|
||||
dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_MAX_CONN_LIFETIME_MILLIS);
|
||||
if (value != null) {
|
||||
dataSource.setMaxConnLifetimeMillis(Long.parseLong(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_LOG_EXPIRED_CONNECTIONS);
|
||||
if (value != null) {
|
||||
dataSource.setLogExpiredConnections(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_JMX_NAME);
|
||||
if (value != null) {
|
||||
dataSource.setJmxName(value);
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_ENABLE_AUTO_COMMIT_ON_RETURN);
|
||||
if (value != null) {
|
||||
dataSource.setAutoCommitOnReturn(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_ROLLBACK_ON_RETURN);
|
||||
if (value != null) {
|
||||
dataSource.setRollbackOnReturn(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_DEFAULT_QUERY_TIMEOUT);
|
||||
if (value != null) {
|
||||
dataSource.setDefaultQueryTimeout(Integer.valueOf(value));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_FAST_FAIL_VALIDATION);
|
||||
if (value != null) {
|
||||
dataSource.setFastFailValidation(Boolean.valueOf(value).booleanValue());
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_DISCONNECTION_SQL_CODES);
|
||||
if (value != null) {
|
||||
dataSource.setDisconnectionSqlCodes(parseList(value, ','));
|
||||
}
|
||||
|
||||
value = properties.getProperty(PROP_CONNECTION_FACTORY_CLASS_NAME);
|
||||
if (value != null) {
|
||||
dataSource.setConnectionFactoryClassName(value);
|
||||
}
|
||||
|
||||
// DBCP-215
|
||||
// Trick to make sure that initialSize connections are created
|
||||
if (dataSource.getInitialSize() > 0) {
|
||||
dataSource.getLogWriter();
|
||||
}
|
||||
|
||||
// Return the configured DataSource instance
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Parse properties from the string. Format of the string must be [propertyName=property;]*
|
||||
* <p>
|
||||
*
|
||||
* @param propText
|
||||
* @return Properties
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Properties getProperties(final String propText) throws Exception {
|
||||
final Properties p = new Properties();
|
||||
if (propText != null) {
|
||||
p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes(StandardCharsets.ISO_8859_1)));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse list of property values from a delimited string
|
||||
*
|
||||
* @param value
|
||||
* delimited list of values
|
||||
* @param delimiter
|
||||
* character used to separate values in the list
|
||||
* @return String Collection of values
|
||||
*/
|
||||
private static Collection<String> parseList(final String value, final char delimiter) {
|
||||
final StringTokenizer tokenizer = new StringTokenizer(value, Character.toString(delimiter));
|
||||
final Collection<String> tokens = new ArrayList<>(tokenizer.countTokens());
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
tokens.add(tokenizer.nextToken());
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
316
java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
Normal file
316
java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
/**
|
||||
* Defines the methods that will be made available via JMX.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface BasicDataSourceMXBean {
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getAbandonedUsageTracking()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getAbandonedUsageTracking()}
|
||||
*/
|
||||
boolean getAbandonedUsageTracking();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getDefaultAutoCommit()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getDefaultAutoCommit()}
|
||||
*/
|
||||
Boolean getDefaultAutoCommit();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getDefaultReadOnly()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getDefaultReadOnly()}
|
||||
*/
|
||||
Boolean getDefaultReadOnly();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getDefaultTransactionIsolation()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getDefaultTransactionIsolation()}
|
||||
*/
|
||||
int getDefaultTransactionIsolation();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getDefaultCatalog()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getDefaultCatalog()}
|
||||
*/
|
||||
String getDefaultCatalog();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getDefaultSchema()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getDefaultSchema()}
|
||||
* @since 2.5.0
|
||||
*/
|
||||
String getDefaultSchema();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getCacheState()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getCacheState()}
|
||||
*/
|
||||
boolean getCacheState();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getDriverClassName()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getDriverClassName()}
|
||||
*/
|
||||
String getDriverClassName();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getLifo()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getLifo()}
|
||||
*/
|
||||
boolean getLifo();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getMaxTotal()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getMaxTotal()}
|
||||
*/
|
||||
int getMaxTotal();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getMaxIdle()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getMaxIdle()}
|
||||
*/
|
||||
int getMaxIdle();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getMinIdle()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getMinIdle()}
|
||||
*/
|
||||
int getMinIdle();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getInitialSize()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getInitialSize()}
|
||||
*/
|
||||
int getInitialSize();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getMaxWaitMillis()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getMaxWaitMillis()}
|
||||
*/
|
||||
long getMaxWaitMillis();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#isPoolPreparedStatements()}
|
||||
*
|
||||
* @return {@link BasicDataSource#isPoolPreparedStatements()}
|
||||
*/
|
||||
boolean isPoolPreparedStatements();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getMaxOpenPreparedStatements()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getMaxOpenPreparedStatements()}
|
||||
*/
|
||||
int getMaxOpenPreparedStatements();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getTestOnCreate()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getTestOnCreate()}
|
||||
*/
|
||||
boolean getTestOnCreate();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getTestOnBorrow()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getTestOnBorrow()}
|
||||
*/
|
||||
boolean getTestOnBorrow();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}
|
||||
*/
|
||||
long getTimeBetweenEvictionRunsMillis();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getNumTestsPerEvictionRun()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getNumTestsPerEvictionRun()}
|
||||
*/
|
||||
int getNumTestsPerEvictionRun();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getMinEvictableIdleTimeMillis()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getMinEvictableIdleTimeMillis()}
|
||||
*/
|
||||
long getMinEvictableIdleTimeMillis();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}
|
||||
*/
|
||||
long getSoftMinEvictableIdleTimeMillis();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getTestWhileIdle()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getTestWhileIdle()}
|
||||
*/
|
||||
boolean getTestWhileIdle();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getNumActive()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getNumActive()}
|
||||
*/
|
||||
int getNumActive();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getNumIdle()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getNumIdle()}
|
||||
*/
|
||||
int getNumIdle();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getPassword()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getPassword()}
|
||||
*/
|
||||
String getPassword();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getUrl()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getUrl()}
|
||||
*/
|
||||
String getUrl();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getUsername()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getUsername()}
|
||||
*/
|
||||
String getUsername();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getValidationQuery()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getValidationQuery()}
|
||||
*/
|
||||
String getValidationQuery();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getValidationQueryTimeout()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getValidationQueryTimeout()}
|
||||
*/
|
||||
int getValidationQueryTimeout();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getConnectionInitSqlsAsArray()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getConnectionInitSqlsAsArray()}
|
||||
*/
|
||||
String[] getConnectionInitSqlsAsArray();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}
|
||||
*
|
||||
* @return {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}
|
||||
*/
|
||||
boolean isAccessToUnderlyingConnectionAllowed();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getMaxConnLifetimeMillis()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getMaxConnLifetimeMillis()}
|
||||
*/
|
||||
long getMaxConnLifetimeMillis();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getLogExpiredConnections()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getLogExpiredConnections()}
|
||||
* @since 2.1
|
||||
*/
|
||||
boolean getLogExpiredConnections();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getRemoveAbandonedOnBorrow()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getRemoveAbandonedOnBorrow()}
|
||||
*/
|
||||
boolean getRemoveAbandonedOnBorrow();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}
|
||||
*/
|
||||
boolean getRemoveAbandonedOnMaintenance();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getRemoveAbandonedTimeout()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getRemoveAbandonedTimeout()}
|
||||
*/
|
||||
int getRemoveAbandonedTimeout();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getLogAbandoned()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getLogAbandoned()}
|
||||
*/
|
||||
boolean getLogAbandoned();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#isClosed()}
|
||||
*
|
||||
* @return {@link BasicDataSource#isClosed()}
|
||||
*/
|
||||
boolean isClosed();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getFastFailValidation()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getFastFailValidation()}
|
||||
* @since 2.1
|
||||
*/
|
||||
boolean getFastFailValidation();
|
||||
|
||||
/**
|
||||
* See {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}
|
||||
*
|
||||
* @return {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}
|
||||
* @since 2.1
|
||||
*/
|
||||
String[] getDisconnectionSqlCodesAsArray();
|
||||
}
|
||||
36
java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactory.java
Normal file
36
java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactory.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Abstract factory interface for creating {@link java.sql.Connection}s.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ConnectionFactory {
|
||||
/**
|
||||
* Create a new {@link java.sql.Connection} in an implementation specific fashion.
|
||||
*
|
||||
* @return a new {@link java.sql.Connection}
|
||||
* @throws SQLException
|
||||
* if a database error occurs creating the connection
|
||||
*/
|
||||
Connection createConnection() throws SQLException;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Driver;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
/*
|
||||
* Creates {@link ConnectionFactory} instances.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
class ConnectionFactoryFactory {
|
||||
|
||||
/**
|
||||
* Creates a new {@link DriverConnectionFactory} allowing for an override through
|
||||
* {@link BasicDataSource#getDriverClassName()}.
|
||||
*
|
||||
* @param basicDataSource Configures creation.
|
||||
* @param driver The JDBC driver.
|
||||
* @return a new {@link DriverConnectionFactory} allowing for a {@link BasicDataSource#getDriverClassName()}
|
||||
* override.
|
||||
* @throws SQLException Thrown when instantiation fails.
|
||||
*/
|
||||
static ConnectionFactory createConnectionFactory(final BasicDataSource basicDataSource, final Driver driver)
|
||||
throws SQLException {
|
||||
final Properties connectionProperties = basicDataSource.getConnectionProperties();
|
||||
final String url = basicDataSource.getUrl();
|
||||
// Set up the driver connection factory we will use
|
||||
final String user = basicDataSource.getUsername();
|
||||
if (user != null) {
|
||||
connectionProperties.put("user", user);
|
||||
} else {
|
||||
basicDataSource.log("DBCP DataSource configured without a 'username'");
|
||||
}
|
||||
|
||||
final String pwd = basicDataSource.getPassword();
|
||||
if (pwd != null) {
|
||||
connectionProperties.put("password", pwd);
|
||||
} else {
|
||||
basicDataSource.log("DBCP DataSource configured without a 'password'");
|
||||
}
|
||||
final String connectionFactoryClassName = basicDataSource.getConnectionFactoryClassName();
|
||||
if (connectionFactoryClassName != null) {
|
||||
try {
|
||||
final Class<?> connectionFactoryFromCCL = Class.forName(connectionFactoryClassName);
|
||||
return (ConnectionFactory) connectionFactoryFromCCL
|
||||
.getConstructor(Driver.class, String.class, Properties.class)
|
||||
.newInstance(driver, url, connectionProperties);
|
||||
} catch (final Exception t) {
|
||||
final String message = "Cannot load ConnectionFactory implementation '" + connectionFactoryClassName
|
||||
+ "'";
|
||||
basicDataSource.log(message, t);
|
||||
throw new SQLException(message, t);
|
||||
}
|
||||
}
|
||||
// Defaults to DriverConnectionFactory
|
||||
return new DriverConnectionFactory(driver, url, connectionProperties);
|
||||
}
|
||||
|
||||
}
|
||||
34
java/org/apache/tomcat/dbcp/dbcp2/Constants.java
Normal file
34
java/org/apache/tomcat/dbcp/dbcp2/Constants.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
/**
|
||||
* Constants for use with JMX.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
public static final String JMX_CONNECTION_POOL_BASE_EXT = ",connectionpool=";
|
||||
public static final String JMX_CONNECTION_POOL_PREFIX = "connections";
|
||||
|
||||
public static final String JMX_CONNECTION_BASE_EXT = JMX_CONNECTION_POOL_BASE_EXT + JMX_CONNECTION_POOL_PREFIX
|
||||
+ ",connection=";
|
||||
|
||||
public static final String JMX_STATEMENT_POOL_BASE_EXT = JMX_CONNECTION_BASE_EXT;
|
||||
public static final String JMX_STATEMENT_POOL_PREFIX = ",statementpool=statements";
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* A {@link DataSource}-based implementation of {@link ConnectionFactory}.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DataSourceConnectionFactory implements ConnectionFactory {
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
private final String userName;
|
||||
|
||||
private final char[] userPassword;
|
||||
|
||||
/**
|
||||
* Constructs an instance for the given DataSource.
|
||||
*
|
||||
* @param dataSource
|
||||
* The DataSource for this factory.
|
||||
*/
|
||||
public DataSourceConnectionFactory(final DataSource dataSource) {
|
||||
this(dataSource, null, (char[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance for the given DataSource.
|
||||
*
|
||||
* @param dataSource
|
||||
* The DataSource for this factory.
|
||||
* @param userName
|
||||
* The user name.
|
||||
* @param userPassword
|
||||
* The user password.
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public DataSourceConnectionFactory(final DataSource dataSource, final String userName, final char[] userPassword) {
|
||||
this.dataSource = dataSource;
|
||||
this.userName = userName;
|
||||
this.userPassword = Utils.clone(userPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance for the given DataSource.
|
||||
*
|
||||
* @param dataSource
|
||||
* The DataSource for this factory.
|
||||
* @param userName
|
||||
* The user name.
|
||||
* @param password
|
||||
* The user password.
|
||||
*/
|
||||
public DataSourceConnectionFactory(final DataSource dataSource, final String userName, final String password) {
|
||||
this.dataSource = dataSource;
|
||||
this.userName = userName;
|
||||
this.userPassword = Utils.toCharArray(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection createConnection() throws SQLException {
|
||||
if (null == userName && null == userPassword) {
|
||||
return dataSource.getConnection();
|
||||
}
|
||||
return dataSource.getConnection(userName, Utils.toString(userPassword));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The data source.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public DataSource getDataSource() {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The user name.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The user password.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public char[] getUserPassword() {
|
||||
return userPassword;
|
||||
}
|
||||
}
|
||||
1271
java/org/apache/tomcat/dbcp/dbcp2/DelegatingCallableStatement.java
Normal file
1271
java/org/apache/tomcat/dbcp/dbcp2/DelegatingCallableStatement.java
Normal file
File diff suppressed because it is too large
Load Diff
1001
java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
Normal file
1001
java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
Normal file
File diff suppressed because it is too large
Load Diff
1917
java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
Normal file
1917
java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Date;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.RowId;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* A base delegating implementation of {@link PreparedStatement}.
|
||||
* <p>
|
||||
* All of the methods from the {@link PreparedStatement} interface simply check to see that the
|
||||
* {@link PreparedStatement} is active, and call the corresponding method on the "delegate" provided in my constructor.
|
||||
* <p>
|
||||
* Extends AbandonedTrace to implement Statement tracking and logging of code which created the Statement. Tracking the
|
||||
* Statement ensures that the Connection which created it can close any open Statement's on Connection close.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DelegatingPreparedStatement extends DelegatingStatement implements PreparedStatement {
|
||||
|
||||
/**
|
||||
* Create a wrapper for the Statement which traces this Statement to the Connection which created it and the code
|
||||
* which created it.
|
||||
*
|
||||
* @param statement
|
||||
* the {@link PreparedStatement} to delegate all calls to.
|
||||
* @param connection
|
||||
* the {@link DelegatingConnection} that created this statement.
|
||||
*/
|
||||
public DelegatingPreparedStatement(final DelegatingConnection<?> connection, final PreparedStatement statement) {
|
||||
super(connection, statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().addBatch();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearParameters() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().clearParameters();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute() throws SQLException {
|
||||
checkOpen();
|
||||
if (getConnectionInternal() != null) {
|
||||
getConnectionInternal().setLastUsed();
|
||||
}
|
||||
try {
|
||||
return getDelegatePreparedStatement().execute();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet executeQuery() throws SQLException {
|
||||
checkOpen();
|
||||
if (getConnectionInternal() != null) {
|
||||
getConnectionInternal().setLastUsed();
|
||||
}
|
||||
try {
|
||||
return DelegatingResultSet.wrapResultSet(this, getDelegatePreparedStatement().executeQuery());
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate() throws SQLException {
|
||||
checkOpen();
|
||||
if (getConnectionInternal() != null) {
|
||||
getConnectionInternal().setLastUsed();
|
||||
}
|
||||
try {
|
||||
return getDelegatePreparedStatement().executeUpdate();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private PreparedStatement getDelegatePreparedStatement() {
|
||||
return (PreparedStatement) getDelegate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSetMetaData getMetaData() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return getDelegatePreparedStatement().getMetaData();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.sql.ParameterMetaData getParameterMetaData() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return getDelegatePreparedStatement().getParameterMetaData();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArray(final int i, final Array x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setArray(i, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(final int parameterIndex, final InputStream inputStream) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setAsciiStream(parameterIndex, x, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(final int parameterIndex, final InputStream inputStream, final long length)
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBigDecimal(final int parameterIndex, final BigDecimal x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setBigDecimal(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(final int parameterIndex, final InputStream inputStream) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setBinaryStream(parameterIndex, x, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(final int parameterIndex, final InputStream inputStream, final long length)
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(final int i, final Blob x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setBlob(i, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(final int parameterIndex, final InputStream inputStream) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setBlob(parameterIndex, inputStream);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(final int parameterIndex, final InputStream inputStream, final long length)
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setBlob(parameterIndex, inputStream, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoolean(final int parameterIndex, final boolean x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setBoolean(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setByte(final int parameterIndex, final byte x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setByte(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBytes(final int parameterIndex, final byte[] x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setBytes(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(final int parameterIndex, final Reader reader) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(final int parameterIndex, final Reader reader, final int length)
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(final int parameterIndex, final Reader reader, final long length)
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(final int i, final Clob x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setClob(i, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(final int parameterIndex, final Reader reader) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setClob(parameterIndex, reader);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setClob(parameterIndex, reader, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(final int parameterIndex, final Date x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setDate(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(final int parameterIndex, final Date x, final Calendar cal) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setDate(parameterIndex, x, cal);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDouble(final int parameterIndex, final double x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setDouble(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloat(final int parameterIndex, final float x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setFloat(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInt(final int parameterIndex, final int x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setInt(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLong(final int parameterIndex, final long x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setLong(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNCharacterStream(final int parameterIndex, final Reader reader) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setNCharacterStream(parameterIndex, reader);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNCharacterStream(final int parameterIndex, final Reader value, final long length)
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setNCharacterStream(parameterIndex, value, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(final int parameterIndex, final NClob value) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setNClob(parameterIndex, value);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(final int parameterIndex, final Reader reader) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setNClob(parameterIndex, reader);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setNClob(parameterIndex, reader, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNString(final int parameterIndex, final String value) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setNString(parameterIndex, value);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNull(final int parameterIndex, final int sqlType) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setNull(parameterIndex, sqlType);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNull(final int paramIndex, final int sqlType, final String typeName) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setNull(paramIndex, sqlType, typeName);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(final int parameterIndex, final Object x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setObject(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scale)
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType, scale);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRef(final int i, final Ref x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setRef(i, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRowId(final int parameterIndex, final RowId value) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setRowId(parameterIndex, value);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShort(final int parameterIndex, final short x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setShort(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSQLXML(final int parameterIndex, final SQLXML value) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setSQLXML(parameterIndex, value);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setString(final int parameterIndex, final String x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setString(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(final int parameterIndex, final Time x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setTime(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(final int parameterIndex, final Time x, final Calendar cal) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setTime(parameterIndex, x, cal);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(final int parameterIndex, final Timestamp x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setTimestamp(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(final int parameterIndex, final Timestamp x, final Calendar cal) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setTimestamp(parameterIndex, x, cal);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated Use setAsciiStream(), setCharacterStream() or setNCharacterStream() */
|
||||
@Deprecated
|
||||
@Override
|
||||
public void setUnicodeStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setUnicodeStream(parameterIndex, x, length);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setURL(final int parameterIndex, final java.net.URL x) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
getDelegatePreparedStatement().setURL(parameterIndex, x);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String representation of this object.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
final Statement statement = getDelegate();
|
||||
return statement == null ? "NULL" : statement.toString();
|
||||
}
|
||||
}
|
||||
2026
java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
Normal file
2026
java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
Normal file
File diff suppressed because it is too large
Load Diff
710
java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
Normal file
710
java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
Normal file
@@ -0,0 +1,710 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A base delegating implementation of {@link Statement}.
|
||||
* <p>
|
||||
* All of the methods from the {@link Statement} interface simply check to see that the {@link Statement} is active, and
|
||||
* call the corresponding method on the "delegate" provided in my constructor.
|
||||
* <p>
|
||||
* Extends AbandonedTrace to implement Statement tracking and logging of code which created the Statement. Tracking the
|
||||
* Statement ensures that the Connection which created it can close any open Statement's on Connection close.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DelegatingStatement extends AbandonedTrace implements Statement {
|
||||
|
||||
/** My delegate. */
|
||||
private Statement statement;
|
||||
|
||||
/** The connection that created me. **/
|
||||
private DelegatingConnection<?> connection;
|
||||
|
||||
private boolean closed = false;
|
||||
|
||||
/**
|
||||
* Create a wrapper for the Statement which traces this Statement to the Connection which created it and the code
|
||||
* which created it.
|
||||
*
|
||||
* @param statement
|
||||
* the {@link Statement} to delegate all calls to.
|
||||
* @param connection
|
||||
* the {@link DelegatingConnection} that created this statement.
|
||||
*/
|
||||
public DelegatingStatement(final DelegatingConnection<?> connection, final Statement statement) {
|
||||
super(connection);
|
||||
this.statement = statement;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws SQLException
|
||||
* thrown by the delegating statement.
|
||||
* @since 2.4.0 made public, was protected in 2.3.0.
|
||||
*/
|
||||
public void activate() throws SQLException {
|
||||
if (statement instanceof DelegatingStatement) {
|
||||
((DelegatingStatement) statement).activate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch(final String sql) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.addBatch(sql);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.cancel();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkOpen() throws SQLException {
|
||||
if (isClosed()) {
|
||||
throw new SQLException(this.getClass().getName() + " with address: \"" + this.toString() + "\" is closed.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBatch() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.clearBatch();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.clearWarnings();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close this DelegatingStatement, and close any ResultSets that were not explicitly closed.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
if (isClosed()) {
|
||||
return;
|
||||
}
|
||||
final List<Exception> thrownList = new ArrayList<>();
|
||||
try {
|
||||
if (connection != null) {
|
||||
connection.removeTrace(this);
|
||||
connection = null;
|
||||
}
|
||||
|
||||
// The JDBC spec requires that a statement close any open
|
||||
// ResultSet's when it is closed.
|
||||
// FIXME The PreparedStatement we're wrapping should handle this for us.
|
||||
// See bug 17301 for what could happen when ResultSets are closed twice.
|
||||
final List<AbandonedTrace> resultSetList = getTrace();
|
||||
if (resultSetList != null) {
|
||||
final int size = resultSetList.size();
|
||||
final ResultSet[] resultSets = resultSetList.toArray(new ResultSet[size]);
|
||||
for (final ResultSet resultSet : resultSets) {
|
||||
if (resultSet != null) {
|
||||
try {
|
||||
resultSet.close();
|
||||
} catch (Exception e) {
|
||||
if (connection != null) {
|
||||
// Does not rethrow e.
|
||||
connection.handleExceptionNoThrow(e);
|
||||
}
|
||||
thrownList.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
clearTrace();
|
||||
}
|
||||
if (statement != null) {
|
||||
try {
|
||||
statement.close();
|
||||
} catch (Exception e) {
|
||||
if (connection != null) {
|
||||
// Does not rethrow e.
|
||||
connection.handleExceptionNoThrow(e);
|
||||
}
|
||||
thrownList.add(e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
closed = true;
|
||||
statement = null;
|
||||
if (!thrownList.isEmpty()) {
|
||||
throw new SQLExceptionList(thrownList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOnCompletion() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
Jdbc41Bridge.closeOnCompletion(statement);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final String sql) throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return statement.execute(sql);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return statement.execute(sql, autoGeneratedKeys);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final String sql, final int columnIndexes[]) throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return statement.execute(sql, columnIndexes);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final String sql, final String columnNames[]) throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return statement.execute(sql, columnNames);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] executeBatch() throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return statement.executeBatch();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet executeQuery(final String sql) throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return DelegatingResultSet.wrapResultSet(this, statement.executeQuery(sql));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(final String sql) throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return statement.executeUpdate(sql);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return statement.executeUpdate(sql, autoGeneratedKeys);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(final String sql, final int columnIndexes[]) throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return statement.executeUpdate(sql, columnIndexes);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(final String sql, final String columnNames[]) throws SQLException {
|
||||
checkOpen();
|
||||
setLastUsedInParent();
|
||||
try {
|
||||
return statement.executeUpdate(sql, columnNames);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
// This is required because of statement pooling. The poolable
|
||||
// statements will always be strongly held by the statement pool. If the
|
||||
// delegating statements that wrap the poolable statement are not
|
||||
// strongly held they will be garbage collected but at that point the
|
||||
// poolable statements need to be returned to the pool else there will
|
||||
// be a leak of statements from the pool. Closing this statement will
|
||||
// close all the wrapped statements and return any poolable statements
|
||||
// to the pool.
|
||||
close();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
checkOpen();
|
||||
return getConnectionInternal(); // return the delegating connection that created this
|
||||
}
|
||||
|
||||
protected DelegatingConnection<?> getConnectionInternal() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns my underlying {@link Statement}.
|
||||
*
|
||||
* @return my underlying {@link Statement}.
|
||||
* @see #getInnermostDelegate
|
||||
*/
|
||||
public Statement getDelegate() {
|
||||
return statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchDirection() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getFetchDirection();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchSize() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getFetchSize();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getGeneratedKeys() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return DelegatingResultSet.wrapResultSet(this, statement.getGeneratedKeys());
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If my underlying {@link Statement} is not a {@code DelegatingStatement}, returns it, otherwise recursively
|
||||
* invokes this method on my delegate.
|
||||
* <p>
|
||||
* Hence this method will return the first delegate that is not a {@code DelegatingStatement} or {@code null} when
|
||||
* no non-{@code DelegatingStatement} delegate can be found by traversing this chain.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method is useful when you may have nested {@code DelegatingStatement}s, and you want to make sure to obtain
|
||||
* a "genuine" {@link Statement}.
|
||||
* </p>
|
||||
*
|
||||
* @return The innermost delegate.
|
||||
*
|
||||
* @see #getDelegate
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public Statement getInnermostDelegate() {
|
||||
Statement s = statement;
|
||||
while (s != null && s instanceof DelegatingStatement) {
|
||||
s = ((DelegatingStatement) s).getDelegate();
|
||||
if (this == s) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxFieldSize() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getMaxFieldSize();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxRows() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getMaxRows();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getMoreResults();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults(final int current) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getMoreResults(current);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQueryTimeout() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getQueryTimeout();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getResultSet() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return DelegatingResultSet.wrapResultSet(this, statement.getResultSet());
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetConcurrency() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getResultSetConcurrency();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetHoldability() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getResultSetHoldability();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetType() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getResultSetType();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getUpdateCount();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLWarning getWarnings() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.getWarnings();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleException(final SQLException e) throws SQLException {
|
||||
if (connection != null) {
|
||||
connection.handleException(e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: This method was protected prior to JDBC 4.
|
||||
*/
|
||||
@Override
|
||||
public boolean isClosed() throws SQLException {
|
||||
return closed;
|
||||
}
|
||||
|
||||
protected boolean isClosedInternal() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCloseOnCompletion() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return Jdbc41Bridge.isCloseOnCompletion(statement);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPoolable() throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return statement.isPoolable();
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(final Class<?> iface) throws SQLException {
|
||||
if (iface.isAssignableFrom(getClass())) {
|
||||
return true;
|
||||
} else if (iface.isAssignableFrom(statement.getClass())) {
|
||||
return true;
|
||||
} else {
|
||||
return statement.isWrapperFor(iface);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws SQLException
|
||||
* thrown by the delegating statement.
|
||||
* @since 2.4.0 made public, was protected in 2.3.0.
|
||||
*/
|
||||
public void passivate() throws SQLException {
|
||||
if (statement instanceof DelegatingStatement) {
|
||||
((DelegatingStatement) statement).passivate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setClosedInternal(final boolean closed) {
|
||||
this.closed = closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorName(final String name) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.setCursorName(name);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets my delegate.
|
||||
*
|
||||
* @param statement
|
||||
* my delegate.
|
||||
*/
|
||||
public void setDelegate(final Statement statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEscapeProcessing(final boolean enable) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.setEscapeProcessing(enable);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchDirection(final int direction) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.setFetchDirection(direction);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchSize(final int rows) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.setFetchSize(rows);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setLastUsedInParent() {
|
||||
if (connection != null) {
|
||||
connection.setLastUsed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFieldSize(final int max) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.setMaxFieldSize(max);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRows(final int max) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.setMaxRows(max);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPoolable(final boolean poolable) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.setPoolable(poolable);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQueryTimeout(final int seconds) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
statement.setQueryTimeout(seconds);
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String representation of this object.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
return statement == null ? "NULL" : statement.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(final Class<T> iface) throws SQLException {
|
||||
if (iface.isAssignableFrom(getClass())) {
|
||||
return iface.cast(this);
|
||||
} else if (iface.isAssignableFrom(statement.getClass())) {
|
||||
return iface.cast(statement);
|
||||
} else {
|
||||
return statement.unwrap(iface);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A {@link Driver}-based implementation of {@link ConnectionFactory}.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DriverConnectionFactory implements ConnectionFactory {
|
||||
|
||||
private final String connectionString;
|
||||
|
||||
private final Driver driver;
|
||||
|
||||
private final Properties properties;
|
||||
|
||||
/**
|
||||
* Constructs a connection factory for a given Driver.
|
||||
*
|
||||
* @param driver
|
||||
* The Driver.
|
||||
* @param connectString
|
||||
* The connection string.
|
||||
* @param properties
|
||||
* The connection properties.
|
||||
*/
|
||||
public DriverConnectionFactory(final Driver driver, final String connectString, final Properties properties) {
|
||||
this.driver = driver;
|
||||
this.connectionString = connectString;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection createConnection() throws SQLException {
|
||||
return driver.connect(connectionString, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The connection String.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public String getConnectionString() {
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Driver.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Driver getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Properties.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getName() + " [" + String.valueOf(driver) + ";" + String.valueOf(connectionString) + ";"
|
||||
+ String.valueOf(properties) + "]";
|
||||
}
|
||||
}
|
||||
81
java/org/apache/tomcat/dbcp/dbcp2/DriverFactory.java
Normal file
81
java/org/apache/tomcat/dbcp/dbcp2/DriverFactory.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/*
|
||||
* Creates {@link Driver} instances.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
class DriverFactory {
|
||||
|
||||
static Driver createDriver(final BasicDataSource basicDataSource) throws SQLException {
|
||||
// Load the JDBC driver class
|
||||
Driver driverToUse = basicDataSource.getDriver();
|
||||
String driverClassName = basicDataSource.getDriverClassName();
|
||||
ClassLoader driverClassLoader = basicDataSource.getDriverClassLoader();
|
||||
String url = basicDataSource.getUrl();
|
||||
|
||||
if (driverToUse == null) {
|
||||
Class<?> driverFromCCL = null;
|
||||
if (driverClassName != null) {
|
||||
try {
|
||||
try {
|
||||
if (driverClassLoader == null) {
|
||||
driverFromCCL = Class.forName(driverClassName);
|
||||
} else {
|
||||
driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
|
||||
}
|
||||
} catch (final ClassNotFoundException cnfe) {
|
||||
driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
|
||||
}
|
||||
} catch (final Exception t) {
|
||||
final String message = "Cannot load JDBC driver class '" + driverClassName + "'";
|
||||
basicDataSource.log(message, t);
|
||||
throw new SQLException(message, t);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (driverFromCCL == null) {
|
||||
driverToUse = DriverManager.getDriver(url);
|
||||
} else {
|
||||
// Usage of DriverManager is not possible, as it does not
|
||||
// respect the ContextClassLoader
|
||||
// N.B. This cast may cause ClassCastException which is
|
||||
// handled below
|
||||
driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();
|
||||
if (!driverToUse.acceptsURL(url)) {
|
||||
throw new SQLException("No suitable driver", "08001");
|
||||
}
|
||||
}
|
||||
} catch (final Exception t) {
|
||||
final String message = "Cannot create JDBC driver of class '"
|
||||
+ (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
|
||||
basicDataSource.log(message, t);
|
||||
throw new SQLException(message, t);
|
||||
}
|
||||
}
|
||||
return driverToUse;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A {@link DriverManager}-based implementation of {@link ConnectionFactory}.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DriverManagerConnectionFactory implements ConnectionFactory {
|
||||
|
||||
static {
|
||||
// Related to DBCP-212
|
||||
// Driver manager does not sync loading of drivers that use the service
|
||||
// provider interface. This will cause issues is multi-threaded
|
||||
// environments. This hack makes sure the drivers are loaded before
|
||||
// DBCP tries to use them.
|
||||
DriverManager.getDrivers();
|
||||
}
|
||||
|
||||
private final String connectionUri;
|
||||
|
||||
private final String userName;
|
||||
|
||||
private final char[] userPassword;
|
||||
|
||||
private final Properties properties;
|
||||
|
||||
/**
|
||||
* Constructor for DriverManagerConnectionFactory.
|
||||
*
|
||||
* @param connectionUri
|
||||
* a database url of the form <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
|
||||
* @since 2.2
|
||||
*/
|
||||
public DriverManagerConnectionFactory(final String connectionUri) {
|
||||
this.connectionUri = connectionUri;
|
||||
this.properties = new Properties();
|
||||
this.userName = null;
|
||||
this.userPassword = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for DriverManagerConnectionFactory.
|
||||
*
|
||||
* @param connectionUri
|
||||
* a database url of the form <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
|
||||
* @param properties
|
||||
* a list of arbitrary string tag/value pairs as connection arguments; normally at least a "user" and
|
||||
* "password" property should be included.
|
||||
*/
|
||||
public DriverManagerConnectionFactory(final String connectionUri, final Properties properties) {
|
||||
this.connectionUri = connectionUri;
|
||||
this.properties = properties;
|
||||
this.userName = null;
|
||||
this.userPassword = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for DriverManagerConnectionFactory.
|
||||
*
|
||||
* @param connectionUri
|
||||
* a database url of the form <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
|
||||
* @param userName
|
||||
* the database user
|
||||
* @param userPassword
|
||||
* the user's password
|
||||
*/
|
||||
public DriverManagerConnectionFactory(final String connectionUri, final String userName,
|
||||
final char[] userPassword) {
|
||||
this.connectionUri = connectionUri;
|
||||
this.userName = userName;
|
||||
this.userPassword = Utils.clone(userPassword);
|
||||
this.properties = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for DriverManagerConnectionFactory.
|
||||
*
|
||||
* @param connectionUri
|
||||
* a database url of the form <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
|
||||
* @param userName
|
||||
* the database user
|
||||
* @param userPassword
|
||||
* the user's password
|
||||
*/
|
||||
public DriverManagerConnectionFactory(final String connectionUri, final String userName,
|
||||
final String userPassword) {
|
||||
this.connectionUri = connectionUri;
|
||||
this.userName = userName;
|
||||
this.userPassword = Utils.toCharArray(userPassword);
|
||||
this.properties = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection createConnection() throws SQLException {
|
||||
if (null == properties) {
|
||||
if (userName == null && userPassword == null) {
|
||||
return DriverManager.getConnection(connectionUri);
|
||||
}
|
||||
return DriverManager.getConnection(connectionUri, userName, Utils.toString(userPassword));
|
||||
}
|
||||
return DriverManager.getConnection(connectionUri, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The connection URI.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public String getConnectionUri() {
|
||||
return connectionUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Properties.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The user name.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
}
|
||||
482
java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
Normal file
482
java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.Date;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.RowId;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.sql.CommonDataSource;
|
||||
|
||||
/**
|
||||
* Defines bridge methods to JDBC 4.1 (Java 7) methods to allow call sites to operate safely (without
|
||||
* {@link AbstractMethodError}) when using a JDBC driver written for JDBC 4.0 (Java 6).
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public class Jdbc41Bridge {
|
||||
|
||||
/**
|
||||
* Delegates to {@link Connection#abort(Executor)} without throwing a {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link Connection#abort(Executor)}, then call {@link Connection#close()}.
|
||||
* </p>
|
||||
*
|
||||
* @param connection
|
||||
* the receiver
|
||||
* @param executor
|
||||
* See {@link Connection#abort(Executor)}.
|
||||
* @throws SQLException
|
||||
* See {@link Connection#abort(Executor)}.
|
||||
* @see Connection#abort(Executor)
|
||||
*/
|
||||
public static void abort(final Connection connection, final Executor executor) throws SQLException {
|
||||
try {
|
||||
connection.abort(executor);
|
||||
} catch (final AbstractMethodError e) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link DatabaseMetaData#generatedKeyAlwaysReturned()} without throwing a
|
||||
* {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link DatabaseMetaData#generatedKeyAlwaysReturned()}, then return false.
|
||||
* </p>
|
||||
*
|
||||
* @param databaseMetaData
|
||||
* See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
|
||||
* @return See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
|
||||
* @throws SQLException
|
||||
* See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
|
||||
* @see DatabaseMetaData#generatedKeyAlwaysReturned()
|
||||
*/
|
||||
public static boolean generatedKeyAlwaysReturned(final DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
try {
|
||||
return databaseMetaData.generatedKeyAlwaysReturned();
|
||||
} catch (final AbstractMethodError e) {
|
||||
// do nothing
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Connection#getNetworkTimeout()} without throwing a {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link Connection#getNetworkTimeout()}, then return 0.
|
||||
* </p>
|
||||
*
|
||||
* @param connection
|
||||
* the receiver
|
||||
* @return See {@link Connection#getNetworkTimeout()}
|
||||
* @throws SQLException
|
||||
* See {@link Connection#getNetworkTimeout()}
|
||||
* @see Connection#getNetworkTimeout()
|
||||
*/
|
||||
public static int getNetworkTimeout(final Connection connection) throws SQLException {
|
||||
try {
|
||||
return connection.getNetworkTimeout();
|
||||
} catch (final AbstractMethodError e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link ResultSet#getObject(int, Class)} without throwing a {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link ResultSet#getObject(int, Class)}, then return 0.
|
||||
* </p>
|
||||
*
|
||||
* @param <T>
|
||||
* See {@link ResultSet#getObject(int, Class)}
|
||||
* @param resultSet
|
||||
* See {@link ResultSet#getObject(int, Class)}
|
||||
* @param columnIndex
|
||||
* See {@link ResultSet#getObject(int, Class)}
|
||||
* @param type
|
||||
* See {@link ResultSet#getObject(int, Class)}
|
||||
* @return See {@link ResultSet#getObject(int, Class)}
|
||||
* @throws SQLException
|
||||
* See {@link ResultSet#getObject(int, Class)}
|
||||
* @see ResultSet#getObject(int, Class)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getObject(final ResultSet resultSet, final int columnIndex, final Class<T> type)
|
||||
throws SQLException {
|
||||
try {
|
||||
return resultSet.getObject(columnIndex, type);
|
||||
} catch (final AbstractMethodError e) {
|
||||
if (type == String.class) {
|
||||
return (T) resultSet.getString(columnIndex);
|
||||
}
|
||||
// Numbers
|
||||
if (type == Integer.class) {
|
||||
return (T) Integer.valueOf(resultSet.getInt(columnIndex));
|
||||
}
|
||||
if (type == Long.class) {
|
||||
return (T) Long.valueOf(resultSet.getLong(columnIndex));
|
||||
}
|
||||
if (type == Double.class) {
|
||||
return (T) Double.valueOf(resultSet.getDouble(columnIndex));
|
||||
}
|
||||
if (type == Float.class) {
|
||||
return (T) Float.valueOf(resultSet.getFloat(columnIndex));
|
||||
}
|
||||
if (type == Short.class) {
|
||||
return (T) Short.valueOf(resultSet.getShort(columnIndex));
|
||||
}
|
||||
if (type == BigDecimal.class) {
|
||||
return (T) resultSet.getBigDecimal(columnIndex);
|
||||
}
|
||||
if (type == Byte.class) {
|
||||
return (T) Byte.valueOf(resultSet.getByte(columnIndex));
|
||||
}
|
||||
// Dates
|
||||
if (type == Date.class) {
|
||||
return (T) resultSet.getDate(columnIndex);
|
||||
}
|
||||
if (type == Time.class) {
|
||||
return (T) resultSet.getTime(columnIndex);
|
||||
}
|
||||
if (type == Timestamp.class) {
|
||||
return (T) resultSet.getTimestamp(columnIndex);
|
||||
}
|
||||
// Streams
|
||||
if (type == InputStream.class) {
|
||||
return (T) resultSet.getBinaryStream(columnIndex);
|
||||
}
|
||||
if (type == Reader.class) {
|
||||
return (T) resultSet.getCharacterStream(columnIndex);
|
||||
}
|
||||
// Other
|
||||
if (type == Object.class) {
|
||||
return (T) resultSet.getObject(columnIndex);
|
||||
}
|
||||
if (type == Boolean.class) {
|
||||
return (T) Boolean.valueOf(resultSet.getBoolean(columnIndex));
|
||||
}
|
||||
if (type == Array.class) {
|
||||
return (T) resultSet.getArray(columnIndex);
|
||||
}
|
||||
if (type == Blob.class) {
|
||||
return (T) resultSet.getBlob(columnIndex);
|
||||
}
|
||||
if (type == Clob.class) {
|
||||
return (T) resultSet.getClob(columnIndex);
|
||||
}
|
||||
if (type == Ref.class) {
|
||||
return (T) resultSet.getRef(columnIndex);
|
||||
}
|
||||
if (type == RowId.class) {
|
||||
return (T) resultSet.getRowId(columnIndex);
|
||||
}
|
||||
if (type == SQLXML.class) {
|
||||
return (T) resultSet.getSQLXML(columnIndex);
|
||||
}
|
||||
if (type == URL.class) {
|
||||
return (T) resultSet.getURL(columnIndex);
|
||||
}
|
||||
throw new SQLFeatureNotSupportedException(
|
||||
String.format("resultSet=%s, columnIndex=%,d, type=%s", resultSet, Integer.valueOf(columnIndex), type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link ResultSet#getObject(String, Class)} without throwing a {@link AbstractMethodError}.
|
||||
*
|
||||
* @param <T>
|
||||
* See {@link ResultSet#getObject(String, Class)}
|
||||
* @param resultSet
|
||||
* See {@link ResultSet#getObject(String, Class)}
|
||||
* @param columnLabel
|
||||
* See {@link ResultSet#getObject(String, Class)}
|
||||
* @param type
|
||||
* See {@link ResultSet#getObject(String, Class)}
|
||||
* @return See {@link ResultSet#getObject(String, Class)}
|
||||
* @throws SQLException
|
||||
* See {@link ResultSet#getObject(String, Class)}
|
||||
* @see ResultSet#getObject(int, Class)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getObject(final ResultSet resultSet, final String columnLabel, final Class<T> type)
|
||||
throws SQLException {
|
||||
try {
|
||||
return resultSet.getObject(columnLabel, type);
|
||||
} catch (final AbstractMethodError e) {
|
||||
// Numbers
|
||||
if (type == Integer.class) {
|
||||
return (T) Integer.valueOf(resultSet.getInt(columnLabel));
|
||||
}
|
||||
if (type == Long.class) {
|
||||
return (T) Long.valueOf(resultSet.getLong(columnLabel));
|
||||
}
|
||||
if (type == Double.class) {
|
||||
return (T) Double.valueOf(resultSet.getDouble(columnLabel));
|
||||
}
|
||||
if (type == Float.class) {
|
||||
return (T) Float.valueOf(resultSet.getFloat(columnLabel));
|
||||
}
|
||||
if (type == Short.class) {
|
||||
return (T) Short.valueOf(resultSet.getShort(columnLabel));
|
||||
}
|
||||
if (type == BigDecimal.class) {
|
||||
return (T) resultSet.getBigDecimal(columnLabel);
|
||||
}
|
||||
if (type == Byte.class) {
|
||||
return (T) Byte.valueOf(resultSet.getByte(columnLabel));
|
||||
}
|
||||
// Dates
|
||||
if (type == Date.class) {
|
||||
return (T) resultSet.getDate(columnLabel);
|
||||
}
|
||||
if (type == Time.class) {
|
||||
return (T) resultSet.getTime(columnLabel);
|
||||
}
|
||||
if (type == Timestamp.class) {
|
||||
return (T) resultSet.getTimestamp(columnLabel);
|
||||
}
|
||||
// Streams
|
||||
if (type == InputStream.class) {
|
||||
return (T) resultSet.getBinaryStream(columnLabel);
|
||||
}
|
||||
if (type == Reader.class) {
|
||||
return (T) resultSet.getCharacterStream(columnLabel);
|
||||
}
|
||||
// Other
|
||||
if (type == Object.class) {
|
||||
return (T) resultSet.getObject(columnLabel);
|
||||
}
|
||||
if (type == Boolean.class) {
|
||||
return (T) Boolean.valueOf(resultSet.getBoolean(columnLabel));
|
||||
}
|
||||
if (type == Array.class) {
|
||||
return (T) resultSet.getArray(columnLabel);
|
||||
}
|
||||
if (type == Blob.class) {
|
||||
return (T) resultSet.getBlob(columnLabel);
|
||||
}
|
||||
if (type == Clob.class) {
|
||||
return (T) resultSet.getClob(columnLabel);
|
||||
}
|
||||
if (type == Ref.class) {
|
||||
return (T) resultSet.getRef(columnLabel);
|
||||
}
|
||||
if (type == RowId.class) {
|
||||
return (T) resultSet.getRowId(columnLabel);
|
||||
}
|
||||
if (type == SQLXML.class) {
|
||||
return (T) resultSet.getSQLXML(columnLabel);
|
||||
}
|
||||
if (type == URL.class) {
|
||||
return (T) resultSet.getURL(columnLabel);
|
||||
}
|
||||
throw new SQLFeatureNotSupportedException(
|
||||
String.format("resultSet=%s, columnLabel=%s, type=%s", resultSet, columnLabel, type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} without throwing a
|
||||
* {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)},
|
||||
* then return null.
|
||||
* </p>
|
||||
*
|
||||
* @param databaseMetaData
|
||||
* the receiver
|
||||
* @param catalog
|
||||
* See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
|
||||
* @param schemaPattern
|
||||
* See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
|
||||
* @param tableNamePattern
|
||||
* See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
|
||||
* @param columnNamePattern
|
||||
* See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
|
||||
* @return See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
|
||||
* @throws SQLException
|
||||
* See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
|
||||
* @see DatabaseMetaData#getPseudoColumns(String, String, String, String)
|
||||
*/
|
||||
public static ResultSet getPseudoColumns(final DatabaseMetaData databaseMetaData, final String catalog,
|
||||
final String schemaPattern, final String tableNamePattern, final String columnNamePattern)
|
||||
throws SQLException {
|
||||
try {
|
||||
return databaseMetaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
|
||||
} catch (final AbstractMethodError e) {
|
||||
// do nothing
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Connection#getSchema()} without throwing a {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link Connection#getSchema()}, then return null.
|
||||
* </p>
|
||||
*
|
||||
* @param connection
|
||||
* the receiver
|
||||
* @return null for a JDBC 4 driver or a value per {@link Connection#getSchema()}.
|
||||
* @throws SQLException
|
||||
* See {@link Connection#getSchema()}.
|
||||
* @see Connection#getSchema()
|
||||
*/
|
||||
public static String getSchema(final Connection connection) throws SQLException {
|
||||
try {
|
||||
return connection.getSchema();
|
||||
} catch (final AbstractMethodError e) {
|
||||
// do nothing
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Connection#setNetworkTimeout(Executor, int)} without throwing a {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link Connection#setNetworkTimeout(Executor, int)}, then do nothing.
|
||||
* </p>
|
||||
*
|
||||
* @param connection
|
||||
* the receiver
|
||||
* @param executor
|
||||
* See {@link Connection#setNetworkTimeout(Executor, int)}
|
||||
* @param milliseconds
|
||||
* {@link Connection#setNetworkTimeout(Executor, int)}
|
||||
* @throws SQLException
|
||||
* {@link Connection#setNetworkTimeout(Executor, int)}
|
||||
* @see Connection#setNetworkTimeout(Executor, int)
|
||||
*/
|
||||
public static void setNetworkTimeout(final Connection connection, final Executor executor, final int milliseconds)
|
||||
throws SQLException {
|
||||
try {
|
||||
connection.setNetworkTimeout(executor, milliseconds);
|
||||
} catch (final AbstractMethodError e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Connection#setSchema(String)} without throwing a {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link Connection#setSchema(String)}, then do nothing.
|
||||
* </p>
|
||||
*
|
||||
* @param connection
|
||||
* the receiver
|
||||
* @param schema
|
||||
* See {@link Connection#setSchema(String)}.
|
||||
* @throws SQLException
|
||||
* See {@link Connection#setSchema(String)}.
|
||||
* @see Connection#setSchema(String)
|
||||
*/
|
||||
public static void setSchema(final Connection connection, final String schema) throws SQLException {
|
||||
try {
|
||||
connection.setSchema(schema);
|
||||
} catch (final AbstractMethodError e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Statement#closeOnCompletion()} without throwing a {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link Statement#closeOnCompletion()}, then just check that the connection
|
||||
* is closed to then throw an SQLException.
|
||||
* </p>
|
||||
*
|
||||
* @param statement
|
||||
* See {@link Statement#closeOnCompletion()}
|
||||
* @throws SQLException
|
||||
* See {@link Statement#closeOnCompletion()}
|
||||
* @see Statement#closeOnCompletion()
|
||||
*/
|
||||
public static void closeOnCompletion(final Statement statement) throws SQLException {
|
||||
try {
|
||||
statement.closeOnCompletion();
|
||||
} catch (final AbstractMethodError e) {
|
||||
if (statement.isClosed()) {
|
||||
throw new SQLException("Statement closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Statement#isCloseOnCompletion()} without throwing a {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link Statement#isCloseOnCompletion()}, then just check that the
|
||||
* connection is closed to then throw an SQLException.
|
||||
* </p>
|
||||
*
|
||||
* @param statement
|
||||
* See {@link Statement#isCloseOnCompletion()}
|
||||
* @return See {@link Statement#isCloseOnCompletion()}
|
||||
* @throws SQLException
|
||||
* See {@link Statement#isCloseOnCompletion()}
|
||||
* @see Statement#closeOnCompletion()
|
||||
*/
|
||||
public static boolean isCloseOnCompletion(final Statement statement) throws SQLException {
|
||||
try {
|
||||
return statement.isCloseOnCompletion();
|
||||
} catch (final AbstractMethodError e) {
|
||||
if (statement.isClosed()) {
|
||||
throw new SQLException("Statement closed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link CommonDataSource#getParentLogger()} without throwing a {@link AbstractMethodError}.
|
||||
* <p>
|
||||
* If the JDBC driver does not implement {@link CommonDataSource#getParentLogger()}, then return null.
|
||||
* </p>
|
||||
*
|
||||
* @param commonDataSource
|
||||
* See {@link CommonDataSource#getParentLogger()}
|
||||
* @return See {@link CommonDataSource#getParentLogger()}
|
||||
* @throws SQLFeatureNotSupportedException
|
||||
* See {@link CommonDataSource#getParentLogger()}
|
||||
*/
|
||||
public static Logger getParentLogger(final CommonDataSource commonDataSource) throws SQLFeatureNotSupportedException {
|
||||
try {
|
||||
return commonDataSource.getParentLogger();
|
||||
} catch (final AbstractMethodError e) {
|
||||
throw new SQLFeatureNotSupportedException("javax.sql.CommonDataSource#getParentLogger()");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
/**
|
||||
* Exception thrown when a connection's maximum lifetime has been exceeded.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
class LifetimeExceededException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -3783783104516492659L;
|
||||
|
||||
/**
|
||||
* Create a LifetimeExceededException.
|
||||
*/
|
||||
public LifetimeExceededException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a LifetimeExceededException with the given message.
|
||||
*
|
||||
* @param message
|
||||
* The message with which to create the exception
|
||||
*/
|
||||
public LifetimeExceededException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
57
java/org/apache/tomcat/dbcp/dbcp2/ListException.java
Normal file
57
java/org/apache/tomcat/dbcp/dbcp2/ListException.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An exception wrapping a list of exceptions.
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public class ListException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<Throwable> exceptionList;
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
|
||||
* be initialized by a call to {@link #initCause}.
|
||||
*
|
||||
* @param message
|
||||
* the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
|
||||
* method.
|
||||
* @param exceptionList
|
||||
* a list of exceptions.
|
||||
*/
|
||||
public ListException(final String message, final List<Throwable> exceptionList) {
|
||||
super(message);
|
||||
this.exceptionList = exceptionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of exceptions.
|
||||
*
|
||||
* @return the list of exceptions.
|
||||
*/
|
||||
public List<Throwable> getExceptionList() {
|
||||
return exceptionList;
|
||||
}
|
||||
|
||||
}
|
||||
26
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings.properties
Normal file
26
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings.properties
Normal file
@@ -0,0 +1,26 @@
|
||||
# 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.
|
||||
|
||||
connectionFactory.lifetimeExceeded=The lifetime of the connection [{0}] milliseconds exceeds the maximum permitted value of [{1}] milliseconds
|
||||
|
||||
pool.close.fail=Cannot close connection pool.
|
||||
|
||||
poolableConnection.validate.fastFail=Fatal SQLException was thrown previously on this connection.
|
||||
|
||||
poolableConnectionFactory.validateObject.fail=Failed to validate a poolable connection.
|
||||
|
||||
poolingDataSource.factoryConfig=PoolableConnectionFactory not linked to pool. Calling setPool() to fix the configuration.
|
||||
|
||||
swallowedExceptionLogger.onSwallowedException=An internal object pool swallowed an Exception.
|
||||
16
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings_de.properties
Normal file
16
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings_de.properties
Normal file
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
poolableConnection.validate.fastFail=Fatale SQLException wurde bereits vorher von dieser Verbindung geworfen
|
||||
26
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings_fr.properties
Normal file
26
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings_fr.properties
Normal file
@@ -0,0 +1,26 @@
|
||||
# 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.
|
||||
|
||||
connectionFactory.lifetimeExceeded=La durée de vie de la connection de [{0}] millisecondes excède la valeur maximale permis de [{1}] millisecondes
|
||||
|
||||
pool.close.fail=Impossible de fermer le pool de connections
|
||||
|
||||
poolableConnection.validate.fastFail=Une exception fatale SQLException avait déjà été lancée pour cette connection
|
||||
|
||||
poolableConnectionFactory.validateObject.fail=Impossible de valider la connection poolable
|
||||
|
||||
poolingDataSource.factoryConfig=La PoolableConnectionFactory n'est pas liée au pool, il faut appeler setPool() pour y remédier et corriger la configuration
|
||||
|
||||
swallowedExceptionLogger.onSwallowedException=Un object interne du pool a avalé une exception
|
||||
26
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings_ja.properties
Normal file
26
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings_ja.properties
Normal file
@@ -0,0 +1,26 @@
|
||||
# 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.
|
||||
|
||||
connectionFactory.lifetimeExceeded=コネクション[{0}]ミリ秒の有効期間が[{1}]ミリ秒の許容最大値を超えています
|
||||
|
||||
pool.close.fail=コネクションプールを停止できません。
|
||||
|
||||
poolableConnection.validate.fastFail=このコネクションは過去に致命的な SQLException を送出したことがあります。
|
||||
|
||||
poolableConnectionFactory.validateObject.fail=プール可能なコネクションを検証できません。
|
||||
|
||||
poolingDataSource.factoryConfig=PoolableConnectionFactory がコネクションプールに接続していません。構成を修復するには setPool() を呼び出してください。
|
||||
|
||||
swallowedExceptionLogger.onSwallowedException=内部オブジェクトプールが例外を飲み込みました。
|
||||
26
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings_ko.properties
Normal file
26
java/org/apache/tomcat/dbcp/dbcp2/LocalStrings_ko.properties
Normal file
@@ -0,0 +1,26 @@
|
||||
# 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.
|
||||
|
||||
connectionFactory.lifetimeExceeded=해당 연결의 존속시간 [{0}] 밀리초가, 최대 허용치인 [{1}] 밀리초를 초과합니다.
|
||||
|
||||
pool.close.fail=데이터베이스 연결 풀을 닫을 수 없습니다.
|
||||
|
||||
poolableConnection.validate.fastFail=이 연결에서, 심각한 SQLException이 이전에 발생했습니다.
|
||||
|
||||
poolableConnectionFactory.validateObject.fail=Poolable connection이 유효한지 확인하지 못했습니다.
|
||||
|
||||
poolingDataSource.factoryConfig=PoolableConnectionFactory가 풀에 연결되지 않았습니다. setPool()을 호출하여 이 설정 문제를 해결합니다.
|
||||
|
||||
swallowedExceptionLogger.onSwallowedException=내부 객체 풀이 예외 발생을 무시했습니다.
|
||||
@@ -0,0 +1,20 @@
|
||||
# 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.
|
||||
|
||||
poolableConnection.validate.fastFail=此连接上预先抛出了致命的 SQLException。
|
||||
|
||||
poolingDataSource.factoryConfig=PoolableConnectionFactory 未连接到连接池。请调用 setPool() 修复此配置。
|
||||
|
||||
swallowedExceptionLogger.onSwallowedException=一个内部对象池吞并了一个异常。
|
||||
105
java/org/apache/tomcat/dbcp/dbcp2/ObjectNameWrapper.java
Normal file
105
java/org/apache/tomcat/dbcp/dbcp2/ObjectNameWrapper.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Internal wrapper class that allows JMX to be a noop if absent or disabled.
|
||||
*
|
||||
* @since 2.2.1
|
||||
*/
|
||||
class ObjectNameWrapper {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ObjectNameWrapper.class);
|
||||
|
||||
private static MBeanServer MBEAN_SERVER = getPlatformMBeanServer();
|
||||
|
||||
private static MBeanServer getPlatformMBeanServer() {
|
||||
try {
|
||||
return ManagementFactory.getPlatformMBeanServer();
|
||||
} catch (LinkageError | Exception e) {
|
||||
// ignore - JMX not available
|
||||
log.debug("Failed to get platform MBeanServer", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static ObjectName unwrap(final ObjectNameWrapper wrapper) {
|
||||
return wrapper == null ? null : wrapper.unwrap();
|
||||
}
|
||||
|
||||
public static ObjectNameWrapper wrap(final ObjectName objectName) {
|
||||
return new ObjectNameWrapper(objectName);
|
||||
}
|
||||
|
||||
public static ObjectNameWrapper wrap(final String name) throws MalformedObjectNameException {
|
||||
return wrap(new ObjectName(name));
|
||||
}
|
||||
|
||||
private final ObjectName objectName;
|
||||
|
||||
public ObjectNameWrapper(final ObjectName objectName) {
|
||||
this.objectName = objectName;
|
||||
}
|
||||
|
||||
public void registerMBean(final Object object) {
|
||||
if (MBEAN_SERVER == null || objectName == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
MBEAN_SERVER.registerMBean(object, objectName);
|
||||
} catch (LinkageError | Exception e) {
|
||||
log.warn("Failed to complete JMX registration for " + objectName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.0
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toString(objectName);
|
||||
}
|
||||
|
||||
public void unregisterMBean() {
|
||||
if (MBEAN_SERVER == null || objectName == null) {
|
||||
return;
|
||||
}
|
||||
if (MBEAN_SERVER.isRegistered(objectName)) {
|
||||
try {
|
||||
MBEAN_SERVER.unregisterMBean(objectName);
|
||||
} catch (LinkageError | Exception e) {
|
||||
log.warn("Failed to complete JMX unregistration for " + objectName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectName unwrap() {
|
||||
return objectName;
|
||||
}
|
||||
|
||||
}
|
||||
998
java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java
Normal file
998
java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java
Normal file
@@ -0,0 +1,998 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.tomcat.dbcp.dbcp2.PoolingConnection.StatementType;
|
||||
|
||||
/**
|
||||
* A key uniquely identifying {@link java.sql.PreparedStatement PreparedStatement}s.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PStmtKey {
|
||||
|
||||
/**
|
||||
* Builder for prepareCall(String sql).
|
||||
*/
|
||||
private class PreparedCallSQL implements StatementBuilder {
|
||||
@Override
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
return connection.prepareCall(sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for prepareCall(String sql, int resultSetType, int resultSetConcurrency).
|
||||
*/
|
||||
private class PreparedCallWithResultSetConcurrency implements StatementBuilder {
|
||||
@Override
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
return connection.prepareCall(sql, resultSetType.intValue(), resultSetConcurrency.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability).
|
||||
*/
|
||||
private class PreparedCallWithResultSetHoldability implements StatementBuilder {
|
||||
@Override
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
return connection.prepareCall(sql, resultSetType.intValue(), resultSetConcurrency.intValue(),
|
||||
resultSetHoldability.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for prepareStatement(String sql).
|
||||
*/
|
||||
private class PreparedStatementSQL implements StatementBuilder {
|
||||
@Override
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for prepareStatement(String sql, int autoGeneratedKeys).
|
||||
*/
|
||||
private class PreparedStatementWithAutoGeneratedKeys implements StatementBuilder {
|
||||
@Override
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(sql, autoGeneratedKeys.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for prepareStatement(String sql, int[] columnIndexes).
|
||||
*/
|
||||
private class PreparedStatementWithColumnIndexes implements StatementBuilder {
|
||||
@Override
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(sql, columnIndexes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for prepareStatement(String sql, String[] columnNames).
|
||||
*/
|
||||
private class PreparedStatementWithColumnNames implements StatementBuilder {
|
||||
@Override
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(sql, columnNames);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for prepareStatement(String sql, int resultSetType, int resultSetConcurrency).
|
||||
*/
|
||||
private class PreparedStatementWithResultSetConcurrency implements StatementBuilder {
|
||||
@Override
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(sql, resultSetType.intValue(), resultSetConcurrency.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability).
|
||||
*/
|
||||
private class PreparedStatementWithResultSetHoldability implements StatementBuilder {
|
||||
@Override
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
return connection.prepareStatement(sql, resultSetType.intValue(), resultSetConcurrency.intValue(),
|
||||
resultSetHoldability.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for Prepared or Callable Statement.
|
||||
*/
|
||||
private interface StatementBuilder {
|
||||
Statement createStatement(Connection connection) throws SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL defining Prepared or Callable Statement
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
/**
|
||||
* Result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>, <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>,
|
||||
* or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
|
||||
*/
|
||||
private final Integer resultSetType;
|
||||
|
||||
/**
|
||||
* Result set concurrency. A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
|
||||
* <code>ResultSet.CONCUR_UPDATABLE</code>.
|
||||
*/
|
||||
private final Integer resultSetConcurrency;
|
||||
|
||||
/**
|
||||
* Result set holdability. One of the following <code>ResultSet</code> constants:
|
||||
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>.
|
||||
*/
|
||||
private final Integer resultSetHoldability;
|
||||
|
||||
/** Database catalog. */
|
||||
private final String catalog;
|
||||
|
||||
/** Database schema. */
|
||||
private final String schema;
|
||||
|
||||
/**
|
||||
* 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>.
|
||||
*/
|
||||
private final Integer autoGeneratedKeys;
|
||||
|
||||
/**
|
||||
* An array of column indexes indicating the columns that should be returned from the inserted row or rows.
|
||||
*/
|
||||
private final int[] columnIndexes;
|
||||
|
||||
/**
|
||||
* An array of column names indicating the columns that should be returned from the inserted row or rows.
|
||||
*/
|
||||
private final String[] columnNames;
|
||||
|
||||
/**
|
||||
* Statement type, prepared or callable.
|
||||
*/
|
||||
private final StatementType statementType;
|
||||
|
||||
/** Statement builder */
|
||||
private transient StatementBuilder builder;
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql) {
|
||||
this(sql, null, StatementType.PREPARED_STATEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @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>.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String, int, int)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
|
||||
this(sql, null, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog) {
|
||||
this(sql, catalog, StatementType.PREPARED_STATEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @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>.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String, int)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog, final int autoGeneratedKeys) {
|
||||
this(sql, catalog, StatementType.PREPARED_STATEMENT, Integer.valueOf(autoGeneratedKeys));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @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>.
|
||||
* @deprecated Use @link {@link #PStmtKey(String, String, String, int, int)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency) {
|
||||
this(sql, catalog, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @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>
|
||||
* @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>.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String, int, int, int)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability) {
|
||||
this(sql, catalog, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @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>.
|
||||
* @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>.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String, int, int, int, PoolingConnection.StatementType)}
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability, final StatementType statementType) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = null;
|
||||
this.resultSetType = Integer.valueOf(resultSetType);
|
||||
this.resultSetConcurrency = Integer.valueOf(resultSetConcurrency);
|
||||
this.resultSetHoldability = Integer.valueOf(resultSetHoldability);
|
||||
this.statementType = statementType;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = null;
|
||||
// create builder
|
||||
if (statementType == StatementType.PREPARED_STATEMENT) {
|
||||
this.builder = new PreparedStatementWithResultSetHoldability();
|
||||
} else if (statementType == StatementType.CALLABLE_STATEMENT) {
|
||||
this.builder = new PreparedCallWithResultSetHoldability();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @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>.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String, int, int, PoolingConnection.StatementType)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency,
|
||||
final StatementType statementType) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = null;
|
||||
this.resultSetType = Integer.valueOf(resultSetType);
|
||||
this.resultSetConcurrency = Integer.valueOf(resultSetConcurrency);
|
||||
this.resultSetHoldability = null;
|
||||
this.statementType = statementType;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = null;
|
||||
// create builder
|
||||
if (statementType == StatementType.PREPARED_STATEMENT) {
|
||||
this.builder = new PreparedStatementWithResultSetConcurrency();
|
||||
} else if (statementType == StatementType.CALLABLE_STATEMENT) {
|
||||
this.builder = new PreparedCallWithResultSetConcurrency();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param columnIndexes
|
||||
* An array of column indexes indicating the columns that should be returned from the inserted row or
|
||||
* rows.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String, int[])}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog, final int[] columnIndexes) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = null;
|
||||
this.statementType = StatementType.PREPARED_STATEMENT;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = columnIndexes == null ? null : Arrays.copyOf(columnIndexes, columnIndexes.length);
|
||||
this.columnNames = null;
|
||||
this.resultSetType = null;
|
||||
this.resultSetConcurrency = null;
|
||||
this.resultSetHoldability = null;
|
||||
// create builder
|
||||
this.builder = new PreparedStatementWithColumnIndexes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String, PoolingConnection.StatementType)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog, final StatementType statementType) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = null;
|
||||
this.statementType = statementType;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = null;
|
||||
this.resultSetType = null;
|
||||
this.resultSetConcurrency = null;
|
||||
this.resultSetHoldability = null;
|
||||
// create builder
|
||||
if (statementType == StatementType.PREPARED_STATEMENT) {
|
||||
this.builder = new PreparedStatementSQL();
|
||||
} else if (statementType == StatementType.CALLABLE_STATEMENT) {
|
||||
this.builder = new PreparedCallSQL();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @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>.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String, PoolingConnection.StatementType, Integer)}
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog, final StatementType statementType,
|
||||
final Integer autoGeneratedKeys) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = null;
|
||||
this.statementType = statementType;
|
||||
this.autoGeneratedKeys = autoGeneratedKeys;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = null;
|
||||
this.resultSetType = null;
|
||||
this.resultSetConcurrency = null;
|
||||
this.resultSetHoldability = null;
|
||||
// create builder
|
||||
if (statementType == StatementType.PREPARED_STATEMENT) {
|
||||
this.builder = new PreparedStatementWithAutoGeneratedKeys();
|
||||
} else if (statementType == StatementType.CALLABLE_STATEMENT) {
|
||||
this.builder = new PreparedCallSQL();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema) {
|
||||
this(sql, catalog, schema, StatementType.PREPARED_STATEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema
|
||||
* @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>.
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema, final int autoGeneratedKeys) {
|
||||
this(sql, catalog, schema, StatementType.PREPARED_STATEMENT, Integer.valueOf(autoGeneratedKeys));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema
|
||||
* @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>.
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency) {
|
||||
this(sql, catalog, schema, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema
|
||||
* @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>
|
||||
* @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>.
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability) {
|
||||
this(sql, catalog, schema, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema.
|
||||
* @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>.
|
||||
* @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>.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability, final StatementType statementType) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = schema;
|
||||
this.resultSetType = Integer.valueOf(resultSetType);
|
||||
this.resultSetConcurrency = Integer.valueOf(resultSetConcurrency);
|
||||
this.resultSetHoldability = Integer.valueOf(resultSetHoldability);
|
||||
this.statementType = statementType;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = null;
|
||||
// create builder
|
||||
if (statementType == StatementType.PREPARED_STATEMENT) {
|
||||
this.builder = new PreparedStatementWithResultSetHoldability();
|
||||
} else if (statementType == StatementType.CALLABLE_STATEMENT) {
|
||||
this.builder = new PreparedCallWithResultSetHoldability();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema.
|
||||
* @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>.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema, final int resultSetType, final int resultSetConcurrency,
|
||||
final StatementType statementType) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = schema;
|
||||
this.resultSetType = Integer.valueOf(resultSetType);
|
||||
this.resultSetConcurrency = Integer.valueOf(resultSetConcurrency);
|
||||
this.resultSetHoldability = null;
|
||||
this.statementType = statementType;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = null;
|
||||
// create builder
|
||||
if (statementType == StatementType.PREPARED_STATEMENT) {
|
||||
this.builder = new PreparedStatementWithResultSetConcurrency();
|
||||
} else if (statementType == StatementType.CALLABLE_STATEMENT) {
|
||||
this.builder = new PreparedCallWithResultSetConcurrency();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema.
|
||||
* @param columnIndexes
|
||||
* An array of column indexes indicating the columns that should be returned from the inserted row or
|
||||
* rows.
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema, final int[] columnIndexes) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = schema;
|
||||
this.statementType = StatementType.PREPARED_STATEMENT;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = columnIndexes == null ? null : Arrays.copyOf(columnIndexes, columnIndexes.length);
|
||||
this.columnNames = null;
|
||||
this.resultSetType = null;
|
||||
this.resultSetConcurrency = null;
|
||||
this.resultSetHoldability = null;
|
||||
// create builder
|
||||
this.builder = new PreparedStatementWithColumnIndexes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema, final StatementType statementType) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = schema;
|
||||
this.statementType = statementType;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = null;
|
||||
this.resultSetType = null;
|
||||
this.resultSetConcurrency = null;
|
||||
this.resultSetHoldability = null;
|
||||
// create builder
|
||||
if (statementType == StatementType.PREPARED_STATEMENT) {
|
||||
this.builder = new PreparedStatementSQL();
|
||||
} else if (statementType == StatementType.CALLABLE_STATEMENT) {
|
||||
this.builder = new PreparedCallSQL();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @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>.
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema, final StatementType statementType,
|
||||
final Integer autoGeneratedKeys) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = schema;
|
||||
this.statementType = statementType;
|
||||
this.autoGeneratedKeys = autoGeneratedKeys;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = null;
|
||||
this.resultSetType = null;
|
||||
this.resultSetConcurrency = null;
|
||||
this.resultSetHoldability = null;
|
||||
// create builder
|
||||
if (statementType == StatementType.PREPARED_STATEMENT) {
|
||||
this.builder = new PreparedStatementWithAutoGeneratedKeys();
|
||||
} else if (statementType == StatementType.CALLABLE_STATEMENT) {
|
||||
this.builder = new PreparedCallSQL();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param schema
|
||||
* The schema.
|
||||
* @param columnNames
|
||||
* An array of column names indicating the columns that should be returned from the inserted row or rows.
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public PStmtKey(final String sql, final String catalog, final String schema, final String[] columnNames) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = schema;
|
||||
this.statementType = StatementType.PREPARED_STATEMENT;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = columnNames == null ? null : Arrays.copyOf(columnNames, columnNames.length);
|
||||
this.resultSetType = null;
|
||||
this.resultSetConcurrency = null;
|
||||
this.resultSetHoldability = null;
|
||||
// create builder
|
||||
builder = new PreparedStatementWithColumnNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param catalog
|
||||
* The catalog.
|
||||
* @param columnNames
|
||||
* An array of column names indicating the columns that should be returned from the inserted row or rows.
|
||||
* @deprecated Use {@link #PStmtKey(String, String, String, String[])}.
|
||||
*/
|
||||
@Deprecated
|
||||
public PStmtKey(final String sql, final String catalog, final String[] columnNames) {
|
||||
this.sql = sql;
|
||||
this.catalog = catalog;
|
||||
this.schema = null;
|
||||
this.statementType = StatementType.PREPARED_STATEMENT;
|
||||
this.autoGeneratedKeys = null;
|
||||
this.columnIndexes = null;
|
||||
this.columnNames = columnNames == null ? null : Arrays.copyOf(columnNames, columnNames.length);
|
||||
this.resultSetType = null;
|
||||
this.resultSetConcurrency = null;
|
||||
this.resultSetHoldability = null;
|
||||
// create builder
|
||||
builder = new PreparedStatementWithColumnNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Statement from the given Connection.
|
||||
*
|
||||
* @param connection
|
||||
* The Connection to use to create the statement.
|
||||
* @return The statement.
|
||||
* @throws SQLException
|
||||
* Thrown when there is a problem creating the statement.
|
||||
*/
|
||||
public Statement createStatement(final Connection connection) throws SQLException {
|
||||
if (builder == null) {
|
||||
throw new IllegalStateException("Prepared statement key is invalid.");
|
||||
}
|
||||
return builder.createStatement(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final PStmtKey other = (PStmtKey) obj;
|
||||
if (autoGeneratedKeys == null) {
|
||||
if (other.autoGeneratedKeys != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!autoGeneratedKeys.equals(other.autoGeneratedKeys)) {
|
||||
return false;
|
||||
}
|
||||
if (catalog == null) {
|
||||
if (other.catalog != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!catalog.equals(other.catalog)) {
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(columnIndexes, other.columnIndexes)) {
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(columnNames, other.columnNames)) {
|
||||
return false;
|
||||
}
|
||||
if (resultSetConcurrency == null) {
|
||||
if (other.resultSetConcurrency != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!resultSetConcurrency.equals(other.resultSetConcurrency)) {
|
||||
return false;
|
||||
}
|
||||
if (resultSetHoldability == null) {
|
||||
if (other.resultSetHoldability != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!resultSetHoldability.equals(other.resultSetHoldability)) {
|
||||
return false;
|
||||
}
|
||||
if (resultSetType == null) {
|
||||
if (other.resultSetType != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!resultSetType.equals(other.resultSetType)) {
|
||||
return false;
|
||||
}
|
||||
if (schema == null) {
|
||||
if (other.schema != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!schema.equals(other.schema)) {
|
||||
return false;
|
||||
}
|
||||
if (sql == null) {
|
||||
if (other.sql != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!sql.equals(other.sql)) {
|
||||
return false;
|
||||
}
|
||||
if (statementType != other.statementType) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets 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 flag indicating whether auto-generated keys should be returned.
|
||||
*/
|
||||
public Integer getAutoGeneratedKeys() {
|
||||
return autoGeneratedKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* The catalog.
|
||||
*
|
||||
* @return The catalog.
|
||||
*/
|
||||
public String getCatalog() {
|
||||
return catalog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of column indexes indicating the columns that should be returned from the inserted row or rows.
|
||||
*
|
||||
* @return An array of column indexes.
|
||||
*/
|
||||
public int[] getColumnIndexes() {
|
||||
return columnIndexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of column names indicating the columns that should be returned from the inserted row or rows.
|
||||
*
|
||||
* @return An array of column names.
|
||||
*/
|
||||
public String[] getColumnNames() {
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result set concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
|
||||
* <code>ResultSet.CONCUR_UPDATABLE</code>.
|
||||
*
|
||||
* @return The result set concurrency type.
|
||||
*/
|
||||
public Integer getResultSetConcurrency() {
|
||||
return resultSetConcurrency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result set holdability, one of the following <code>ResultSet</code> constants:
|
||||
* <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>.
|
||||
*
|
||||
* @return The result set holdability.
|
||||
*/
|
||||
public Integer getResultSetHoldability() {
|
||||
return resultSetHoldability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result set type, one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
|
||||
* <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
|
||||
*
|
||||
* @return the result set type.
|
||||
*/
|
||||
public Integer getResultSetType() {
|
||||
return resultSetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The schema.
|
||||
*
|
||||
* @return The catalog.
|
||||
*/
|
||||
public String getSchema() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL statement.
|
||||
*
|
||||
* @return the SQL statement.
|
||||
*/
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL statement type.
|
||||
*
|
||||
* @return The SQL statement type.
|
||||
*/
|
||||
public StatementType getStmtType() {
|
||||
return statementType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((autoGeneratedKeys == null) ? 0 : autoGeneratedKeys.hashCode());
|
||||
result = prime * result + ((catalog == null) ? 0 : catalog.hashCode());
|
||||
result = prime * result + Arrays.hashCode(columnIndexes);
|
||||
result = prime * result + Arrays.hashCode(columnNames);
|
||||
result = prime * result + ((resultSetConcurrency == null) ? 0 : resultSetConcurrency.hashCode());
|
||||
result = prime * result + ((resultSetHoldability == null) ? 0 : resultSetHoldability.hashCode());
|
||||
result = prime * result + ((resultSetType == null) ? 0 : resultSetType.hashCode());
|
||||
result = prime * result + ((schema == null) ? 0 : schema.hashCode());
|
||||
result = prime * result + ((sql == null) ? 0 : sql.hashCode());
|
||||
result = prime * result + ((statementType == null) ? 0 : statementType.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
buf.append("PStmtKey: sql=");
|
||||
buf.append(sql);
|
||||
buf.append(", catalog=");
|
||||
buf.append(catalog);
|
||||
buf.append(", schema=");
|
||||
buf.append(schema);
|
||||
buf.append(", resultSetType=");
|
||||
buf.append(resultSetType);
|
||||
buf.append(", resultSetConcurrency=");
|
||||
buf.append(resultSetConcurrency);
|
||||
buf.append(", resultSetHoldability=");
|
||||
buf.append(resultSetHoldability);
|
||||
buf.append(", autoGeneratedKeys=");
|
||||
buf.append(autoGeneratedKeys);
|
||||
buf.append(", columnIndexes=");
|
||||
buf.append(Arrays.toString(columnIndexes));
|
||||
buf.append(", columnNames=");
|
||||
buf.append(Arrays.toString(columnNames));
|
||||
buf.append(", statementType=");
|
||||
buf.append(statementType);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
145
java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
Normal file
145
java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
|
||||
|
||||
/**
|
||||
* A {@link DelegatingCallableStatement} that cooperates with {@link PoolingConnection} to implement a pool of
|
||||
* {@link CallableStatement}s.
|
||||
* <p>
|
||||
* The {@link #close} method returns this statement to its containing pool. (See {@link PoolingConnection}.)
|
||||
*
|
||||
* @see PoolingConnection
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PoolableCallableStatement extends DelegatingCallableStatement {
|
||||
|
||||
/**
|
||||
* The {@link KeyedObjectPool} from which this CallableStatement was obtained.
|
||||
*/
|
||||
private final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pool;
|
||||
|
||||
/**
|
||||
* Key for this statement in the containing {@link KeyedObjectPool}.
|
||||
*/
|
||||
private final PStmtKey key;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param callableStatement
|
||||
* the underlying {@link CallableStatement}
|
||||
* @param key
|
||||
* the key for this statement in the {@link KeyedObjectPool}
|
||||
* @param pool
|
||||
* the {@link KeyedObjectPool} from which this CallableStatement was obtained
|
||||
* @param connection
|
||||
* the {@link DelegatingConnection} that created this CallableStatement
|
||||
*/
|
||||
public PoolableCallableStatement(final CallableStatement callableStatement, final PStmtKey key,
|
||||
final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pool,
|
||||
final DelegatingConnection<Connection> connection) {
|
||||
super(connection, callableStatement);
|
||||
this.pool = pool;
|
||||
this.key = key;
|
||||
|
||||
// Remove from trace now because this statement will be
|
||||
// added by the activate method.
|
||||
removeThisTrace(getConnectionInternal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CallableStatement to the pool. If {{@link #isClosed()}, this is a No-op.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
// calling close twice should have no effect
|
||||
if (!isClosed()) {
|
||||
try {
|
||||
pool.returnObject(key, this);
|
||||
} catch (final SQLException e) {
|
||||
throw e;
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Cannot close CallableStatement (return to pool failed)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates after retrieval from the pool. Adds a trace for this CallableStatement to the Connection that created
|
||||
* it.
|
||||
*
|
||||
* @since 2.4.0 made public, was protected in 2.3.0.
|
||||
*/
|
||||
@Override
|
||||
public void activate() throws SQLException {
|
||||
setClosedInternal(false);
|
||||
if (getConnectionInternal() != null) {
|
||||
getConnectionInternal().addTrace(this);
|
||||
}
|
||||
super.activate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Passivates to prepare for return to the pool. Removes the trace associated with this CallableStatement from the
|
||||
* Connection that created it. Also closes any associated ResultSets.
|
||||
*
|
||||
* @since 2.4.0 made public, was protected in 2.3.0.
|
||||
*/
|
||||
@Override
|
||||
public void passivate() throws SQLException {
|
||||
setClosedInternal(true);
|
||||
removeThisTrace(getConnectionInternal());
|
||||
|
||||
// The JDBC spec requires that a statement close any open
|
||||
// ResultSet's when it is closed.
|
||||
// FIXME The PreparedStatement we're wrapping should handle this for us.
|
||||
// See DBCP-10 for what could happen when ResultSets are closed twice.
|
||||
final List<AbandonedTrace> resultSetList = getTrace();
|
||||
if (resultSetList != null) {
|
||||
final List<Exception> thrownList = new ArrayList<>();
|
||||
final ResultSet[] resultSets = resultSetList.toArray(new ResultSet[resultSetList.size()]);
|
||||
for (final ResultSet resultSet : resultSets) {
|
||||
if (resultSet != null) {
|
||||
try {
|
||||
resultSet.close();
|
||||
} catch (Exception e) {
|
||||
thrownList.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
clearTrace();
|
||||
if (!thrownList.isEmpty()) {
|
||||
throw new SQLExceptionList(thrownList);
|
||||
}
|
||||
}
|
||||
|
||||
super.passivate();
|
||||
}
|
||||
|
||||
}
|
||||
348
java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
Normal file
348
java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.ObjectPool;
|
||||
|
||||
/**
|
||||
* A delegating connection that, rather than closing the underlying connection, returns itself to an {@link ObjectPool}
|
||||
* when closed.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PoolableConnection extends DelegatingConnection<Connection> implements PoolableConnectionMXBean {
|
||||
|
||||
private static MBeanServer MBEAN_SERVER;
|
||||
|
||||
static {
|
||||
try {
|
||||
MBEAN_SERVER = ManagementFactory.getPlatformMBeanServer();
|
||||
} catch (NoClassDefFoundError | Exception ex) {
|
||||
// ignore - JMX not available
|
||||
}
|
||||
}
|
||||
|
||||
/** The pool to which I should return. */
|
||||
private final ObjectPool<PoolableConnection> pool;
|
||||
|
||||
private final ObjectNameWrapper jmxObjectName;
|
||||
|
||||
// Use a prepared statement for validation, retaining the last used SQL to
|
||||
// check if the validation query has changed.
|
||||
private PreparedStatement validationPreparedStatement;
|
||||
private String lastValidationSql;
|
||||
|
||||
/**
|
||||
* Indicate that unrecoverable SQLException was thrown when using this connection. Such a connection should be
|
||||
* considered broken and not pass validation in the future.
|
||||
*/
|
||||
private boolean fatalSqlExceptionThrown = false;
|
||||
|
||||
/**
|
||||
* SQL_STATE codes considered to signal fatal conditions. Overrides the defaults in
|
||||
* {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting with {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}).
|
||||
*/
|
||||
private final Collection<String> disconnectionSqlCodes;
|
||||
|
||||
/** Whether or not to fast fail validation after fatal connection errors */
|
||||
private final boolean fastFailValidation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param conn
|
||||
* my underlying connection
|
||||
* @param pool
|
||||
* the pool to which I should return when closed
|
||||
* @param jmxObjectName
|
||||
* JMX name
|
||||
* @param disconnectSqlCodes
|
||||
* SQL_STATE codes considered fatal disconnection errors
|
||||
* @param fastFailValidation
|
||||
* true means fatal disconnection errors cause subsequent validations to fail immediately (no attempt to
|
||||
* run query or isValid)
|
||||
*/
|
||||
public PoolableConnection(final Connection conn, final ObjectPool<PoolableConnection> pool,
|
||||
final ObjectName jmxObjectName, final Collection<String> disconnectSqlCodes,
|
||||
final boolean fastFailValidation) {
|
||||
super(conn);
|
||||
this.pool = pool;
|
||||
this.jmxObjectName = ObjectNameWrapper.wrap(jmxObjectName);
|
||||
this.disconnectionSqlCodes = disconnectSqlCodes;
|
||||
this.fastFailValidation = fastFailValidation;
|
||||
|
||||
if (jmxObjectName != null) {
|
||||
try {
|
||||
MBEAN_SERVER.registerMBean(this, jmxObjectName);
|
||||
} catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
|
||||
// For now, simply skip registration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param conn
|
||||
* my underlying connection
|
||||
* @param pool
|
||||
* the pool to which I should return when closed
|
||||
* @param jmxName
|
||||
* JMX name
|
||||
*/
|
||||
public PoolableConnection(final Connection conn, final ObjectPool<PoolableConnection> pool,
|
||||
final ObjectName jmxName) {
|
||||
this(conn, pool, jmxName, null, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void passivate() throws SQLException {
|
||||
super.passivate();
|
||||
setClosedInternal(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* This method should not be used by a client to determine whether or not a connection should be return to the
|
||||
* connection pool (by calling {@link #close()}). Clients should always attempt to return a connection to the pool
|
||||
* once it is no longer required.
|
||||
*/
|
||||
@Override
|
||||
public boolean isClosed() throws SQLException {
|
||||
if (isClosedInternal()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getDelegateInternal().isClosed()) {
|
||||
// Something has gone wrong. The underlying connection has been
|
||||
// closed without the connection being returned to the pool. Return
|
||||
// it now.
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns me to my pool.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void close() throws SQLException {
|
||||
if (isClosedInternal()) {
|
||||
// already closed
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isUnderlyingConnectionClosed;
|
||||
try {
|
||||
isUnderlyingConnectionClosed = getDelegateInternal().isClosed();
|
||||
} catch (final SQLException e) {
|
||||
try {
|
||||
pool.invalidateObject(this);
|
||||
} catch (final IllegalStateException ise) {
|
||||
// pool is closed, so close the connection
|
||||
passivate();
|
||||
getInnermostDelegate().close();
|
||||
} catch (final Exception ie) {
|
||||
// DO NOTHING the original exception will be rethrown
|
||||
}
|
||||
throw new SQLException("Cannot close connection (isClosed check failed)", e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't set close before this code block since the connection needs to be open when validation runs. Can't set
|
||||
* close after this code block since by then the connection will have been returned to the pool and may have
|
||||
* been borrowed by another thread. Therefore, the close flag is set in passivate().
|
||||
*/
|
||||
if (isUnderlyingConnectionClosed) {
|
||||
// Abnormal close: underlying connection closed unexpectedly, so we
|
||||
// must destroy this proxy
|
||||
try {
|
||||
pool.invalidateObject(this);
|
||||
} catch (final IllegalStateException e) {
|
||||
// pool is closed, so close the connection
|
||||
passivate();
|
||||
getInnermostDelegate().close();
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Cannot close connection (invalidating pooled object failed)", e);
|
||||
}
|
||||
} else {
|
||||
// Normal close: underlying connection is still open, so we
|
||||
// simply need to return this proxy to the pool
|
||||
try {
|
||||
pool.returnObject(this);
|
||||
} catch (final IllegalStateException e) {
|
||||
// pool is closed, so close the connection
|
||||
passivate();
|
||||
getInnermostDelegate().close();
|
||||
} catch (final SQLException e) {
|
||||
throw e;
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Cannot close connection (return to pool failed)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually close my underlying {@link Connection}.
|
||||
*/
|
||||
@Override
|
||||
public void reallyClose() throws SQLException {
|
||||
if (jmxObjectName != null) {
|
||||
jmxObjectName.unregisterMBean();
|
||||
}
|
||||
|
||||
if (validationPreparedStatement != null) {
|
||||
try {
|
||||
validationPreparedStatement.close();
|
||||
} catch (final SQLException sqle) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
super.closeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose the {@link #toString()} method via a bean getter so it can be read as a property via JMX.
|
||||
*/
|
||||
@Override
|
||||
public String getToString() {
|
||||
return toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the connection, using the following algorithm:
|
||||
* <ol>
|
||||
* <li>If {@code fastFailValidation} (constructor argument) is {@code true} and this connection has previously
|
||||
* thrown a fatal disconnection exception, a {@code SQLException} is thrown.</li>
|
||||
* <li>If {@code sql} is null, the driver's #{@link Connection#isValid(int) isValid(timeout)} is called. If it
|
||||
* returns {@code false}, {@code SQLException} is thrown; otherwise, this method returns successfully.</li>
|
||||
* <li>If {@code sql} is not null, it is executed as a query and if the resulting {@code ResultSet} contains at
|
||||
* least one row, this method returns successfully. If not, {@code SQLException} is thrown.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param sql
|
||||
* The validation SQL query.
|
||||
* @param timeoutSeconds
|
||||
* The validation timeout in seconds.
|
||||
* @throws SQLException
|
||||
* Thrown when validation fails or an SQLException occurs during validation
|
||||
*/
|
||||
public void validate(final String sql, int timeoutSeconds) throws SQLException {
|
||||
if (fastFailValidation && fatalSqlExceptionThrown) {
|
||||
throw new SQLException(Utils.getMessage("poolableConnection.validate.fastFail"));
|
||||
}
|
||||
|
||||
if (sql == null || sql.length() == 0) {
|
||||
if (timeoutSeconds < 0) {
|
||||
timeoutSeconds = 0;
|
||||
}
|
||||
if (!isValid(timeoutSeconds)) {
|
||||
throw new SQLException("isValid() returned false");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sql.equals(lastValidationSql)) {
|
||||
lastValidationSql = sql;
|
||||
// Has to be the innermost delegate else the prepared statement will
|
||||
// be closed when the pooled connection is passivated.
|
||||
validationPreparedStatement = getInnermostDelegateInternal().prepareStatement(sql);
|
||||
}
|
||||
|
||||
if (timeoutSeconds > 0) {
|
||||
validationPreparedStatement.setQueryTimeout(timeoutSeconds);
|
||||
}
|
||||
|
||||
try (ResultSet rs = validationPreparedStatement.executeQuery()) {
|
||||
if (!rs.next()) {
|
||||
throw new SQLException("validationQuery didn't return a row");
|
||||
}
|
||||
} catch (final SQLException sqle) {
|
||||
throw sqle;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the SQLState of the input exception and any nested SQLExceptions it wraps.
|
||||
* <p>
|
||||
* If {@link #disconnectionSqlCodes} has been set, sql states are compared to those in the
|
||||
* configured list of fatal exception codes. If this property is not set, codes are compared against the default
|
||||
* codes in {@link Utils#DISCONNECTION_SQL_CODES} and in this case anything starting with #{link
|
||||
* Utils.DISCONNECTION_SQL_CODE_PREFIX} is considered a disconnection.
|
||||
* </p>
|
||||
*
|
||||
* @param e
|
||||
* SQLException to be examined
|
||||
* @return true if the exception signals a disconnection
|
||||
*/
|
||||
private boolean isDisconnectionSqlException(final SQLException e) {
|
||||
boolean fatalException = false;
|
||||
final String sqlState = e.getSQLState();
|
||||
if (sqlState != null) {
|
||||
fatalException = disconnectionSqlCodes == null
|
||||
? sqlState.startsWith(Utils.DISCONNECTION_SQL_CODE_PREFIX)
|
||||
|| Utils.DISCONNECTION_SQL_CODES.contains(sqlState)
|
||||
: disconnectionSqlCodes.contains(sqlState);
|
||||
if (!fatalException) {
|
||||
final SQLException nextException = e.getNextException();
|
||||
if (nextException != null && nextException != e) {
|
||||
fatalException = isDisconnectionSqlException(e.getNextException());
|
||||
}
|
||||
}
|
||||
}
|
||||
return fatalException;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleException(final SQLException e) throws SQLException {
|
||||
fatalSqlExceptionThrown |= isDisconnectionSqlException(e);
|
||||
super.handleException(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The disconnection SQL codes.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Collection<String> getDisconnectionSqlCodes() {
|
||||
return disconnectionSqlCodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether to fail-fast.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public boolean isFastFailValidation() {
|
||||
return fastFailValidation;
|
||||
}
|
||||
}
|
||||
657
java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
Normal file
657
java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
Normal file
@@ -0,0 +1,657 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
|
||||
import org.apache.tomcat.dbcp.pool2.ObjectPool;
|
||||
import org.apache.tomcat.dbcp.pool2.PooledObject;
|
||||
import org.apache.tomcat.dbcp.pool2.PooledObjectFactory;
|
||||
import org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject;
|
||||
import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPool;
|
||||
import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
|
||||
/**
|
||||
* A {@link PooledObjectFactory} that creates {@link PoolableConnection}s.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PoolableConnectionFactory implements PooledObjectFactory<PoolableConnection> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(PoolableConnectionFactory.class);
|
||||
|
||||
/**
|
||||
* Internal constant to indicate the level is not set.
|
||||
*/
|
||||
static final int UNKNOWN_TRANSACTION_ISOLATION = -1;
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
|
||||
private final ObjectName dataSourceJmxObjectName;
|
||||
|
||||
private volatile String validationQuery;
|
||||
|
||||
private volatile int validationQueryTimeoutSeconds = -1;
|
||||
|
||||
private Collection<String> connectionInitSqls;
|
||||
|
||||
private Collection<String> disconnectionSqlCodes;
|
||||
|
||||
private boolean fastFailValidation = true;
|
||||
|
||||
private volatile ObjectPool<PoolableConnection> pool;
|
||||
|
||||
private Boolean defaultReadOnly;
|
||||
|
||||
private Boolean defaultAutoCommit;
|
||||
|
||||
private boolean autoCommitOnReturn = true;
|
||||
|
||||
private boolean rollbackOnReturn = true;
|
||||
|
||||
private int defaultTransactionIsolation = UNKNOWN_TRANSACTION_ISOLATION;
|
||||
|
||||
private String defaultCatalog;
|
||||
|
||||
private String defaultSchema;
|
||||
|
||||
private boolean cacheState;
|
||||
|
||||
private boolean poolStatements;
|
||||
|
||||
private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
|
||||
|
||||
private long maxConnLifetimeMillis = -1;
|
||||
|
||||
private final AtomicLong connectionIndex = new AtomicLong(0);
|
||||
|
||||
private Integer defaultQueryTimeoutSeconds;
|
||||
|
||||
/**
|
||||
* Creates a new {@code PoolableConnectionFactory}.
|
||||
*
|
||||
* @param connFactory
|
||||
* the {@link ConnectionFactory} from which to obtain base {@link Connection}s
|
||||
* @param dataSourceJmxObjectName
|
||||
* The JMX object name, may be null.
|
||||
*/
|
||||
public PoolableConnectionFactory(final ConnectionFactory connFactory, final ObjectName dataSourceJmxObjectName) {
|
||||
this.connectionFactory = connFactory;
|
||||
this.dataSourceJmxObjectName = dataSourceJmxObjectName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(final PooledObject<PoolableConnection> p) throws Exception {
|
||||
|
||||
validateLifetime(p);
|
||||
|
||||
final PoolableConnection conn = p.getObject();
|
||||
conn.activate();
|
||||
|
||||
if (defaultAutoCommit != null && conn.getAutoCommit() != defaultAutoCommit.booleanValue()) {
|
||||
conn.setAutoCommit(defaultAutoCommit.booleanValue());
|
||||
}
|
||||
if (defaultTransactionIsolation != UNKNOWN_TRANSACTION_ISOLATION
|
||||
&& conn.getTransactionIsolation() != defaultTransactionIsolation) {
|
||||
conn.setTransactionIsolation(defaultTransactionIsolation);
|
||||
}
|
||||
if (defaultReadOnly != null && conn.isReadOnly() != defaultReadOnly.booleanValue()) {
|
||||
conn.setReadOnly(defaultReadOnly.booleanValue());
|
||||
}
|
||||
if (defaultCatalog != null && !defaultCatalog.equals(conn.getCatalog())) {
|
||||
conn.setCatalog(defaultCatalog);
|
||||
}
|
||||
if (defaultSchema != null && !defaultSchema.equals(Jdbc41Bridge.getSchema(conn))) {
|
||||
Jdbc41Bridge.setSchema(conn, defaultSchema);
|
||||
}
|
||||
conn.setDefaultQueryTimeout(defaultQueryTimeoutSeconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyObject(final PooledObject<PoolableConnection> p) throws Exception {
|
||||
p.getObject().reallyClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The cache state.
|
||||
* @since Made public in 2.6.0.
|
||||
*/
|
||||
public boolean getCacheState() {
|
||||
return cacheState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The connection factory.
|
||||
* @since Made public in 2.6.0.
|
||||
*/
|
||||
public ConnectionFactory getConnectionFactory() {
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
protected AtomicLong getConnectionIndex() {
|
||||
return connectionIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The collection of initialization SQL statements.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Collection<String> getConnectionInitSqls() {
|
||||
return connectionInitSqls;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The data source JMX ObjectName
|
||||
* @since Made public in 2.6.0.
|
||||
*/
|
||||
public ObjectName getDataSourceJmxName() {
|
||||
return dataSourceJmxObjectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The data source JMS ObjectName.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public ObjectName getDataSourceJmxObjectName() {
|
||||
return dataSourceJmxObjectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Default auto-commit value.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Boolean getDefaultAutoCommit() {
|
||||
return defaultAutoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Default catalog.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public String getDefaultCatalog() {
|
||||
return defaultCatalog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Default query timeout in seconds.
|
||||
*/
|
||||
public Integer getDefaultQueryTimeout() {
|
||||
return defaultQueryTimeoutSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Default query timeout in seconds.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Integer getDefaultQueryTimeoutSeconds() {
|
||||
return defaultQueryTimeoutSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Default read-only-value.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Boolean getDefaultReadOnly() {
|
||||
return defaultReadOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Default schema.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public String getDefaultSchema() {
|
||||
return defaultSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Default transaction isolation.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public int getDefaultTransactionIsolation() {
|
||||
return defaultTransactionIsolation;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL_STATE codes considered to signal fatal conditions.
|
||||
* <p>
|
||||
* Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting with
|
||||
* {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #isFastFailValidation()} is
|
||||
* {@code true}, whenever connections created by this factory generate exceptions with SQL_STATE codes in this list,
|
||||
* they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at isValid or
|
||||
* validation query).
|
||||
* </p>
|
||||
* <p>
|
||||
* If {@link #isFastFailValidation()} is {@code false} setting this property has no effect.
|
||||
* </p>
|
||||
*
|
||||
* @return SQL_STATE codes overriding defaults
|
||||
* @since 2.1
|
||||
*/
|
||||
public Collection<String> getDisconnectionSqlCodes() {
|
||||
return disconnectionSqlCodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maximum connection lifetime in milliseconds.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public long getMaxConnLifetimeMillis() {
|
||||
return maxConnLifetimeMillis;
|
||||
}
|
||||
|
||||
protected int getMaxOpenPreparedStatements() {
|
||||
return maxOpenPreparedStatements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ObjectPool} in which {@link Connection}s are pooled.
|
||||
*
|
||||
* @return the connection pool
|
||||
*/
|
||||
public synchronized ObjectPool<PoolableConnection> getPool() {
|
||||
return pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether to pool statements.
|
||||
* @since Made public in 2.6.0.
|
||||
*/
|
||||
public boolean getPoolStatements() {
|
||||
return poolStatements;
|
||||
}
|
||||
/**
|
||||
* @return Validation query.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public String getValidationQuery() {
|
||||
return validationQuery;
|
||||
}
|
||||
/**
|
||||
* @return Validation query timeout in seconds.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public int getValidationQueryTimeoutSeconds() {
|
||||
return validationQueryTimeoutSeconds;
|
||||
}
|
||||
protected void initializeConnection(final Connection conn) throws SQLException {
|
||||
final Collection<String> sqls = connectionInitSqls;
|
||||
if (conn.isClosed()) {
|
||||
throw new SQLException("initializeConnection: connection closed");
|
||||
}
|
||||
if (null != sqls) {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
for (final String sql : sqls) {
|
||||
Objects.requireNonNull(sql, "null connectionInitSqls element");
|
||||
stmt.execute(sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether to auto-commit on return.
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public boolean isAutoCommitOnReturn() {
|
||||
return autoCommitOnReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether to auto-commit on return.
|
||||
* @deprecated Use {@link #isAutoCommitOnReturn()}.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isEnableAutoCommitOnReturn() {
|
||||
return autoCommitOnReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
|
||||
* SQL_STATE indicating fatal disconnection errors.
|
||||
*
|
||||
* @return true if connections created by this factory will fast fail validation.
|
||||
* @see #setDisconnectionSqlCodes(Collection)
|
||||
* @since 2.1
|
||||
* @since 2.5.0 Defaults to true, previous versions defaulted to false.
|
||||
*/
|
||||
public boolean isFastFailValidation() {
|
||||
return fastFailValidation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether to rollback on return.
|
||||
*/
|
||||
public boolean isRollbackOnReturn() {
|
||||
return rollbackOnReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PooledObject<PoolableConnection> makeObject() throws Exception {
|
||||
Connection conn = connectionFactory.createConnection();
|
||||
if (conn == null) {
|
||||
throw new IllegalStateException("Connection factory returned null from createConnection");
|
||||
}
|
||||
try {
|
||||
initializeConnection(conn);
|
||||
} catch (final SQLException sqle) {
|
||||
// Make sure the connection is closed
|
||||
try {
|
||||
conn.close();
|
||||
} catch (final SQLException ignore) {
|
||||
// ignore
|
||||
}
|
||||
// Rethrow original exception so it is visible to caller
|
||||
throw sqle;
|
||||
}
|
||||
|
||||
final long connIndex = connectionIndex.getAndIncrement();
|
||||
|
||||
if (poolStatements) {
|
||||
conn = new PoolingConnection(conn);
|
||||
final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>();
|
||||
config.setMaxTotalPerKey(-1);
|
||||
config.setBlockWhenExhausted(false);
|
||||
config.setMaxWaitMillis(0);
|
||||
config.setMaxIdlePerKey(1);
|
||||
config.setMaxTotal(maxOpenPreparedStatements);
|
||||
if (dataSourceJmxObjectName != null) {
|
||||
final StringBuilder base = new StringBuilder(dataSourceJmxObjectName.toString());
|
||||
base.append(Constants.JMX_CONNECTION_BASE_EXT);
|
||||
base.append(Long.toString(connIndex));
|
||||
config.setJmxNameBase(base.toString());
|
||||
config.setJmxNamePrefix(Constants.JMX_STATEMENT_POOL_PREFIX);
|
||||
} else {
|
||||
config.setJmxEnabled(false);
|
||||
}
|
||||
final PoolingConnection poolingConn = (PoolingConnection) conn;
|
||||
final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = new GenericKeyedObjectPool<>(
|
||||
poolingConn, config);
|
||||
poolingConn.setStatementPool(stmtPool);
|
||||
poolingConn.setCacheState(cacheState);
|
||||
}
|
||||
|
||||
// Register this connection with JMX
|
||||
ObjectName connJmxName;
|
||||
if (dataSourceJmxObjectName == null) {
|
||||
connJmxName = null;
|
||||
} else {
|
||||
connJmxName = new ObjectName(
|
||||
dataSourceJmxObjectName.toString() + Constants.JMX_CONNECTION_BASE_EXT + connIndex);
|
||||
}
|
||||
|
||||
final PoolableConnection pc = new PoolableConnection(conn, pool, connJmxName, disconnectionSqlCodes,
|
||||
fastFailValidation);
|
||||
pc.setCacheState(cacheState);
|
||||
|
||||
return new DefaultPooledObject<>(pc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(final PooledObject<PoolableConnection> p) throws Exception {
|
||||
|
||||
validateLifetime(p);
|
||||
|
||||
final PoolableConnection conn = p.getObject();
|
||||
Boolean connAutoCommit = null;
|
||||
if (rollbackOnReturn) {
|
||||
connAutoCommit = Boolean.valueOf(conn.getAutoCommit());
|
||||
if (!connAutoCommit.booleanValue() && !conn.isReadOnly()) {
|
||||
conn.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
conn.clearWarnings();
|
||||
|
||||
// DBCP-97 / DBCP-399 / DBCP-351 Idle connections in the pool should
|
||||
// have autoCommit enabled
|
||||
if (autoCommitOnReturn) {
|
||||
if (connAutoCommit == null) {
|
||||
connAutoCommit = Boolean.valueOf(conn.getAutoCommit());
|
||||
}
|
||||
if (!connAutoCommit.booleanValue()) {
|
||||
conn.setAutoCommit(true);
|
||||
}
|
||||
}
|
||||
|
||||
conn.passivate();
|
||||
}
|
||||
|
||||
public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) {
|
||||
this.autoCommitOnReturn = autoCommitOnReturn;
|
||||
}
|
||||
|
||||
public void setCacheState(final boolean cacheState) {
|
||||
this.cacheState = cacheState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SQL statements I use to initialize newly created {@link Connection}s. Using {@code null} turns off
|
||||
* connection initialization.
|
||||
*
|
||||
* @param connectionInitSqls
|
||||
* SQL statement to initialize {@link Connection}s.
|
||||
*/
|
||||
public void setConnectionInitSql(final Collection<String> connectionInitSqls) {
|
||||
this.connectionInitSqls = connectionInitSqls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default "auto commit" setting for borrowed {@link Connection}s
|
||||
*
|
||||
* @param defaultAutoCommit
|
||||
* the default "auto commit" setting for borrowed {@link Connection}s
|
||||
*/
|
||||
public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
|
||||
this.defaultAutoCommit = defaultAutoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default "catalog" setting for borrowed {@link Connection}s
|
||||
*
|
||||
* @param defaultCatalog
|
||||
* the default "catalog" setting for borrowed {@link Connection}s
|
||||
*/
|
||||
public void setDefaultCatalog(final String defaultCatalog) {
|
||||
this.defaultCatalog = defaultCatalog;
|
||||
}
|
||||
|
||||
public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
|
||||
this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
|
||||
}
|
||||
/**
|
||||
* Sets the default "read only" setting for borrowed {@link Connection}s
|
||||
*
|
||||
* @param defaultReadOnly
|
||||
* the default "read only" setting for borrowed {@link Connection}s
|
||||
*/
|
||||
public void setDefaultReadOnly(final Boolean defaultReadOnly) {
|
||||
this.defaultReadOnly = defaultReadOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default "schema" setting for borrowed {@link Connection}s
|
||||
*
|
||||
* @param defaultSchema
|
||||
* the default "schema" setting for borrowed {@link Connection}s
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public void setDefaultSchema(final String defaultSchema) {
|
||||
this.defaultSchema = defaultSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s
|
||||
*
|
||||
* @param defaultTransactionIsolation
|
||||
* the default "Transaction Isolation" setting for returned {@link Connection}s
|
||||
*/
|
||||
public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
|
||||
this.defaultTransactionIsolation = defaultTransactionIsolation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param disconnectionSqlCodes
|
||||
* The disconnection SQL codes.
|
||||
* @see #getDisconnectionSqlCodes()
|
||||
* @since 2.1
|
||||
*/
|
||||
public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
|
||||
this.disconnectionSqlCodes = disconnectionSqlCodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param autoCommitOnReturn Whether to auto-commit on return.
|
||||
* @deprecated Use {@link #setAutoCommitOnReturn(boolean)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setEnableAutoCommitOnReturn(final boolean autoCommitOnReturn) {
|
||||
this.autoCommitOnReturn = autoCommitOnReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #isFastFailValidation()
|
||||
* @param fastFailValidation
|
||||
* true means connections created by this factory will fast fail validation
|
||||
* @since 2.1
|
||||
*/
|
||||
public void setFastFailValidation(final boolean fastFailValidation) {
|
||||
this.fastFailValidation = fastFailValidation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
|
||||
* passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1.
|
||||
*
|
||||
* @param maxConnLifetimeMillis
|
||||
* The maximum lifetime in milliseconds.
|
||||
*/
|
||||
public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
|
||||
this.maxConnLifetimeMillis = maxConnLifetimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of open prepared statements.
|
||||
*
|
||||
* @param maxOpenPreparedStatements
|
||||
* The maximum number of open prepared statements.
|
||||
*/
|
||||
public void setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) {
|
||||
this.maxOpenPreparedStatements = maxOpenPreparedStatements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated due to typo in method name.
|
||||
*
|
||||
* @param maxOpenPreparedStatements
|
||||
* The maximum number of open prepared statements.
|
||||
* @deprecated Use {@link #setMaxOpenPreparedStatements(int)}.
|
||||
*/
|
||||
@Deprecated // Due to typo in method name.
|
||||
public void setMaxOpenPrepatedStatements(final int maxOpenPreparedStatements) {
|
||||
setMaxOpenPreparedStatements(maxOpenPreparedStatements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ObjectPool} in which to pool {@link Connection}s.
|
||||
*
|
||||
* @param pool
|
||||
* the {@link ObjectPool} in which to pool those {@link Connection}s
|
||||
*/
|
||||
public synchronized void setPool(final ObjectPool<PoolableConnection> pool) {
|
||||
if (null != this.pool && pool != this.pool) {
|
||||
try {
|
||||
this.pool.close();
|
||||
} catch (final Exception e) {
|
||||
// ignored !?!
|
||||
}
|
||||
}
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
public void setPoolStatements(final boolean poolStatements) {
|
||||
this.poolStatements = poolStatements;
|
||||
}
|
||||
|
||||
public void setRollbackOnReturn(final boolean rollbackOnReturn) {
|
||||
this.rollbackOnReturn = rollbackOnReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query I use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. If
|
||||
* not specified, {@link Connection#isValid(int)} will be used to validate connections.
|
||||
*
|
||||
* @param validationQuery
|
||||
* a query to use to {@link #validateObject validate} {@link Connection}s.
|
||||
*/
|
||||
public void setValidationQuery(final String validationQuery) {
|
||||
this.validationQuery = validationQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
|
||||
* response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
|
||||
*
|
||||
* @param validationQueryTimeoutSeconds
|
||||
* new validation query timeout value in seconds
|
||||
*/
|
||||
public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
|
||||
this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
|
||||
}
|
||||
|
||||
public void validateConnection(final PoolableConnection conn) throws SQLException {
|
||||
if (conn.isClosed()) {
|
||||
throw new SQLException("validateConnection: connection closed");
|
||||
}
|
||||
conn.validate(validationQuery, validationQueryTimeoutSeconds);
|
||||
}
|
||||
|
||||
private void validateLifetime(final PooledObject<PoolableConnection> p) throws Exception {
|
||||
if (maxConnLifetimeMillis > 0) {
|
||||
final long lifetime = System.currentTimeMillis() - p.getCreateTime();
|
||||
if (lifetime > maxConnLifetimeMillis) {
|
||||
throw new LifetimeExceededException(Utils.getMessage("connectionFactory.lifetimeExceeded",
|
||||
Long.valueOf(lifetime), Long.valueOf(maxConnLifetimeMillis)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(final PooledObject<PoolableConnection> p) {
|
||||
try {
|
||||
validateLifetime(p);
|
||||
|
||||
validateConnection(p.getObject());
|
||||
return true;
|
||||
} catch (final Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(Utils.getMessage("poolableConnectionFactory.validateObject.fail"), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Defines the attributes and methods that will be exposed via JMX for {@link PoolableConnection} instances.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface PoolableConnectionMXBean {
|
||||
// Read-only properties
|
||||
boolean isClosed() throws SQLException;
|
||||
|
||||
// SQLWarning getWarnings() throws SQLException;
|
||||
String getToString();
|
||||
|
||||
// Read-write properties
|
||||
boolean getAutoCommit() throws SQLException;
|
||||
|
||||
void setAutoCommit(boolean autoCommit) throws SQLException;
|
||||
|
||||
boolean getCacheState();
|
||||
|
||||
void setCacheState(boolean cacheState);
|
||||
|
||||
String getCatalog() throws SQLException;
|
||||
|
||||
void setCatalog(String catalog) throws SQLException;
|
||||
|
||||
int getHoldability() throws SQLException;
|
||||
|
||||
void setHoldability(int holdability) throws SQLException;
|
||||
|
||||
boolean isReadOnly() throws SQLException;
|
||||
|
||||
void setReadOnly(boolean readOnly) throws SQLException;
|
||||
|
||||
String getSchema() throws SQLException;
|
||||
|
||||
void setSchema(String schema) throws SQLException;
|
||||
|
||||
int getTransactionIsolation() throws SQLException;
|
||||
|
||||
void setTransactionIsolation(int level) throws SQLException;
|
||||
|
||||
// Methods
|
||||
void clearCachedState();
|
||||
|
||||
void clearWarnings() throws SQLException;
|
||||
|
||||
void close() throws SQLException;
|
||||
|
||||
void reallyClose() throws SQLException;
|
||||
}
|
||||
159
java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
Normal file
159
java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
|
||||
|
||||
/**
|
||||
* A {@link DelegatingPreparedStatement} that cooperates with {@link PoolingConnection} to implement a pool of
|
||||
* {@link PreparedStatement}s.
|
||||
* <p>
|
||||
* My {@link #close} method returns me to my containing pool. (See {@link PoolingConnection}.)
|
||||
* </p>
|
||||
*
|
||||
* @param <K>
|
||||
* the key type
|
||||
*
|
||||
* @see PoolingConnection
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement {
|
||||
|
||||
/**
|
||||
* The {@link KeyedObjectPool} from which I was obtained.
|
||||
*/
|
||||
private final KeyedObjectPool<K, PoolablePreparedStatement<K>> pool;
|
||||
|
||||
/**
|
||||
* My "key" as used by {@link KeyedObjectPool}.
|
||||
*/
|
||||
private final K key;
|
||||
|
||||
private volatile boolean batchAdded = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stmt
|
||||
* my underlying {@link PreparedStatement}
|
||||
* @param key
|
||||
* my key" as used by {@link KeyedObjectPool}
|
||||
* @param pool
|
||||
* the {@link KeyedObjectPool} from which I was obtained.
|
||||
* @param conn
|
||||
* the {@link java.sql.Connection Connection} from which I was created
|
||||
*/
|
||||
public PoolablePreparedStatement(final PreparedStatement stmt, final K key,
|
||||
final KeyedObjectPool<K, PoolablePreparedStatement<K>> pool, final DelegatingConnection<?> conn) {
|
||||
super(conn, stmt);
|
||||
this.pool = pool;
|
||||
this.key = key;
|
||||
|
||||
// Remove from trace now because this statement will be
|
||||
// added by the activate method.
|
||||
removeThisTrace(getConnectionInternal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add batch.
|
||||
*/
|
||||
@Override
|
||||
public void addBatch() throws SQLException {
|
||||
super.addBatch();
|
||||
batchAdded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Batch.
|
||||
*/
|
||||
@Override
|
||||
public void clearBatch() throws SQLException {
|
||||
batchAdded = false;
|
||||
super.clearBatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return me to my pool.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
// calling close twice should have no effect
|
||||
if (!isClosed()) {
|
||||
try {
|
||||
pool.returnObject(key, this);
|
||||
} catch (final SQLException e) {
|
||||
throw e;
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Cannot close preparedstatement (return to pool failed)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() throws SQLException {
|
||||
setClosedInternal(false);
|
||||
if (getConnectionInternal() != null) {
|
||||
getConnectionInternal().addTrace(this);
|
||||
}
|
||||
super.activate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivate() throws SQLException {
|
||||
// DBCP-372. clearBatch with throw an exception if called when the
|
||||
// connection is marked as closed.
|
||||
if (batchAdded) {
|
||||
clearBatch();
|
||||
}
|
||||
setClosedInternal(true);
|
||||
removeThisTrace(getConnectionInternal());
|
||||
|
||||
// The JDBC spec requires that a statement closes any open
|
||||
// ResultSet's when it is closed.
|
||||
// FIXME The PreparedStatement we're wrapping should handle this for us.
|
||||
// See bug 17301 for what could happen when ResultSets are closed twice.
|
||||
final List<AbandonedTrace> resultSetList = getTrace();
|
||||
if (resultSetList != null) {
|
||||
final List<Exception> thrownList = new ArrayList<>();
|
||||
final ResultSet[] resultSets = resultSetList.toArray(new ResultSet[resultSetList.size()]);
|
||||
for (final ResultSet resultSet : resultSets) {
|
||||
if (resultSet != null) {
|
||||
try {
|
||||
resultSet.close();
|
||||
} catch (Exception e) {
|
||||
thrownList.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
clearTrace();
|
||||
if (!thrownList.isEmpty()) {
|
||||
throw new SQLExceptionList(thrownList);
|
||||
}
|
||||
}
|
||||
|
||||
super.passivate();
|
||||
}
|
||||
}
|
||||
602
java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
Normal file
602
java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* A {@link DelegatingConnection} that pools {@link PreparedStatement}s.
|
||||
* <p>
|
||||
* The {@link #prepareStatement} and {@link #prepareCall} methods, rather than creating a new PreparedStatement each
|
||||
* time, may actually pull the statement from a pool of unused statements. The {@link PreparedStatement#close} method of
|
||||
* the returned statement doesn't actually close the statement, but rather returns it to the pool. (See
|
||||
* {@link PoolablePreparedStatement}, {@link PoolableCallableStatement}.)
|
||||
* </p>
|
||||
*
|
||||
* @see PoolablePreparedStatement
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PoolingConnection extends DelegatingConnection<Connection>
|
||||
implements KeyedPooledObjectFactory<PStmtKey, DelegatingPreparedStatement> {
|
||||
|
||||
/**
|
||||
* Statement types.
|
||||
*
|
||||
* @since 2.0 protected enum.
|
||||
* @since 2.4.0 public enum.
|
||||
*/
|
||||
public enum StatementType {
|
||||
|
||||
/**
|
||||
* Callable statement.
|
||||
*/
|
||||
CALLABLE_STATEMENT,
|
||||
|
||||
/**
|
||||
* Prepared statement.
|
||||
*/
|
||||
PREPARED_STATEMENT
|
||||
}
|
||||
|
||||
/** Pool of {@link PreparedStatement}s. and {@link CallableStatement}s */
|
||||
private KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pstmtPool;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param connection
|
||||
* the underlying {@link Connection}.
|
||||
*/
|
||||
public PoolingConnection(final Connection connection) {
|
||||
super(connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link KeyedPooledObjectFactory} method for activating pooled statements.
|
||||
*
|
||||
* @param key
|
||||
* ignored
|
||||
* @param pooledObject
|
||||
* wrapped pooled statement to be activated
|
||||
*/
|
||||
@Override
|
||||
public void activateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
|
||||
throws Exception {
|
||||
pooledObject.getObject().activate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes and frees all {@link PreparedStatement}s or {@link CallableStatement}s from the pool, and close the
|
||||
* underlying connection.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void close() throws SQLException {
|
||||
try {
|
||||
if (null != pstmtPool) {
|
||||
final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> oldpool = pstmtPool;
|
||||
pstmtPool = null;
|
||||
try {
|
||||
oldpool.close();
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Cannot close connection", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
getDelegateInternal().close();
|
||||
} finally {
|
||||
setClosedInternal(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PStmtKey for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the statement
|
||||
*
|
||||
* @return the PStmtKey created for the given arguments.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PStmtKey for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the statement
|
||||
* @param columnIndexes
|
||||
* column indexes
|
||||
*
|
||||
* @return the PStmtKey created for the given arguments.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final int columnIndexes[]) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnIndexes);
|
||||
}
|
||||
|
||||
protected PStmtKey createKey(final String sql, final int autoGeneratedKeys) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), autoGeneratedKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PStmtKey for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the statement
|
||||
* @param resultSetType
|
||||
* result set type
|
||||
* @param resultSetConcurrency
|
||||
* result set concurrency
|
||||
*
|
||||
* @return the PStmtKey created for the given arguments.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PStmtKey for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the statement
|
||||
* @param resultSetType
|
||||
* result set type
|
||||
* @param resultSetConcurrency
|
||||
* result set concurrency
|
||||
* @param resultSetHoldability
|
||||
* result set holdability
|
||||
*
|
||||
* @return the PStmtKey created 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(), getSchemaOrNull(), resultSetType, resultSetConcurrency,
|
||||
resultSetHoldability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PStmtKey for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the statement
|
||||
* @param resultSetType
|
||||
* result set type
|
||||
* @param resultSetConcurrency
|
||||
* result set concurrency
|
||||
* @param resultSetHoldability
|
||||
* result set holdability
|
||||
* @param statementType
|
||||
* statement type
|
||||
*
|
||||
* @return the PStmtKey created for the given arguments.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability, final StatementType statementType) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency,
|
||||
resultSetHoldability, statementType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PStmtKey for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the statement
|
||||
* @param resultSetType
|
||||
* result set type
|
||||
* @param resultSetConcurrency
|
||||
* result set concurrency
|
||||
* @param statementType
|
||||
* statement type
|
||||
*
|
||||
* @return the PStmtKey created for the given arguments.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
|
||||
final StatementType statementType) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType, resultSetConcurrency, statementType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PStmtKey for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the statement
|
||||
* @param statementType
|
||||
* statement type
|
||||
*
|
||||
* @return the PStmtKey created for the given arguments.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final StatementType statementType) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), statementType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PStmtKey for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the statement
|
||||
* @param columnNames
|
||||
* column names
|
||||
*
|
||||
* @return the PStmtKey created for the given arguments.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final String columnNames[]) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link KeyedPooledObjectFactory} method for destroying PoolablePreparedStatements and PoolableCallableStatements.
|
||||
* Closes the underlying statement.
|
||||
*
|
||||
* @param key
|
||||
* ignored
|
||||
* @param pooledObject
|
||||
* the wrapped pooled statement to be destroyed.
|
||||
*/
|
||||
@Override
|
||||
public void destroyObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
|
||||
throws Exception {
|
||||
pooledObject.getObject().getInnermostDelegate().close();
|
||||
}
|
||||
|
||||
private String getCatalogOrNull() {
|
||||
String catalog = null;
|
||||
try {
|
||||
catalog = getCatalog();
|
||||
} catch (final SQLException e) {
|
||||
// Ignored
|
||||
}
|
||||
return catalog;
|
||||
}
|
||||
|
||||
private String getSchemaOrNull() {
|
||||
String catalog = null;
|
||||
try {
|
||||
catalog = getSchema();
|
||||
} catch (final SQLException e) {
|
||||
// Ignored
|
||||
}
|
||||
return catalog;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link KeyedPooledObjectFactory} method for creating {@link PoolablePreparedStatement}s or
|
||||
* {@link PoolableCallableStatement}s. The <code>stmtType</code> field in the key determines whether a
|
||||
* PoolablePreparedStatement or PoolableCallableStatement is created.
|
||||
*
|
||||
* @param key
|
||||
* the key for the {@link PreparedStatement} to be created
|
||||
* @see #createKey(String, int, int, StatementType)
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
@Override
|
||||
public PooledObject<DelegatingPreparedStatement> makeObject(final PStmtKey key) throws Exception {
|
||||
if (null == key) {
|
||||
throw new IllegalArgumentException("Prepared statement key is null or invalid.");
|
||||
}
|
||||
if (key.getStmtType() == StatementType.PREPARED_STATEMENT) {
|
||||
final PreparedStatement statement = (PreparedStatement) key.createStatement(getDelegate());
|
||||
@SuppressWarnings({"rawtypes", "unchecked" }) // Unable to find way to avoid this
|
||||
final PoolablePreparedStatement pps = new PoolablePreparedStatement(statement, key, pstmtPool, this);
|
||||
return new DefaultPooledObject<DelegatingPreparedStatement>(pps);
|
||||
}
|
||||
final CallableStatement statement = (CallableStatement) key.createStatement(getDelegate());
|
||||
final PoolableCallableStatement pcs = new PoolableCallableStatement(statement, key, pstmtPool, this);
|
||||
return new DefaultPooledObject<DelegatingPreparedStatement>(pcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the given SQL statement, producing a canonical form that is semantically equivalent to the original.
|
||||
*
|
||||
* @param sql The statement to be normalized.
|
||||
*
|
||||
* @return The canonical form of the supplied SQL statement.
|
||||
*/
|
||||
protected String normalizeSQL(final String sql) {
|
||||
return sql.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link KeyedPooledObjectFactory} method for passivating {@link PreparedStatement}s or {@link CallableStatement}s.
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or obtains a {@link CallableStatement} from the pool.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the CallableStatement
|
||||
* @return a {@link PoolableCallableStatement}
|
||||
* @throws SQLException
|
||||
* Wraps an underlying exception.
|
||||
*/
|
||||
@Override
|
||||
public CallableStatement prepareCall(final String sql) throws SQLException {
|
||||
try {
|
||||
return (CallableStatement) pstmtPool.borrowObject(createKey(sql, StatementType.CALLABLE_STATEMENT));
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("MaxOpenCallableStatements limit reached", e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow callableStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or obtains a {@link CallableStatement} from the pool.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the CallableStatement
|
||||
* @param resultSetType
|
||||
* result set type
|
||||
* @param resultSetConcurrency
|
||||
* result set concurrency
|
||||
* @return a {@link PoolableCallableStatement}
|
||||
* @throws SQLException
|
||||
* Wraps an underlying exception.
|
||||
*/
|
||||
@Override
|
||||
public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
try {
|
||||
return (CallableStatement) pstmtPool.borrowObject(
|
||||
createKey(sql, resultSetType, resultSetConcurrency, StatementType.CALLABLE_STATEMENT));
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("MaxOpenCallableStatements limit reached", e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow callableStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or obtains a {@link CallableStatement} from the pool.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the CallableStatement
|
||||
* @param resultSetType
|
||||
* result set type
|
||||
* @param resultSetConcurrency
|
||||
* result set concurrency
|
||||
* @param resultSetHoldability
|
||||
* result set holdability
|
||||
* @return a {@link PoolableCallableStatement}
|
||||
* @throws SQLException
|
||||
* Wraps an underlying exception.
|
||||
*/
|
||||
@Override
|
||||
public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability) throws SQLException {
|
||||
try {
|
||||
return (CallableStatement) pstmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency,
|
||||
resultSetHoldability, StatementType.CALLABLE_STATEMENT));
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("MaxOpenCallableStatements limit reached", e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow callableStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or obtains a {@link PreparedStatement} from the pool.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the PreparedStatement
|
||||
* @return a {@link PoolablePreparedStatement}
|
||||
*/
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql) throws SQLException {
|
||||
if (null == pstmtPool) {
|
||||
throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
|
||||
}
|
||||
try {
|
||||
return pstmtPool.borrowObject(createKey(sql));
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("MaxOpenPreparedStatements limit reached", e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
|
||||
if (null == pstmtPool) {
|
||||
throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
|
||||
}
|
||||
try {
|
||||
return pstmtPool.borrowObject(createKey(sql, autoGeneratedKeys));
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("MaxOpenPreparedStatements limit reached", e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or obtains a {@link PreparedStatement} from the pool.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the PreparedStatement
|
||||
* @param columnIndexes
|
||||
* column indexes
|
||||
* @return a {@link PoolablePreparedStatement}
|
||||
*/
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException {
|
||||
if (null == pstmtPool) {
|
||||
throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
|
||||
}
|
||||
try {
|
||||
return pstmtPool.borrowObject(createKey(sql, columnIndexes));
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("MaxOpenPreparedStatements limit reached", e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or obtains a {@link PreparedStatement} from the pool.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the PreparedStatement
|
||||
* @param resultSetType
|
||||
* result set type
|
||||
* @param resultSetConcurrency
|
||||
* result set concurrency
|
||||
* @return a {@link PoolablePreparedStatement}
|
||||
*/
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
if (null == pstmtPool) {
|
||||
throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
|
||||
}
|
||||
try {
|
||||
return pstmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency));
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("MaxOpenPreparedStatements limit reached", e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or obtains a {@link PreparedStatement} from the pool.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the PreparedStatement
|
||||
* @param resultSetType
|
||||
* result set type
|
||||
* @param resultSetConcurrency
|
||||
* result set concurrency
|
||||
* @param resultSetHoldability
|
||||
* result set holdability
|
||||
* @return a {@link PoolablePreparedStatement}
|
||||
*/
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability) throws SQLException {
|
||||
if (null == pstmtPool) {
|
||||
throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
|
||||
}
|
||||
try {
|
||||
return pstmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("MaxOpenPreparedStatements limit reached", e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or obtains a {@link PreparedStatement} from the pool.
|
||||
*
|
||||
* @param sql
|
||||
* the SQL string used to define the PreparedStatement
|
||||
* @param columnNames
|
||||
* column names
|
||||
* @return a {@link PoolablePreparedStatement}
|
||||
*/
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException {
|
||||
if (null == pstmtPool) {
|
||||
throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
|
||||
}
|
||||
try {
|
||||
return pstmtPool.borrowObject(createKey(sql, columnNames));
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("MaxOpenPreparedStatements limit reached", e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prepared statement pool.
|
||||
*
|
||||
* @param pool
|
||||
* the prepared statement pool.
|
||||
*/
|
||||
public void setStatementPool(final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pool) {
|
||||
pstmtPool = pool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
if (pstmtPool != null) {
|
||||
return "PoolingConnection: " + pstmtPool.toString();
|
||||
}
|
||||
return "PoolingConnection: null";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link KeyedPooledObjectFactory} method for validating pooled statements. Currently always returns true.
|
||||
*
|
||||
* @param key
|
||||
* ignored
|
||||
* @param pooledObject
|
||||
* ignored
|
||||
* @return {@code true}
|
||||
*/
|
||||
@Override
|
||||
public boolean validateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
257
java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
Normal file
257
java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.dbcp.pool2.ObjectPool;
|
||||
import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool;
|
||||
|
||||
/**
|
||||
* A simple {@link DataSource} implementation that obtains {@link Connection}s from the specified {@link ObjectPool}.
|
||||
*
|
||||
* @param <C>
|
||||
* The connection type
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PoolingDataSource<C extends Connection> implements DataSource, AutoCloseable {
|
||||
|
||||
private static final Log log = LogFactory.getLog(PoolingDataSource.class);
|
||||
|
||||
/** Controls access to the underlying connection */
|
||||
private boolean accessToUnderlyingConnectionAllowed;
|
||||
|
||||
/**
|
||||
* Constructs a new instance backed by the given connection pool.
|
||||
*
|
||||
* @param pool
|
||||
* the given connection pool.
|
||||
*/
|
||||
public PoolingDataSource(final ObjectPool<C> pool) {
|
||||
Objects.requireNonNull(pool, "Pool must not be null.");
|
||||
this.pool = pool;
|
||||
// Verify that pool's factory refers back to it. If not, log a warning and try to fix.
|
||||
if (this.pool instanceof GenericObjectPool<?>) {
|
||||
final PoolableConnectionFactory pcf = (PoolableConnectionFactory) ((GenericObjectPool<?>) this.pool)
|
||||
.getFactory();
|
||||
Objects.requireNonNull(pcf, "PoolableConnectionFactory must not be null.");
|
||||
if (pcf.getPool() != this.pool) {
|
||||
log.warn(Utils.getMessage("poolingDataSource.factoryConfig"));
|
||||
@SuppressWarnings("unchecked") // PCF must have a pool of PCs
|
||||
final ObjectPool<PoolableConnection> p = (ObjectPool<PoolableConnection>) this.pool;
|
||||
pcf.setPool(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes and free all {@link Connection}s from the pool.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
@Override
|
||||
public void close() throws RuntimeException, SQLException {
|
||||
try {
|
||||
pool.close();
|
||||
} catch (final RuntimeException rte) {
|
||||
throw new RuntimeException(Utils.getMessage("pool.close.fail"), rte);
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException(Utils.getMessage("pool.close.fail"), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the accessToUnderlyingConnectionAllowed property.
|
||||
*
|
||||
* @return true if access to the underlying {@link Connection} is allowed, false otherwise.
|
||||
*/
|
||||
public 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)
|
||||
*
|
||||
* @param allow
|
||||
* Access to the underlying connection is granted when true.
|
||||
*/
|
||||
public void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
|
||||
this.accessToUnderlyingConnectionAllowed = allow;
|
||||
}
|
||||
|
||||
/* JDBC_4_ANT_KEY_BEGIN */
|
||||
@Override
|
||||
public boolean isWrapperFor(final Class<?> iface) throws SQLException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(final Class<T> iface) throws SQLException {
|
||||
throw new SQLException("PoolingDataSource is not a wrapper.");
|
||||
}
|
||||
/* JDBC_4_ANT_KEY_END */
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
throw new SQLFeatureNotSupportedException();
|
||||
}
|
||||
|
||||
// --- DataSource methods -----------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a {@link java.sql.Connection} from my pool, according to the contract specified by
|
||||
* {@link ObjectPool#borrowObject}.
|
||||
*/
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
try {
|
||||
final C conn = pool.borrowObject();
|
||||
if (conn == null) {
|
||||
return null;
|
||||
}
|
||||
return new PoolGuardConnectionWrapper<>(conn);
|
||||
} catch (final SQLException e) {
|
||||
throw e;
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("Cannot get a connection, pool error " + e.getMessage(), e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final InterruptedException e) {
|
||||
// Reset the interrupt status so it is visible to callers
|
||||
Thread.currentThread().interrupt();
|
||||
throw new SQLException("Cannot get a connection, general error", e);
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Cannot get a connection, general error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws {@link UnsupportedOperationException}
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* always thrown
|
||||
*/
|
||||
@Override
|
||||
public Connection getConnection(final String uname, final String passwd) throws SQLException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns my log writer.
|
||||
*
|
||||
* @return my log writer
|
||||
* @see DataSource#getLogWriter
|
||||
*/
|
||||
@Override
|
||||
public PrintWriter getLogWriter() {
|
||||
return logWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* As this implementation does not support this feature.
|
||||
*/
|
||||
@Override
|
||||
public int getLoginTimeout() {
|
||||
throw new UnsupportedOperationException("Login timeout is not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* As this implementation does not support this feature.
|
||||
*/
|
||||
@Override
|
||||
public void setLoginTimeout(final int seconds) {
|
||||
throw new UnsupportedOperationException("Login timeout is not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets my log writer.
|
||||
*
|
||||
* @see DataSource#setLogWriter
|
||||
*/
|
||||
@Override
|
||||
public void setLogWriter(final PrintWriter out) {
|
||||
logWriter = out;
|
||||
}
|
||||
|
||||
/** My log writer. */
|
||||
private PrintWriter logWriter = null;
|
||||
|
||||
private final ObjectPool<C> pool;
|
||||
|
||||
protected ObjectPool<C> getPool() {
|
||||
return pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
private class PoolGuardConnectionWrapper<D extends Connection> extends DelegatingConnection<D> {
|
||||
|
||||
PoolGuardConnectionWrapper(final D delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getDelegate()
|
||||
*/
|
||||
@Override
|
||||
public D getDelegate() {
|
||||
return isAccessToUnderlyingConnectionAllowed() ? super.getDelegate() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getInnermostDelegate()
|
||||
*/
|
||||
@Override
|
||||
public Connection getInnermostDelegate() {
|
||||
return isAccessToUnderlyingConnectionAllowed() ? super.getInnermostDelegate() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
if (getDelegateInternal() != null) {
|
||||
super.close();
|
||||
super.setDelegate(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() throws SQLException {
|
||||
return getDelegateInternal() == null ? true : super.isClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
263
java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
Normal file
263
java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.DriverPropertyInfo;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.HashMap;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.ObjectPool;
|
||||
|
||||
/**
|
||||
* A {@link Driver} implementation that obtains {@link Connection}s from a registered {@link ObjectPool}.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PoolingDriver implements Driver {
|
||||
|
||||
/** Register myself with the {@link DriverManager}. */
|
||||
static {
|
||||
try {
|
||||
DriverManager.registerDriver(new PoolingDriver());
|
||||
} catch (final Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/** The map of registered pools. */
|
||||
protected static final HashMap<String, ObjectPool<? extends Connection>> pools = new HashMap<>();
|
||||
|
||||
/** Controls access to the underlying connection */
|
||||
private final boolean accessToUnderlyingConnectionAllowed;
|
||||
|
||||
/**
|
||||
* Constructs a new driver with <code>accessToUnderlyingConnectionAllowed</code> enabled.
|
||||
*/
|
||||
public PoolingDriver() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* For unit testing purposes.
|
||||
*
|
||||
* @param accessToUnderlyingConnectionAllowed
|
||||
* Do {@link DelegatingConnection}s created by this driver permit access to the delegate?
|
||||
*/
|
||||
protected PoolingDriver(final boolean accessToUnderlyingConnectionAllowed) {
|
||||
this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the accessToUnderlyingConnectionAllowed property.
|
||||
*
|
||||
* @return true if access to the underlying is allowed, false otherwise.
|
||||
*/
|
||||
protected boolean isAccessToUnderlyingConnectionAllowed() {
|
||||
return accessToUnderlyingConnectionAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the connection pool for the given name.
|
||||
*
|
||||
* @param name
|
||||
* The pool name
|
||||
* @return The pool
|
||||
* @throws SQLException
|
||||
* Thrown when the named pool is not registered.
|
||||
*/
|
||||
public synchronized ObjectPool<? extends Connection> getConnectionPool(final String name) throws SQLException {
|
||||
final ObjectPool<? extends Connection> pool = pools.get(name);
|
||||
if (null == pool) {
|
||||
throw new SQLException("Pool not registered: " + name);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a named pool.
|
||||
*
|
||||
* @param name
|
||||
* The pool name.
|
||||
* @param pool
|
||||
* The pool.
|
||||
*/
|
||||
public synchronized void registerPool(final String name, final ObjectPool<? extends Connection> pool) {
|
||||
pools.put(name, pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a named pool.
|
||||
*
|
||||
* @param name
|
||||
* The pool name.
|
||||
* @throws SQLException
|
||||
* Thrown when a problem is caught closing the pool.
|
||||
*/
|
||||
public synchronized void closePool(final String name) throws SQLException {
|
||||
@SuppressWarnings("resource")
|
||||
final ObjectPool<? extends Connection> pool = pools.get(name);
|
||||
if (pool != null) {
|
||||
pools.remove(name);
|
||||
try {
|
||||
pool.close();
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Error closing pool " + name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pool names.
|
||||
*
|
||||
* @return the pool names.
|
||||
*/
|
||||
public synchronized String[] getPoolNames() {
|
||||
final Set<String> names = pools.keySet();
|
||||
return names.toArray(new String[names.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsURL(final String url) throws SQLException {
|
||||
return url == null ? false : url.startsWith(URL_PREFIX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection connect(final String url, final Properties info) throws SQLException {
|
||||
if (acceptsURL(url)) {
|
||||
final ObjectPool<? extends Connection> pool = getConnectionPool(url.substring(URL_PREFIX_LEN));
|
||||
|
||||
try {
|
||||
final Connection conn = pool.borrowObject();
|
||||
if (conn == null) {
|
||||
return null;
|
||||
}
|
||||
return new PoolGuardConnectionWrapper(pool, conn);
|
||||
} catch (final SQLException e) {
|
||||
throw e;
|
||||
} catch (final NoSuchElementException e) {
|
||||
throw new SQLException("Cannot get a connection, pool error: " + e.getMessage(), e);
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Cannot get a connection, general error: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
throw new SQLFeatureNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the given connection.
|
||||
*
|
||||
* @param conn
|
||||
* connection to invalidate
|
||||
* @throws SQLException
|
||||
* if the connection is not a <code>PoolGuardConnectionWrapper</code> or an error occurs invalidating
|
||||
* the connection
|
||||
*/
|
||||
public void invalidateConnection(final Connection conn) throws SQLException {
|
||||
if (conn instanceof PoolGuardConnectionWrapper) { // normal case
|
||||
final PoolGuardConnectionWrapper pgconn = (PoolGuardConnectionWrapper) conn;
|
||||
@SuppressWarnings("unchecked")
|
||||
final ObjectPool<Connection> pool = (ObjectPool<Connection>) pgconn.pool;
|
||||
try {
|
||||
pool.invalidateObject(pgconn.getDelegateInternal());
|
||||
} catch (final Exception e) {
|
||||
// Ignore.
|
||||
}
|
||||
} else {
|
||||
throw new SQLException("Invalid connection class");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMajorVersion() {
|
||||
return MAJOR_VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinorVersion() {
|
||||
return MINOR_VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean jdbcCompliant() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) {
|
||||
return new DriverPropertyInfo[0];
|
||||
}
|
||||
|
||||
/** My URL prefix */
|
||||
public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
|
||||
protected static final int URL_PREFIX_LEN = URL_PREFIX.length();
|
||||
|
||||
// version numbers
|
||||
protected static final int MAJOR_VERSION = 1;
|
||||
protected static final int MINOR_VERSION = 0;
|
||||
|
||||
/**
|
||||
* PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
private class PoolGuardConnectionWrapper extends DelegatingConnection<Connection> {
|
||||
|
||||
private final ObjectPool<? extends Connection> pool;
|
||||
|
||||
PoolGuardConnectionWrapper(final ObjectPool<? extends Connection> pool, final Connection delegate) {
|
||||
super(delegate);
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getDelegate()
|
||||
*/
|
||||
@Override
|
||||
public Connection getDelegate() {
|
||||
if (isAccessToUnderlyingConnectionAllowed()) {
|
||||
return super.getDelegate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getInnermostDelegate()
|
||||
*/
|
||||
@Override
|
||||
public Connection getInnermostDelegate() {
|
||||
if (isAccessToUnderlyingConnectionAllowed()) {
|
||||
return super.getInnermostDelegate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
java/org/apache/tomcat/dbcp/dbcp2/SQLExceptionList.java
Normal file
57
java/org/apache/tomcat/dbcp/dbcp2/SQLExceptionList.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An SQLException based on a list of Throwable causes.
|
||||
* <p>
|
||||
* The first exception in the list is used as this exception's cause and is accessible with the usual
|
||||
* {@link #getCause()} while the complete list is accessible with {@link #getCauseList()}.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public class SQLExceptionList extends SQLException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final List<? extends Throwable> causeList;
|
||||
|
||||
/**
|
||||
* Creates a new exception caused by a list of exceptions.
|
||||
*
|
||||
* @param causeList a list of cause exceptions.
|
||||
*/
|
||||
public SQLExceptionList(List<? extends Throwable> causeList) {
|
||||
super(String.format("%,d exceptions: %s", Integer.valueOf(causeList == null ? 0 : causeList.size()), causeList),
|
||||
causeList == null ? null : causeList.get(0));
|
||||
this.causeList = causeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cause list.
|
||||
*
|
||||
* @return The list of causes.
|
||||
*/
|
||||
public List<? extends Throwable> getCauseList() {
|
||||
return causeList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.tomcat.dbcp.pool2.SwallowedExceptionListener;
|
||||
|
||||
/**
|
||||
* Class for logging swallowed exceptions.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SwallowedExceptionLogger implements SwallowedExceptionListener {
|
||||
|
||||
private final Log log;
|
||||
private final boolean logExpiredConnections;
|
||||
|
||||
/**
|
||||
* Create a SwallowedExceptionLogger with the given logger. By default, expired connection logging is turned on.
|
||||
*
|
||||
* @param log
|
||||
* logger
|
||||
*/
|
||||
public SwallowedExceptionLogger(final Log log) {
|
||||
this(log, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SwallowedExceptionLogger with the given logger and expired connection logging property.
|
||||
*
|
||||
* @param log
|
||||
* logger
|
||||
* @param logExpiredConnections
|
||||
* false suppresses logging of expired connection events
|
||||
*/
|
||||
public SwallowedExceptionLogger(final Log log, final boolean logExpiredConnections) {
|
||||
this.log = log;
|
||||
this.logExpiredConnections = logExpiredConnections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwallowException(final Exception e) {
|
||||
if (logExpiredConnections || !(e instanceof LifetimeExceededException)) {
|
||||
log.warn(Utils.getMessage("swallowedExceptionLogger.onSwallowedException"), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
150
java/org/apache/tomcat/dbcp/dbcp2/Utils.java
Normal file
150
java/org/apache/tomcat/dbcp/dbcp2/Utils.java
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility methods.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public final class Utils {
|
||||
|
||||
private static final ResourceBundle messages = ResourceBundle
|
||||
.getBundle(Utils.class.getPackage().getName() + ".LocalStrings");
|
||||
|
||||
/**
|
||||
* Whether the security manager is enabled.
|
||||
*/
|
||||
public static final boolean IS_SECURITY_ENABLED = System.getSecurityManager() != null;
|
||||
|
||||
/** Any SQL_STATE starting with this value is considered a fatal disconnect */
|
||||
public static final String DISCONNECTION_SQL_CODE_PREFIX = "08";
|
||||
|
||||
/**
|
||||
* SQL codes of fatal connection errors.
|
||||
* <ul>
|
||||
* <li>57P01 (Admin shutdown)</li>
|
||||
* <li>57P02 (Crash shutdown)</li>
|
||||
* <li>57P03 (Cannot connect now)</li>
|
||||
* <li>01002 (SQL92 disconnect error)</li>
|
||||
* <li>JZ0C0 (Sybase disconnect error)</li>
|
||||
* <li>JZ0C1 (Sybase disconnect error)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final Set<String> DISCONNECTION_SQL_CODES;
|
||||
|
||||
static {
|
||||
DISCONNECTION_SQL_CODES = new HashSet<>();
|
||||
DISCONNECTION_SQL_CODES.add("57P01"); // Admin shutdown
|
||||
DISCONNECTION_SQL_CODES.add("57P02"); // Crash shutdown
|
||||
DISCONNECTION_SQL_CODES.add("57P03"); // Cannot connect now
|
||||
DISCONNECTION_SQL_CODES.add("01002"); // SQL92 disconnect error
|
||||
DISCONNECTION_SQL_CODES.add("JZ0C0"); // Sybase disconnect error
|
||||
DISCONNECTION_SQL_CODES.add("JZ0C1"); // Sybase disconnect error
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the given char[] if not null.
|
||||
*
|
||||
* @param value
|
||||
* may be null.
|
||||
* @return a cloned char[] or null.
|
||||
*/
|
||||
public static char[] clone(final char[] value) {
|
||||
return value == null ? null : value.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the AutoCloseable (which may be null).
|
||||
*
|
||||
* @param autoCloseable
|
||||
* an AutoCloseable, may be {@code null}
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public static void closeQuietly(final AutoCloseable autoCloseable) {
|
||||
if (autoCloseable != null) {
|
||||
try {
|
||||
autoCloseable.close();
|
||||
} catch (final Exception e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the correct i18n message for the given key.
|
||||
*
|
||||
* @param key
|
||||
* The key to look up an i18n message.
|
||||
* @return The i18n message.
|
||||
*/
|
||||
public static String getMessage(final String key) {
|
||||
return getMessage(key, (Object[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the correct i18n message for the given key with placeholders replaced by the supplied arguments.
|
||||
*
|
||||
* @param key
|
||||
* A message key.
|
||||
* @param args
|
||||
* The message arguments.
|
||||
* @return An i18n message.
|
||||
*/
|
||||
public static String getMessage(final String key, final Object... args) {
|
||||
final String msg = messages.getString(key);
|
||||
if (args == null || args.length == 0) {
|
||||
return msg;
|
||||
}
|
||||
final MessageFormat mf = new MessageFormat(msg);
|
||||
return mf.format(args, new StringBuffer(), null).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given String to a char[].
|
||||
*
|
||||
* @param value
|
||||
* may be null.
|
||||
* @return a char[] or null.
|
||||
*/
|
||||
public static char[] toCharArray(final String value) {
|
||||
return value != null ? value.toCharArray() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given char[] to a String.
|
||||
*
|
||||
* @param value
|
||||
* may be null.
|
||||
* @return a String or null.
|
||||
*/
|
||||
public static String toString(final char[] value) {
|
||||
return value == null ? null : String.valueOf(value);
|
||||
}
|
||||
|
||||
private Utils() {
|
||||
// not instantiable
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.cpdsadapter;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.tomcat.dbcp.dbcp2.DelegatingCallableStatement;
|
||||
import org.apache.tomcat.dbcp.dbcp2.DelegatingConnection;
|
||||
import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement;
|
||||
|
||||
/**
|
||||
* This class is the <code>Connection</code> that will be returned from
|
||||
* <code>PooledConnectionImpl.getConnection()</code>. Most methods are wrappers around the JDBC 1.x
|
||||
* <code>Connection</code>. A few exceptions include preparedStatement and close. In accordance with the JDBC
|
||||
* specification this Connection cannot be used after closed() is called. Any further usage will result in an
|
||||
* SQLException.
|
||||
* <p>
|
||||
* ConnectionImpl extends DelegatingConnection to enable access to the underlying connection.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
class ConnectionImpl extends DelegatingConnection<Connection> {
|
||||
|
||||
private final boolean accessToUnderlyingConnectionAllowed;
|
||||
|
||||
/** The object that instantiated this object */
|
||||
private final PooledConnectionImpl pooledConnection;
|
||||
|
||||
/**
|
||||
* Creates a <code>ConnectionImpl</code>.
|
||||
*
|
||||
* @param pooledConnection
|
||||
* The PooledConnection that is calling the ctor.
|
||||
* @param connection
|
||||
* The JDBC 1.x Connection to wrap.
|
||||
* @param accessToUnderlyingConnectionAllowed
|
||||
* if true, then access is allowed to the underlying connection
|
||||
*/
|
||||
ConnectionImpl(final PooledConnectionImpl pooledConnection, final Connection connection,
|
||||
final boolean accessToUnderlyingConnectionAllowed) {
|
||||
super(connection);
|
||||
this.pooledConnection = pooledConnection;
|
||||
this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the Connection as closed, and notifies the pool that the pooled connection is available.
|
||||
* <p>
|
||||
* In accordance with the JDBC specification this Connection cannot be used after closed() is called. Any further
|
||||
* usage will result in an SQLException.
|
||||
* </p>
|
||||
*
|
||||
* @throws SQLException
|
||||
* The database connection couldn't be closed.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
if (!isClosedInternal()) {
|
||||
try {
|
||||
passivate();
|
||||
} finally {
|
||||
setClosedInternal(true);
|
||||
pooledConnection.notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If pooling of <code>CallableStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
|
||||
* be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
@Override
|
||||
public CallableStatement prepareCall(final String sql) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return new DelegatingCallableStatement(this, pooledConnection.prepareCall(sql));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e); // Does not return
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If pooling of <code>CallableStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
|
||||
* be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
@Override
|
||||
public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return new DelegatingCallableStatement(this,
|
||||
pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e); // Does not return
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If pooling of <code>CallableStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
|
||||
* be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
@Override
|
||||
public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return new DelegatingCallableStatement(this,
|
||||
pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e); // Does not return
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If pooling of <code>PreparedStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
|
||||
* be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
|
||||
*
|
||||
* @param sql
|
||||
* SQL statement to be prepared
|
||||
* @return the prepared statement
|
||||
* @throws SQLException
|
||||
* if this connection is closed or an error occurs in the wrapped connection.
|
||||
*/
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e); // Does not return
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If pooling of <code>PreparedStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
|
||||
* be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
|
||||
*
|
||||
* @throws SQLException
|
||||
* if this connection is closed or an error occurs in the wrapped connection.
|
||||
*/
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return new DelegatingPreparedStatement(this,
|
||||
pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return new DelegatingPreparedStatement(this,
|
||||
pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, autoGeneratedKeys));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnIndexes));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException {
|
||||
checkOpen();
|
||||
try {
|
||||
return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnNames));
|
||||
} catch (final SQLException e) {
|
||||
handleException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Methods for accessing the delegate connection
|
||||
//
|
||||
|
||||
/**
|
||||
* If false, getDelegate() and getInnermostDelegate() will return null.
|
||||
*
|
||||
* @return true if access is allowed to the underlying connection
|
||||
* @see ConnectionImpl
|
||||
*/
|
||||
public boolean isAccessToUnderlyingConnectionAllowed() {
|
||||
return accessToUnderlyingConnectionAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the delegated connection, if allowed.
|
||||
*
|
||||
* @return the internal connection, or null if access is not allowed.
|
||||
* @see #isAccessToUnderlyingConnectionAllowed()
|
||||
*/
|
||||
@Override
|
||||
public Connection getDelegate() {
|
||||
if (isAccessToUnderlyingConnectionAllowed()) {
|
||||
return getDelegateInternal();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the innermost connection, if allowed.
|
||||
*
|
||||
* @return the innermost internal connection, or null if access is not allowed.
|
||||
* @see #isAccessToUnderlyingConnectionAllowed()
|
||||
*/
|
||||
@Override
|
||||
public Connection getInnermostDelegate() {
|
||||
if (isAccessToUnderlyingConnectionAllowed()) {
|
||||
return super.getInnermostDelegateInternal();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,779 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.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.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;
|
||||
import org.apache.tomcat.dbcp.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.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
|
||||
* <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, <code>ceil({*link #numIdle})/abs({*link #getNumTestsPerEvictionRun})</code>
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java
Normal file
113
java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2.cpdsadapter;
|
||||
|
||||
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 {
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
*/
|
||||
public PStmtKeyCPDS(final String sql) {
|
||||
super(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @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>.
|
||||
*/
|
||||
public PStmtKeyCPDS(final String sql, final int autoGeneratedKeys) {
|
||||
super(sql, null, autoGeneratedKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @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>.
|
||||
*/
|
||||
public PStmtKeyCPDS(final String sql, final int resultSetType, final int resultSetConcurrency) {
|
||||
super(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @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>
|
||||
* @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>.
|
||||
*/
|
||||
public PStmtKeyCPDS(final String sql, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability) {
|
||||
super(sql, null, resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param columnIndexes
|
||||
* An array of column indexes indicating the columns that should be returned from the inserted row or
|
||||
* rows.
|
||||
*/
|
||||
public PStmtKeyCPDS(final String sql, final int columnIndexes[]) {
|
||||
super(sql, null, columnIndexes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a key to uniquely identify a prepared statement.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param columnNames
|
||||
* An array of column names indicating the columns that should be returned from the inserted row or rows.
|
||||
*/
|
||||
public PStmtKeyCPDS(final String sql, final String columnNames[]) {
|
||||
super(sql, null, columnNames);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,731 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.cpdsadapter;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sql.ConnectionEvent;
|
||||
import javax.sql.ConnectionEventListener;
|
||||
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.Jdbc41Bridge;
|
||||
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.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
class PooledConnectionImpl
|
||||
implements PooledConnection, KeyedPooledObjectFactory<PStmtKey, DelegatingPreparedStatement> {
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* A DelegatingConnection used to create a PoolablePreparedStatementStub.
|
||||
*/
|
||||
private final DelegatingConnection<?> delegatingConnection;
|
||||
|
||||
/**
|
||||
* The JDBC database logical connection.
|
||||
*/
|
||||
private Connection logicalConnection;
|
||||
|
||||
/**
|
||||
* ConnectionEventListeners.
|
||||
*/
|
||||
private final Vector<ConnectionEventListener> eventListeners;
|
||||
|
||||
/**
|
||||
* StatementEventListeners.
|
||||
*/
|
||||
private final Vector<StatementEventListener> statementEventListeners = new Vector<>();
|
||||
|
||||
/**
|
||||
* Flag set to true, once {@link #close()} is called.
|
||||
*/
|
||||
private boolean closed;
|
||||
|
||||
/** My pool of {@link PreparedStatement}s. */
|
||||
private KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pStmtPool;
|
||||
|
||||
/**
|
||||
* Controls access to the underlying connection.
|
||||
*/
|
||||
private boolean accessToUnderlyingConnectionAllowed;
|
||||
|
||||
/**
|
||||
* Wraps the real connection.
|
||||
*
|
||||
* @param connection
|
||||
* the connection to be wrapped.
|
||||
*/
|
||||
PooledConnectionImpl(final Connection connection) {
|
||||
this.connection = connection;
|
||||
if (connection instanceof DelegatingConnection) {
|
||||
this.delegatingConnection = (DelegatingConnection<?>) connection;
|
||||
} else {
|
||||
this.delegatingConnection = new DelegatingConnection<>(connection);
|
||||
}
|
||||
eventListeners = new Vector<>();
|
||||
closed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void addConnectionEventListener(final ConnectionEventListener listener) {
|
||||
if (!eventListeners.contains(listener)) {
|
||||
eventListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/* JDBC_4_ANT_KEY_BEGIN */
|
||||
@Override
|
||||
public void addStatementEventListener(final StatementEventListener listener) {
|
||||
if (!statementEventListeners.contains(listener)) {
|
||||
statementEventListeners.add(listener);
|
||||
}
|
||||
}
|
||||
/* JDBC_4_ANT_KEY_END */
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Thrown when an error occurs or the connection is already closed.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
assertOpen();
|
||||
closed = true;
|
||||
try {
|
||||
if (pStmtPool != null) {
|
||||
try {
|
||||
pStmtPool.close();
|
||||
} finally {
|
||||
pStmtPool = null;
|
||||
}
|
||||
}
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Cannot close connection (return to pool failed)", e);
|
||||
} finally {
|
||||
try {
|
||||
connection.close();
|
||||
} finally {
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PStmtKey} for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @return a {@link PStmtKey} for the given arguments.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PStmtKey} for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @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 key to uniquely identify a prepared statement.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final int autoGeneratedKeys) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), autoGeneratedKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PStmtKey} for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param columnIndexes
|
||||
* An array of column indexes indicating the columns that should be returned from the inserted row or
|
||||
* rows.
|
||||
* @return a key to uniquely identify a prepared statement.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final int columnIndexes[]) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnIndexes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PStmtKey} for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @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 key to uniquely identify a prepared statement.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType,
|
||||
resultSetConcurrency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PStmtKey} for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @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>
|
||||
* @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 key to uniquely identify a prepared statement.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
|
||||
final int resultSetHoldability) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), resultSetType,
|
||||
resultSetConcurrency, resultSetHoldability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PStmtKey} for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @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>.
|
||||
* @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>.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @return a key to uniquely identify a prepared statement.
|
||||
* @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(), getSchemaOrNull(), resultSetType,
|
||||
resultSetConcurrency, resultSetHoldability, statementType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PStmtKey} for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @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>.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @return a key to uniquely identify a prepared statement.
|
||||
* @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(), getSchemaOrNull(), resultSetType,
|
||||
resultSetConcurrency, statementType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PStmtKey} for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param statementType
|
||||
* The SQL statement type, prepared or callable.
|
||||
* @return a key to uniquely identify a prepared statement.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final StatementType statementType) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), statementType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PStmtKey} for the given arguments.
|
||||
*
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @param columnNames
|
||||
* An array of column names indicating the columns that should be returned from the inserted row or rows.
|
||||
* @return a key to uniquely identify a prepared statement.
|
||||
*/
|
||||
protected PStmtKey createKey(final String sql, final String columnNames[]) {
|
||||
return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), 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;
|
||||
}
|
||||
}
|
||||
|
||||
private String getSchemaOrNull() {
|
||||
try {
|
||||
return connection == null ? null : Jdbc41Bridge.getSchema(connection);
|
||||
} catch (final SQLException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JDBC connection.
|
||||
*
|
||||
* @return The database connection.
|
||||
* @throws SQLException
|
||||
* if the connection is not open or the previous logical connection is still open
|
||||
*/
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
assertOpen();
|
||||
// make sure the last connection is marked as closed
|
||||
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.");
|
||||
}
|
||||
|
||||
// the spec requires that this return a new Connection instance.
|
||||
logicalConnection = new ConnectionImpl(this, connection, isAccessToUnderlyingConnectionAllowed());
|
||||
return logicalConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* My {@link KeyedPooledObjectFactory} method for creating {@link PreparedStatement}s.
|
||||
*
|
||||
* @param key
|
||||
* The key for the {@link PreparedStatement} to be created.
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
@Override
|
||||
public PooledObject<DelegatingPreparedStatement> makeObject(final PStmtKey key) throws Exception {
|
||||
if (null == key) {
|
||||
throw new IllegalArgumentException("Prepared statement key is null or invalid.");
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the given SQL statement, producing a canonical form that is semantically equivalent to the original.
|
||||
* @param sql
|
||||
* The SQL statement.
|
||||
* @return the normalized SQL statement.
|
||||
*/
|
||||
protected String normalizeSQL(final String sql) {
|
||||
return sql.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a connectionClosed event.
|
||||
*/
|
||||
void notifyListeners() {
|
||||
final ConnectionEvent event = new ConnectionEvent(this);
|
||||
final Object[] listeners = eventListeners.toArray();
|
||||
for (final Object listener : listeners) {
|
||||
((ConnectionEventListener) listener).connectionClosed(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
|
||||
throws SQLException {
|
||||
if (pStmtPool == null) {
|
||||
return connection.prepareCall(sql, resultSetType, resultSetConcurrency);
|
||||
}
|
||||
try {
|
||||
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 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
|
||||
* 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}
|
||||
*/
|
||||
PreparedStatement prepareStatement(final String sql) throws SQLException {
|
||||
if (pStmtPool == null) {
|
||||
return connection.prepareStatement(sql);
|
||||
}
|
||||
try {
|
||||
return pStmtPool.borrowObject(createKey(sql));
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return connection.prepareStatement(sql, autoGeneratedKeys);
|
||||
}
|
||||
try {
|
||||
return pStmtPool.borrowObject(createKey(sql, autoGeneratedKeys));
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException {
|
||||
if (pStmtPool == null) {
|
||||
return connection.prepareStatement(sql, columnIndexes);
|
||||
}
|
||||
try {
|
||||
return pStmtPool.borrowObject(createKey(sql, columnIndexes));
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, resultSetType, resultSetConcurrency));
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
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, resultSetType, resultSetConcurrency, resultSetHoldability));
|
||||
} catch (final RuntimeException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Borrow prepareStatement from pool failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException {
|
||||
if (pStmtPool == null) {
|
||||
return connection.prepareStatement(sql, columnNames);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
/* JDBC_4_ANT_KEY_END */
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
public void setStatementPool(final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> statementPool) {
|
||||
pStmtPool = statementPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* My {@link KeyedPooledObjectFactory} method for validating {@link PreparedStatement}s.
|
||||
*
|
||||
* @param key
|
||||
* Ignored.
|
||||
* @param pooledObject
|
||||
* Ignored.
|
||||
* @return {@code true}
|
||||
*/
|
||||
@Override
|
||||
public boolean validateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This package contains one public class which is a
|
||||
* <code>ConnectionPoolDataSource</code> (CPDS) implementation that can be used to
|
||||
* adapt older <code>Driver</code> based JDBC implementations. Below is an
|
||||
* example of setting up the CPDS to be available via JNDI in the
|
||||
* catalina servlet container.
|
||||
* </p>
|
||||
* <p>In server.xml, the following would be added to the <Context> for your
|
||||
* webapp:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <Resource name="jdbc/bookstoreCPDS" auth="Container"
|
||||
* type="org.apache.tomcat.dbcp.dbcp2.cpdsadapter.DriverAdapterCPDS"/>
|
||||
* <ResourceParams name="jdbc/bookstoreCPDS">
|
||||
* <parameter>
|
||||
* <name>factory</name>
|
||||
* <value>org.apache.tomcat.dbcp.dbcp2.cpdsadapter.DriverAdapterCPDS</value>
|
||||
* </parameter>
|
||||
* <parameter><name>user</name><value>root</value></parameter>
|
||||
* <parameter><name>password</name><value></value></parameter>
|
||||
* <parameter>
|
||||
* <name>driver</name>
|
||||
* <value>org.gjt.mm.mysql.Driver</value></parameter>
|
||||
* <parameter>
|
||||
* <name>url</name>
|
||||
* <value>jdbc:mysql://localhost:3306/bookstore</value>
|
||||
* </parameter>
|
||||
* </ResourceParams>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* In web.xml. Note that elements must be given in the order of the dtd
|
||||
* described in the servlet specification:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <resource-ref>
|
||||
* <description>
|
||||
* Resource reference to a factory for java.sql.Connection
|
||||
* instances that may be used for talking to a particular
|
||||
* database that is configured in the server.xml file.
|
||||
* </description>
|
||||
* <res-ref-name>
|
||||
* jdbc/bookstoreCPDS
|
||||
* </res-ref-name>
|
||||
* <res-type>
|
||||
* org.apache.tomcat.dbcp.dbcp2.cpdsadapter.DriverAdapterCPDS
|
||||
* </res-type>
|
||||
* <res-auth>
|
||||
* Container
|
||||
* </res-auth>
|
||||
* </resource-ref>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Catalina deploys all objects configured similarly to above within the
|
||||
* <strong>java:comp/env</strong> namespace.
|
||||
* </p>
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2.cpdsadapter;
|
||||
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.sql.ConnectionEvent;
|
||||
import javax.sql.ConnectionEventListener;
|
||||
import javax.sql.ConnectionPoolDataSource;
|
||||
import javax.sql.PooledConnection;
|
||||
|
||||
import org.apache.tomcat.dbcp.dbcp2.Utils;
|
||||
import org.apache.tomcat.dbcp.pool2.ObjectPool;
|
||||
import org.apache.tomcat.dbcp.pool2.PooledObject;
|
||||
import org.apache.tomcat.dbcp.pool2.PooledObjectFactory;
|
||||
import org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject;
|
||||
|
||||
/**
|
||||
* A {@link PooledObjectFactory} that creates
|
||||
* {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnection PoolableConnection}s.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
class CPDSConnectionFactory
|
||||
implements PooledObjectFactory<PooledConnectionAndInfo>, ConnectionEventListener, PooledConnectionManager {
|
||||
|
||||
private static final String NO_KEY_MESSAGE = "close() was called on a Connection, but I have no record of the underlying PooledConnection.";
|
||||
|
||||
private final ConnectionPoolDataSource cpds;
|
||||
private final String validationQuery;
|
||||
private final int validationQueryTimeoutSeconds;
|
||||
private final boolean rollbackAfterValidation;
|
||||
private ObjectPool<PooledConnectionAndInfo> pool;
|
||||
private final String userName;
|
||||
private char[] userPassword;
|
||||
private long maxConnLifetimeMillis = -1;
|
||||
|
||||
/**
|
||||
* Map of PooledConnections for which close events are ignored. Connections are muted when they are being validated.
|
||||
*/
|
||||
private final Set<PooledConnection> validatingSet = Collections
|
||||
.newSetFromMap(new ConcurrentHashMap<PooledConnection, Boolean>());
|
||||
|
||||
/**
|
||||
* Map of PooledConnectionAndInfo instances
|
||||
*/
|
||||
private final Map<PooledConnection, PooledConnectionAndInfo> pcMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new {@code PoolableConnectionFactory}.
|
||||
*
|
||||
* @param cpds
|
||||
* the ConnectionPoolDataSource from which to obtain PooledConnection's
|
||||
* @param validationQuery
|
||||
* a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
|
||||
* row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate
|
||||
* connections.
|
||||
* @param validationQueryTimeoutSeconds
|
||||
* Timeout in seconds before validation fails
|
||||
* @param rollbackAfterValidation
|
||||
* whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
|
||||
* @param userName
|
||||
* The user name to use to create connections
|
||||
* @param userPassword
|
||||
* The password to use to create connections
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
|
||||
final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation, final String userName,
|
||||
final char[] userPassword) {
|
||||
this.cpds = cpds;
|
||||
this.validationQuery = validationQuery;
|
||||
this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
|
||||
this.userName = userName;
|
||||
this.userPassword = userPassword;
|
||||
this.rollbackAfterValidation = rollbackAfterValidation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code PoolableConnectionFactory}.
|
||||
*
|
||||
* @param cpds
|
||||
* the ConnectionPoolDataSource from which to obtain PooledConnection's
|
||||
* @param validationQuery
|
||||
* a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
|
||||
* row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate
|
||||
* connections.
|
||||
* @param validationQueryTimeoutSeconds
|
||||
* Timeout in seconds before validation fails
|
||||
* @param rollbackAfterValidation
|
||||
* whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
|
||||
* @param userName
|
||||
* The user name to use to create connections
|
||||
* @param userPassword
|
||||
* The password to use to create connections
|
||||
*/
|
||||
public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
|
||||
final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation, final String userName,
|
||||
final String userPassword) {
|
||||
this(cpds, validationQuery, validationQueryTimeoutSeconds, rollbackAfterValidation, userName,
|
||||
Utils.toCharArray(userPassword));
|
||||
}
|
||||
|
||||
/**
|
||||
* (Testing API) Gets the value of password for the default user.
|
||||
*
|
||||
* @return value of password.
|
||||
*/
|
||||
char[] getPasswordCharArray() {
|
||||
return userPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object pool used to pool connections created by this factory.
|
||||
*
|
||||
* @return ObjectPool managing pooled connections
|
||||
*/
|
||||
public ObjectPool<PooledConnectionAndInfo> getPool() {
|
||||
return pool;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pool
|
||||
* the {@link ObjectPool} in which to pool those {@link Connection}s
|
||||
*/
|
||||
public void setPool(final ObjectPool<PooledConnectionAndInfo> pool) {
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized PooledObject<PooledConnectionAndInfo> makeObject() {
|
||||
PooledConnectionAndInfo pci;
|
||||
try {
|
||||
PooledConnection pc = null;
|
||||
if (userName == null) {
|
||||
pc = cpds.getPooledConnection();
|
||||
} else {
|
||||
pc = cpds.getPooledConnection(userName, Utils.toString(userPassword));
|
||||
}
|
||||
|
||||
if (pc == null) {
|
||||
throw new IllegalStateException("Connection pool data source returned null from getPooledConnection");
|
||||
}
|
||||
|
||||
// should we add this object as a listener or the pool.
|
||||
// consider the validateObject method in decision
|
||||
pc.addConnectionEventListener(this);
|
||||
pci = new PooledConnectionAndInfo(pc, userName, userPassword);
|
||||
pcMap.put(pc, pci);
|
||||
} catch (final SQLException e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
return new DefaultPooledObject<>(pci);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the PooledConnection and stops listening for events from it.
|
||||
*/
|
||||
@Override
|
||||
public void destroyObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
|
||||
doDestroyObject(p.getObject());
|
||||
}
|
||||
|
||||
private void doDestroyObject(final PooledConnectionAndInfo pci) throws Exception {
|
||||
final PooledConnection pc = pci.getPooledConnection();
|
||||
pc.removeConnectionEventListener(this);
|
||||
pcMap.remove(pc);
|
||||
pc.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(final PooledObject<PooledConnectionAndInfo> p) {
|
||||
try {
|
||||
validateLifetime(p);
|
||||
} catch (final Exception e) {
|
||||
return false;
|
||||
}
|
||||
boolean valid = false;
|
||||
final PooledConnection pconn = p.getObject().getPooledConnection();
|
||||
Connection conn = null;
|
||||
validatingSet.add(pconn);
|
||||
if (null == validationQuery) {
|
||||
int timeoutSeconds = validationQueryTimeoutSeconds;
|
||||
if (timeoutSeconds < 0) {
|
||||
timeoutSeconds = 0;
|
||||
}
|
||||
try {
|
||||
conn = pconn.getConnection();
|
||||
valid = conn.isValid(timeoutSeconds);
|
||||
} catch (final SQLException e) {
|
||||
valid = false;
|
||||
} finally {
|
||||
Utils.closeQuietly(conn);
|
||||
validatingSet.remove(pconn);
|
||||
}
|
||||
} else {
|
||||
Statement stmt = null;
|
||||
ResultSet rset = null;
|
||||
// logical Connection from the PooledConnection must be closed
|
||||
// before another one can be requested and closing it will
|
||||
// generate an event. Keep track so we know not to return
|
||||
// the PooledConnection
|
||||
validatingSet.add(pconn);
|
||||
try {
|
||||
conn = pconn.getConnection();
|
||||
stmt = conn.createStatement();
|
||||
rset = stmt.executeQuery(validationQuery);
|
||||
if (rset.next()) {
|
||||
valid = true;
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
if (rollbackAfterValidation) {
|
||||
conn.rollback();
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
valid = false;
|
||||
} finally {
|
||||
Utils.closeQuietly(rset);
|
||||
Utils.closeQuietly(stmt);
|
||||
Utils.closeQuietly(conn);
|
||||
validatingSet.remove(pconn);
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
|
||||
validateLifetime(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
|
||||
validateLifetime(p);
|
||||
}
|
||||
|
||||
// ***********************************************************************
|
||||
// java.sql.ConnectionEventListener implementation
|
||||
// ***********************************************************************
|
||||
|
||||
/**
|
||||
* This will be called if the Connection returned by the getConnection method came from a PooledConnection, and the
|
||||
* user calls the close() method of this connection object. What we need to do here is to release this
|
||||
* PooledConnection from our pool...
|
||||
*/
|
||||
@Override
|
||||
public void connectionClosed(final ConnectionEvent event) {
|
||||
final PooledConnection pc = (PooledConnection) event.getSource();
|
||||
// if this event occurred because we were validating, ignore it
|
||||
// otherwise return the connection to the pool.
|
||||
if (!validatingSet.contains(pc)) {
|
||||
final PooledConnectionAndInfo pci = pcMap.get(pc);
|
||||
if (pci == null) {
|
||||
throw new IllegalStateException(NO_KEY_MESSAGE);
|
||||
}
|
||||
|
||||
try {
|
||||
pool.returnObject(pci);
|
||||
} catch (final Exception e) {
|
||||
System.err.println("CLOSING DOWN CONNECTION AS IT COULD " + "NOT BE RETURNED TO THE POOL");
|
||||
pc.removeConnectionEventListener(this);
|
||||
try {
|
||||
doDestroyObject(pci);
|
||||
} catch (final Exception e2) {
|
||||
System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci);
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a fatal error occurs, close the underlying physical connection so as not to be returned in the future
|
||||
*/
|
||||
@Override
|
||||
public void connectionErrorOccurred(final ConnectionEvent event) {
|
||||
final PooledConnection pc = (PooledConnection) event.getSource();
|
||||
if (null != event.getSQLException()) {
|
||||
System.err.println("CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR (" + event.getSQLException() + ")");
|
||||
}
|
||||
pc.removeConnectionEventListener(this);
|
||||
|
||||
final PooledConnectionAndInfo pci = pcMap.get(pc);
|
||||
if (pci == null) {
|
||||
throw new IllegalStateException(NO_KEY_MESSAGE);
|
||||
}
|
||||
try {
|
||||
pool.invalidateObject(pci);
|
||||
} catch (final Exception e) {
|
||||
System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// ***********************************************************************
|
||||
// PooledConnectionManager implementation
|
||||
// ***********************************************************************
|
||||
|
||||
/**
|
||||
* Invalidates the PooledConnection in the pool. The CPDSConnectionFactory closes the connection and pool counters
|
||||
* are updated appropriately. Also closes the pool. This ensures that all idle connections are closed and
|
||||
* connections that are checked out are closed on return.
|
||||
*/
|
||||
@Override
|
||||
public void invalidate(final PooledConnection pc) throws SQLException {
|
||||
final PooledConnectionAndInfo pci = pcMap.get(pc);
|
||||
if (pci == null) {
|
||||
throw new IllegalStateException(NO_KEY_MESSAGE);
|
||||
}
|
||||
try {
|
||||
pool.invalidateObject(pci); // Destroy instance and update pool counters
|
||||
pool.close(); // Clear any other instances in this pool and kill others as they come back
|
||||
} catch (final Exception ex) {
|
||||
throw new SQLException("Error invalidating connection", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database password used when creating new connections.
|
||||
*
|
||||
* @param userPassword
|
||||
* new password
|
||||
*/
|
||||
public synchronized void setPassword(final char[] userPassword) {
|
||||
this.userPassword = Utils.clone(userPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database password used when creating new connections.
|
||||
*
|
||||
* @param userPassword
|
||||
* new password
|
||||
*/
|
||||
@Override
|
||||
public synchronized void setPassword(final String userPassword) {
|
||||
this.userPassword = Utils.toCharArray(userPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
|
||||
* passivation and validation.
|
||||
*
|
||||
* @param maxConnLifetimeMillis
|
||||
* A value of zero or less indicates an infinite lifetime. The default value is -1.
|
||||
*/
|
||||
public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
|
||||
this.maxConnLifetimeMillis = maxConnLifetimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the user name matches the user whose connections are being managed by this factory and closes the
|
||||
* pool if this is the case; otherwise does nothing.
|
||||
*/
|
||||
@Override
|
||||
public void closePool(final String userName) throws SQLException {
|
||||
synchronized (this) {
|
||||
if (userName == null || !userName.equals(this.userName)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
pool.close();
|
||||
} catch (final Exception ex) {
|
||||
throw new SQLException("Error closing connection pool", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLifetime(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
|
||||
if (maxConnLifetimeMillis > 0) {
|
||||
final long lifetime = System.currentTimeMillis() - p.getCreateTime();
|
||||
if (lifetime > maxConnLifetimeMillis) {
|
||||
throw new Exception(Utils.getMessage("connectionFactory.lifetimeExceeded", Long.valueOf(lifetime),
|
||||
Long.valueOf(maxConnLifetimeMillis)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.6.0
|
||||
*/
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
final StringBuilder builder = new StringBuilder(super.toString());
|
||||
builder.append("[cpds=");
|
||||
builder.append(cpds);
|
||||
builder.append(", validationQuery=");
|
||||
builder.append(validationQuery);
|
||||
builder.append(", validationQueryTimeoutSeconds=");
|
||||
builder.append(validationQueryTimeoutSeconds);
|
||||
builder.append(", rollbackAfterValidation=");
|
||||
builder.append(rollbackAfterValidation);
|
||||
builder.append(", pool=");
|
||||
builder.append(pool);
|
||||
builder.append(", maxConnLifetimeMillis=");
|
||||
builder.append(maxConnLifetimeMillis);
|
||||
builder.append(", validatingSet=");
|
||||
builder.append(validatingSet);
|
||||
builder.append(", pcMap=");
|
||||
builder.append(pcMap);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.RefAddr;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.spi.ObjectFactory;
|
||||
|
||||
import org.apache.tomcat.dbcp.dbcp2.ListException;
|
||||
|
||||
/**
|
||||
* A JNDI ObjectFactory which creates <code>SharedPoolDataSource</code>s or <code>PerUserPoolDataSource</code>s
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
|
||||
|
||||
private static final Map<String, InstanceKeyDataSource> instanceMap = new ConcurrentHashMap<>();
|
||||
|
||||
static synchronized String registerNewInstance(final InstanceKeyDataSource ds) {
|
||||
int max = 0;
|
||||
final Iterator<String> iterator = instanceMap.keySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final String s = iterator.next();
|
||||
if (s != null) {
|
||||
try {
|
||||
max = Math.max(max, Integer.parseInt(s));
|
||||
} catch (final NumberFormatException e) {
|
||||
// no sweat, ignore those keys
|
||||
}
|
||||
}
|
||||
}
|
||||
final String instanceKey = String.valueOf(max + 1);
|
||||
// Put a placeholder here for now, so other instances will not
|
||||
// take our key. We will replace with a pool when ready.
|
||||
instanceMap.put(instanceKey, ds);
|
||||
return instanceKey;
|
||||
}
|
||||
|
||||
static void removeInstance(final String key) {
|
||||
if (key != null) {
|
||||
instanceMap.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all pools associated with this class.
|
||||
*
|
||||
* @throws Exception
|
||||
* a {@link ListException} containing all exceptions thrown by {@link InstanceKeyDataSource#close()}
|
||||
* @see InstanceKeyDataSource#close()
|
||||
* @see ListException
|
||||
* @since 2.4.0 throws a {@link ListException} instead of, in 2.3.0 and before, the first exception thrown by
|
||||
* {@link InstanceKeyDataSource#close()}.
|
||||
*/
|
||||
public static void closeAll() throws Exception {
|
||||
// Get iterator to loop over all instances of this data source.
|
||||
final List<Throwable> exceptionList = new ArrayList<>(instanceMap.size());
|
||||
final Iterator<Entry<String, InstanceKeyDataSource>> instanceIterator = instanceMap.entrySet().iterator();
|
||||
while (instanceIterator.hasNext()) {
|
||||
// Bullet-proof to avoid anything else but problems from InstanceKeyDataSource#close().
|
||||
final Entry<String, InstanceKeyDataSource> next = instanceIterator.next();
|
||||
if (next != null) {
|
||||
@SuppressWarnings("resource")
|
||||
final InstanceKeyDataSource value = next.getValue();
|
||||
if (value != null) {
|
||||
try {
|
||||
value.close();
|
||||
} catch (final Exception e) {
|
||||
exceptionList.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
instanceMap.clear();
|
||||
if (!exceptionList.isEmpty()) {
|
||||
throw new ListException("Could not close all InstanceKeyDataSource instances.", exceptionList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ObjectFactory to create an instance of SharedPoolDataSource or PerUserPoolDataSource
|
||||
*/
|
||||
@Override
|
||||
public Object getObjectInstance(final Object refObj, final Name name, final Context context,
|
||||
final Hashtable<?, ?> env) throws IOException, ClassNotFoundException {
|
||||
// The spec says to return null if we can't create an instance
|
||||
// of the reference
|
||||
Object obj = null;
|
||||
if (refObj instanceof Reference) {
|
||||
final Reference ref = (Reference) refObj;
|
||||
if (isCorrectClass(ref.getClassName())) {
|
||||
final RefAddr refAddr = ref.get("instanceKey");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
// object was bound to JNDI via Referenceable API.
|
||||
obj = instanceMap.get(refAddr.getContent());
|
||||
} else {
|
||||
// Tomcat JNDI creates a Reference out of server.xml
|
||||
// <ResourceParam> configuration and passes it to an
|
||||
// instance of the factory given in server.xml.
|
||||
String key = null;
|
||||
if (name != null) {
|
||||
key = name.toString();
|
||||
obj = instanceMap.get(key);
|
||||
}
|
||||
if (obj == null) {
|
||||
final InstanceKeyDataSource ds = getNewInstance(ref);
|
||||
setCommonProperties(ref, ds);
|
||||
obj = ds;
|
||||
if (key != null) {
|
||||
instanceMap.put(key, ds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private void setCommonProperties(final Reference ref, final InstanceKeyDataSource ikds)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
RefAddr refAddr = ref.get("dataSourceName");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDataSourceName(refAddr.getContent().toString());
|
||||
}
|
||||
|
||||
refAddr = ref.get("description");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDescription(refAddr.getContent().toString());
|
||||
}
|
||||
|
||||
refAddr = ref.get("jndiEnvironment");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
final byte[] serialized = (byte[]) refAddr.getContent();
|
||||
ikds.setJndiEnvironment((Properties) deserialize(serialized));
|
||||
}
|
||||
|
||||
refAddr = ref.get("loginTimeout");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setLoginTimeout(Integer.parseInt(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
// Pool properties
|
||||
refAddr = ref.get("blockWhenExhausted");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultBlockWhenExhausted(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
|
||||
}
|
||||
|
||||
refAddr = ref.get("evictionPolicyClassName");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultEvictionPolicyClassName(refAddr.getContent().toString());
|
||||
}
|
||||
|
||||
// Pool properties
|
||||
refAddr = ref.get("lifo");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultLifo(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
|
||||
}
|
||||
|
||||
refAddr = ref.get("maxIdlePerKey");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultMaxIdle(Integer.parseInt(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("maxTotalPerKey");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultMaxTotal(Integer.parseInt(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("maxWaitMillis");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultMaxWaitMillis(Long.parseLong(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("minEvictableIdleTimeMillis");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultMinEvictableIdleTimeMillis(Long.parseLong(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("minIdlePerKey");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultMinIdle(Integer.parseInt(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("numTestsPerEvictionRun");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultNumTestsPerEvictionRun(Integer.parseInt(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("softMinEvictableIdleTimeMillis");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultSoftMinEvictableIdleTimeMillis(Long.parseLong(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("testOnCreate");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultTestOnCreate(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
|
||||
}
|
||||
|
||||
refAddr = ref.get("testOnBorrow");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultTestOnBorrow(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
|
||||
}
|
||||
|
||||
refAddr = ref.get("testOnReturn");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultTestOnReturn(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
|
||||
}
|
||||
|
||||
refAddr = ref.get("testWhileIdle");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultTestWhileIdle(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
|
||||
}
|
||||
|
||||
refAddr = ref.get("timeBetweenEvictionRunsMillis");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultTimeBetweenEvictionRunsMillis(Long.parseLong(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
// Connection factory properties
|
||||
|
||||
refAddr = ref.get("validationQuery");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setValidationQuery(refAddr.getContent().toString());
|
||||
}
|
||||
|
||||
refAddr = ref.get("validationQueryTimeout");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setValidationQueryTimeout(Integer.parseInt(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("rollbackAfterValidation");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setRollbackAfterValidation(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
|
||||
}
|
||||
|
||||
refAddr = ref.get("maxConnLifetimeMillis");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setMaxConnLifetimeMillis(Long.parseLong(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
// Connection properties
|
||||
|
||||
refAddr = ref.get("defaultAutoCommit");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultAutoCommit(Boolean.valueOf(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("defaultTransactionIsolation");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultTransactionIsolation(Integer.parseInt(refAddr.getContent().toString()));
|
||||
}
|
||||
|
||||
refAddr = ref.get("defaultReadOnly");
|
||||
if (refAddr != null && refAddr.getContent() != null) {
|
||||
ikds.setDefaultReadOnly(Boolean.valueOf(refAddr.getContent().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param className
|
||||
* The class name to test.
|
||||
*
|
||||
* @return true if and only if className is the value returned from getClass().getName().toString()
|
||||
*/
|
||||
protected abstract boolean isCorrectClass(String className);
|
||||
|
||||
/**
|
||||
* Creates an instance of the subclass and sets any properties contained in the Reference.
|
||||
*
|
||||
* @param ref
|
||||
* The properties to be set on the created DataSource
|
||||
*
|
||||
* @return A configured DataSource of the appropriate type.
|
||||
*
|
||||
* @throws ClassNotFoundException
|
||||
* If a class cannot be found during the deserialization of a configuration parameter.
|
||||
* @throws IOException
|
||||
* If an I/O error occurs during the deserialization of a configuration parameter.
|
||||
*/
|
||||
protected abstract InstanceKeyDataSource getNewInstance(Reference ref) throws IOException, ClassNotFoundException;
|
||||
|
||||
/**
|
||||
* Deserializes the provided byte array to create an object.
|
||||
*
|
||||
* @param data
|
||||
* Data to deserialize to create the configuration parameter.
|
||||
*
|
||||
* @return The Object created by deserializing the data.
|
||||
*
|
||||
* @throws ClassNotFoundException
|
||||
* If a class cannot be found during the deserialization of a configuration parameter.
|
||||
* @throws IOException
|
||||
* If an I/O error occurs during the deserialization of a configuration parameter.
|
||||
*/
|
||||
protected static final Object deserialize(final byte[] data) throws IOException, ClassNotFoundException {
|
||||
ObjectInputStream in = null;
|
||||
try {
|
||||
in = new ObjectInputStream(new ByteArrayInputStream(data));
|
||||
return in.readObject();
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (final IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.sql.ConnectionEvent;
|
||||
import javax.sql.ConnectionEventListener;
|
||||
import javax.sql.ConnectionPoolDataSource;
|
||||
import javax.sql.PooledConnection;
|
||||
|
||||
import org.apache.tomcat.dbcp.dbcp2.Utils;
|
||||
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;
|
||||
|
||||
/**
|
||||
* A {@link KeyedPooledObjectFactory} that creates {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnection
|
||||
* PoolableConnection}s.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
class KeyedCPDSConnectionFactory implements KeyedPooledObjectFactory<UserPassKey, PooledConnectionAndInfo>,
|
||||
ConnectionEventListener, PooledConnectionManager {
|
||||
|
||||
private static final String NO_KEY_MESSAGE = "close() was called on a Connection, but "
|
||||
+ "I have no record of the underlying PooledConnection.";
|
||||
|
||||
private final ConnectionPoolDataSource cpds;
|
||||
private final String validationQuery;
|
||||
private final int validationQueryTimeoutSeconds;
|
||||
private final boolean rollbackAfterValidation;
|
||||
private KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> pool;
|
||||
private long maxConnLifetimeMillis = -1;
|
||||
|
||||
/**
|
||||
* Map of PooledConnections for which close events are ignored. Connections are muted when they are being validated.
|
||||
*/
|
||||
private final Set<PooledConnection> validatingSet = Collections
|
||||
.newSetFromMap(new ConcurrentHashMap<PooledConnection, Boolean>());
|
||||
|
||||
/**
|
||||
* Map of PooledConnectionAndInfo instances
|
||||
*/
|
||||
private final Map<PooledConnection, PooledConnectionAndInfo> pcMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Create a new {@code KeyedPoolableConnectionFactory}.
|
||||
*
|
||||
* @param cpds
|
||||
* the ConnectionPoolDataSource from which to obtain PooledConnections
|
||||
* @param validationQuery
|
||||
* a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
|
||||
* row. May be {@code null} in which case3 {@link Connection#isValid(int)} will be used to validate
|
||||
* connections.
|
||||
* @param validationQueryTimeoutSeconds
|
||||
* The time, in seconds, to allow for the validation query to complete
|
||||
* @param rollbackAfterValidation
|
||||
* whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
|
||||
*/
|
||||
public KeyedCPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
|
||||
final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation) {
|
||||
this.cpds = cpds;
|
||||
this.validationQuery = validationQuery;
|
||||
this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
|
||||
this.rollbackAfterValidation = rollbackAfterValidation;
|
||||
}
|
||||
|
||||
public void setPool(final KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> pool) {
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keyed object pool used to pool connections created by this factory.
|
||||
*
|
||||
* @return KeyedObjectPool managing pooled connections
|
||||
*/
|
||||
public KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> getPool() {
|
||||
return pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link PooledConnectionAndInfo} from the given {@link UserPassKey}.
|
||||
*
|
||||
* @param upkey
|
||||
* {@link UserPassKey} containing user credentials
|
||||
* @throws SQLException
|
||||
* if the connection could not be created.
|
||||
* @see org.apache.tomcat.dbcp.pool2.KeyedPooledObjectFactory#makeObject(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public synchronized PooledObject<PooledConnectionAndInfo> makeObject(final UserPassKey upkey) throws Exception {
|
||||
PooledConnectionAndInfo pci = null;
|
||||
|
||||
PooledConnection pc = null;
|
||||
final String userName = upkey.getUsername();
|
||||
final String password = upkey.getPassword();
|
||||
if (userName == null) {
|
||||
pc = cpds.getPooledConnection();
|
||||
} else {
|
||||
pc = cpds.getPooledConnection(userName, password);
|
||||
}
|
||||
|
||||
if (pc == null) {
|
||||
throw new IllegalStateException("Connection pool data source returned null from getPooledConnection");
|
||||
}
|
||||
|
||||
// should we add this object as a listener or the pool.
|
||||
// consider the validateObject method in decision
|
||||
pc.addConnectionEventListener(this);
|
||||
pci = new PooledConnectionAndInfo(pc, userName, upkey.getPasswordCharArray());
|
||||
pcMap.put(pc, pci);
|
||||
|
||||
return new DefaultPooledObject<>(pci);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the PooledConnection and stops listening for events from it.
|
||||
*/
|
||||
@Override
|
||||
public void destroyObject(final UserPassKey key, final PooledObject<PooledConnectionAndInfo> p) throws Exception {
|
||||
final PooledConnection pc = p.getObject().getPooledConnection();
|
||||
pc.removeConnectionEventListener(this);
|
||||
pcMap.remove(pc);
|
||||
pc.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a pooled connection.
|
||||
*
|
||||
* @param key
|
||||
* ignored
|
||||
* @param pooledObject
|
||||
* wrapped {@link PooledConnectionAndInfo} containing the connection to validate
|
||||
* @return true if validation succeeds
|
||||
*/
|
||||
@Override
|
||||
public boolean validateObject(final UserPassKey key, final PooledObject<PooledConnectionAndInfo> pooledObject) {
|
||||
try {
|
||||
validateLifetime(pooledObject);
|
||||
} catch (final Exception e) {
|
||||
return false;
|
||||
}
|
||||
boolean valid = false;
|
||||
final PooledConnection pconn = pooledObject.getObject().getPooledConnection();
|
||||
Connection conn = null;
|
||||
validatingSet.add(pconn);
|
||||
if (null == validationQuery) {
|
||||
int timeoutSeconds = validationQueryTimeoutSeconds;
|
||||
if (timeoutSeconds < 0) {
|
||||
timeoutSeconds = 0;
|
||||
}
|
||||
try {
|
||||
conn = pconn.getConnection();
|
||||
valid = conn.isValid(timeoutSeconds);
|
||||
} catch (final SQLException e) {
|
||||
valid = false;
|
||||
} finally {
|
||||
Utils.closeQuietly(conn);
|
||||
validatingSet.remove(pconn);
|
||||
}
|
||||
} else {
|
||||
Statement stmt = null;
|
||||
ResultSet rset = null;
|
||||
// logical Connection from the PooledConnection must be closed
|
||||
// before another one can be requested and closing it will
|
||||
// generate an event. Keep track so we know not to return
|
||||
// the PooledConnection
|
||||
validatingSet.add(pconn);
|
||||
try {
|
||||
conn = pconn.getConnection();
|
||||
stmt = conn.createStatement();
|
||||
rset = stmt.executeQuery(validationQuery);
|
||||
if (rset.next()) {
|
||||
valid = true;
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
if (rollbackAfterValidation) {
|
||||
conn.rollback();
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
valid = false;
|
||||
} finally {
|
||||
Utils.closeQuietly(rset);
|
||||
Utils.closeQuietly(stmt);
|
||||
Utils.closeQuietly(conn);
|
||||
validatingSet.remove(pconn);
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(final UserPassKey key, final PooledObject<PooledConnectionAndInfo> p) throws Exception {
|
||||
validateLifetime(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(final UserPassKey key, final PooledObject<PooledConnectionAndInfo> p) throws Exception {
|
||||
validateLifetime(p);
|
||||
}
|
||||
|
||||
// ***********************************************************************
|
||||
// java.sql.ConnectionEventListener implementation
|
||||
// ***********************************************************************
|
||||
|
||||
/**
|
||||
* This will be called if the Connection returned by the getConnection method came from a PooledConnection, and the
|
||||
* user calls the close() method of this connection object. What we need to do here is to release this
|
||||
* PooledConnection from our pool...
|
||||
*/
|
||||
@Override
|
||||
public void connectionClosed(final ConnectionEvent event) {
|
||||
final PooledConnection pc = (PooledConnection) event.getSource();
|
||||
// if this event occurred because we were validating, or if this
|
||||
// connection has been marked for removal, ignore it
|
||||
// otherwise return the connection to the pool.
|
||||
if (!validatingSet.contains(pc)) {
|
||||
final PooledConnectionAndInfo pci = pcMap.get(pc);
|
||||
if (pci == null) {
|
||||
throw new IllegalStateException(NO_KEY_MESSAGE);
|
||||
}
|
||||
try {
|
||||
pool.returnObject(pci.getUserPassKey(), pci);
|
||||
} catch (final Exception e) {
|
||||
System.err.println("CLOSING DOWN CONNECTION AS IT COULD " + "NOT BE RETURNED TO THE POOL");
|
||||
pc.removeConnectionEventListener(this);
|
||||
try {
|
||||
pool.invalidateObject(pci.getUserPassKey(), pci);
|
||||
} catch (final Exception e3) {
|
||||
System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci);
|
||||
e3.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a fatal error occurs, close the underlying physical connection so as not to be returned in the future
|
||||
*/
|
||||
@Override
|
||||
public void connectionErrorOccurred(final ConnectionEvent event) {
|
||||
final PooledConnection pc = (PooledConnection) event.getSource();
|
||||
if (null != event.getSQLException()) {
|
||||
System.err.println("CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR (" + event.getSQLException() + ")");
|
||||
}
|
||||
pc.removeConnectionEventListener(this);
|
||||
|
||||
final PooledConnectionAndInfo info = pcMap.get(pc);
|
||||
if (info == null) {
|
||||
throw new IllegalStateException(NO_KEY_MESSAGE);
|
||||
}
|
||||
try {
|
||||
pool.invalidateObject(info.getUserPassKey(), info);
|
||||
} catch (final Exception e) {
|
||||
System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + info);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// ***********************************************************************
|
||||
// PooledConnectionManager implementation
|
||||
// ***********************************************************************
|
||||
|
||||
/**
|
||||
* Invalidates the PooledConnection in the pool. The KeyedCPDSConnectionFactory closes the connection and pool
|
||||
* counters are updated appropriately. Also clears any idle instances associated with the user name that was used to
|
||||
* create the PooledConnection. Connections associated with this user are not affected and they will not be
|
||||
* automatically closed on return to the pool.
|
||||
*/
|
||||
@Override
|
||||
public void invalidate(final PooledConnection pc) throws SQLException {
|
||||
final PooledConnectionAndInfo info = pcMap.get(pc);
|
||||
if (info == null) {
|
||||
throw new IllegalStateException(NO_KEY_MESSAGE);
|
||||
}
|
||||
final UserPassKey key = info.getUserPassKey();
|
||||
try {
|
||||
pool.invalidateObject(key, info); // Destroy and update pool counters
|
||||
pool.clear(key); // Remove any idle instances with this key
|
||||
} catch (final Exception ex) {
|
||||
throw new SQLException("Error invalidating connection", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing. This factory does not cache user credentials.
|
||||
*/
|
||||
@Override
|
||||
public void setPassword(final String password) {
|
||||
// Does nothing. This factory does not cache user credentials.
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
|
||||
* passivation and validation.
|
||||
*
|
||||
* @param maxConnLifetimeMillis
|
||||
* A value of zero or less indicates an infinite lifetime. The default value is -1.
|
||||
*/
|
||||
public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
|
||||
this.maxConnLifetimeMillis = maxConnLifetimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation does not fully close the KeyedObjectPool, as this would affect all users. Instead, it clears
|
||||
* the pool associated with the given user. This method is not currently used.
|
||||
*/
|
||||
@Override
|
||||
public void closePool(final String userName) throws SQLException {
|
||||
try {
|
||||
pool.clear(new UserPassKey(userName));
|
||||
} catch (final Exception ex) {
|
||||
throw new SQLException("Error closing connection pool", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLifetime(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
|
||||
if (maxConnLifetimeMillis > 0) {
|
||||
final long lifetime = System.currentTimeMillis() - p.getCreateTime();
|
||||
if (lifetime > maxConnLifetimeMillis) {
|
||||
throw new Exception(Utils.getMessage("connectionFactory.lifetimeExceeded", Long.valueOf(lifetime),
|
||||
Long.valueOf(maxConnLifetimeMillis)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.naming.RefAddr;
|
||||
import javax.naming.Reference;
|
||||
|
||||
/**
|
||||
* A JNDI ObjectFactory which creates <code>SharedPoolDataSource</code>s
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PerUserPoolDataSourceFactory extends InstanceKeyDataSourceFactory {
|
||||
private static final String PER_USER_POOL_CLASSNAME = PerUserPoolDataSource.class.getName();
|
||||
|
||||
@Override
|
||||
protected boolean isCorrectClass(final String className) {
|
||||
return PER_USER_POOL_CLASSNAME.equals(className);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Avoid warnings on deserialization
|
||||
@Override
|
||||
protected InstanceKeyDataSource getNewInstance(final Reference ref) throws IOException, ClassNotFoundException {
|
||||
final PerUserPoolDataSource pupds = new PerUserPoolDataSource();
|
||||
RefAddr ra = ref.get("defaultMaxTotal");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
pupds.setDefaultMaxTotal(Integer.parseInt(ra.getContent().toString()));
|
||||
}
|
||||
|
||||
ra = ref.get("defaultMaxIdle");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
pupds.setDefaultMaxIdle(Integer.parseInt(ra.getContent().toString()));
|
||||
}
|
||||
|
||||
ra = ref.get("defaultMaxWaitMillis");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
pupds.setDefaultMaxWaitMillis(Integer.parseInt(ra.getContent().toString()));
|
||||
}
|
||||
|
||||
ra = ref.get("perUserDefaultAutoCommit");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
final byte[] serialized = (byte[]) ra.getContent();
|
||||
pupds.setPerUserDefaultAutoCommit((Map<String, Boolean>) deserialize(serialized));
|
||||
}
|
||||
|
||||
ra = ref.get("perUserDefaultTransactionIsolation");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
final byte[] serialized = (byte[]) ra.getContent();
|
||||
pupds.setPerUserDefaultTransactionIsolation((Map<String, Integer>) deserialize(serialized));
|
||||
}
|
||||
|
||||
ra = ref.get("perUserMaxTotal");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
final byte[] serialized = (byte[]) ra.getContent();
|
||||
pupds.setPerUserMaxTotal((Map<String, Integer>) deserialize(serialized));
|
||||
}
|
||||
|
||||
ra = ref.get("perUserMaxIdle");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
final byte[] serialized = (byte[]) ra.getContent();
|
||||
pupds.setPerUserMaxIdle((Map<String, Integer>) deserialize(serialized));
|
||||
}
|
||||
|
||||
ra = ref.get("perUserMaxWaitMillis");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
final byte[] serialized = (byte[]) ra.getContent();
|
||||
pupds.setPerUserMaxWaitMillis((Map<String, Long>) deserialize(serialized));
|
||||
}
|
||||
|
||||
ra = ref.get("perUserDefaultReadOnly");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
final byte[] serialized = (byte[]) ra.getContent();
|
||||
pupds.setPerUserDefaultReadOnly((Map<String, Boolean>) deserialize(serialized));
|
||||
}
|
||||
return pupds;
|
||||
}
|
||||
}
|
||||
82
java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java
Normal file
82
java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
class PoolKey implements Serializable {
|
||||
private static final long serialVersionUID = 2252771047542484533L;
|
||||
|
||||
private final String dataSourceName;
|
||||
private final String userName;
|
||||
|
||||
PoolKey(final String dataSourceName, final String userName) {
|
||||
this.dataSourceName = dataSourceName;
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final PoolKey other = (PoolKey) obj;
|
||||
if (dataSourceName == null) {
|
||||
if (other.dataSourceName != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!dataSourceName.equals(other.dataSourceName)) {
|
||||
return false;
|
||||
}
|
||||
if (userName == null) {
|
||||
if (other.userName != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!userName.equals(other.userName)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((dataSourceName == null) ? 0 : dataSourceName.hashCode());
|
||||
result = prime * result + ((userName == null) ? 0 : userName.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer(50);
|
||||
sb.append("PoolKey(");
|
||||
sb.append(userName).append(", ").append(dataSourceName);
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import javax.sql.PooledConnection;
|
||||
|
||||
import org.apache.tomcat.dbcp.dbcp2.Utils;
|
||||
|
||||
/**
|
||||
* Immutable poolable object holding a PooledConnection along with the user name and password used to create the
|
||||
* connection.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
final class PooledConnectionAndInfo {
|
||||
private final PooledConnection pooledConnection;
|
||||
private final char[] userPassword;
|
||||
private final String userName;
|
||||
private final UserPassKey upKey;
|
||||
|
||||
/**
|
||||
* @since 2.4.0
|
||||
*/
|
||||
PooledConnectionAndInfo(final PooledConnection pc, final String userName, final char[] userPassword) {
|
||||
this.pooledConnection = pc;
|
||||
this.userName = userName;
|
||||
this.userPassword = userPassword;
|
||||
this.upKey = new UserPassKey(userName, userPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Since 2.4.0
|
||||
*/
|
||||
@Deprecated
|
||||
PooledConnectionAndInfo(final PooledConnection pc, final String userName, final String userPassword) {
|
||||
this(pc, userName, Utils.toCharArray(userPassword));
|
||||
}
|
||||
|
||||
PooledConnection getPooledConnection() {
|
||||
return pooledConnection;
|
||||
}
|
||||
|
||||
UserPassKey getUserPassKey() {
|
||||
return upKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of password.
|
||||
*
|
||||
* @return value of password.
|
||||
*/
|
||||
String getPassword() {
|
||||
return Utils.toString(userPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of password.
|
||||
*
|
||||
* @return value of password.
|
||||
* @since 2.4.0
|
||||
*/
|
||||
char[] getPasswordCharArray() {
|
||||
return userPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of userName.
|
||||
*
|
||||
* @return value of userName.
|
||||
*/
|
||||
String getUsername() {
|
||||
return userName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.PooledConnection;
|
||||
|
||||
/**
|
||||
* Methods to manage PoolableConnections and the connection pools that source them.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
interface PooledConnectionManager {
|
||||
|
||||
/**
|
||||
* Closes the PooledConnection and remove it from the connection pool to which it belongs, adjusting pool counters.
|
||||
*
|
||||
* @param pc
|
||||
* PooledConnection to be invalidated
|
||||
* @throws SQLException
|
||||
* if an SQL error occurs closing the connection
|
||||
*/
|
||||
void invalidate(PooledConnection pc) throws SQLException;
|
||||
|
||||
// /**
|
||||
// * Sets the database password used when creating connections.
|
||||
// *
|
||||
// * @param password password used when authenticating to the database
|
||||
// * @since 3.0.0
|
||||
// */
|
||||
// void setPassword(char[] password);
|
||||
|
||||
/**
|
||||
* Sets the database password used when creating connections.
|
||||
*
|
||||
* @param password
|
||||
* password used when authenticating to the database
|
||||
*/
|
||||
void setPassword(String password);
|
||||
|
||||
/**
|
||||
* Closes the connection pool associated with the given user.
|
||||
*
|
||||
* @param userName
|
||||
* user name
|
||||
* @throws SQLException
|
||||
* if an error occurs closing idle connections in the pool
|
||||
*/
|
||||
void closePool(String userName) throws SQLException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.StringRefAddr;
|
||||
import javax.sql.ConnectionPoolDataSource;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
|
||||
import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPool;
|
||||
import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A pooling <code>DataSource</code> appropriate for deployment within J2EE environment. There are many configuration
|
||||
* options, most of which are defined in the parent class. All users (based on user name) share a single maximum number
|
||||
* of Connections in this data source.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* User passwords can be changed without re-initializing the data source. When a
|
||||
* <code>getConnection(user name, password)</code> request is processed with a password that is different from those
|
||||
* used to create connections in the pool associated with <code>user name</code>, an attempt is made to create a new
|
||||
* connection using the supplied password and if this succeeds, idle connections created using the old password are
|
||||
* destroyed and new connections are created using the new password.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SharedPoolDataSource extends InstanceKeyDataSource {
|
||||
|
||||
private static final long serialVersionUID = -1458539734480586454L;
|
||||
|
||||
// Pool properties
|
||||
private int maxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
|
||||
|
||||
private transient KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> pool;
|
||||
private transient KeyedCPDSConnectionFactory factory;
|
||||
|
||||
/**
|
||||
* Default no-argument constructor for Serialization
|
||||
*/
|
||||
public SharedPoolDataSource() {
|
||||
// empty.
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes pool being maintained by this data source.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (pool != null) {
|
||||
pool.close();
|
||||
}
|
||||
InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Properties
|
||||
|
||||
/**
|
||||
* Gets {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
|
||||
*
|
||||
* @return {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
|
||||
*/
|
||||
public int getMaxTotal() {
|
||||
return this.maxTotal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
|
||||
*
|
||||
* @param maxTotal
|
||||
* {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
|
||||
*/
|
||||
public void setMaxTotal(final int maxTotal) {
|
||||
assertInitializationAllowed();
|
||||
this.maxTotal = maxTotal;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Instrumentation Methods
|
||||
|
||||
/**
|
||||
* Gets the number of active connections in the pool.
|
||||
*
|
||||
* @return The number of active connections in the pool.
|
||||
*/
|
||||
public int getNumActive() {
|
||||
return pool == null ? 0 : pool.getNumActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of idle connections in the pool.
|
||||
*
|
||||
* @return The number of idle connections in the pool.
|
||||
*/
|
||||
public int getNumIdle() {
|
||||
return pool == null ? 0 : pool.getNumIdle();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Inherited abstract methods
|
||||
|
||||
@Override
|
||||
protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String userPassword)
|
||||
throws SQLException {
|
||||
|
||||
synchronized (this) {
|
||||
if (pool == null) {
|
||||
try {
|
||||
registerPool(userName, userPassword);
|
||||
} catch (final NamingException e) {
|
||||
throw new SQLException("RegisterPool failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PooledConnectionAndInfo info = null;
|
||||
|
||||
final UserPassKey key = new UserPassKey(userName, userPassword);
|
||||
|
||||
try {
|
||||
info = pool.borrowObject(key);
|
||||
} catch (final Exception e) {
|
||||
throw new SQLException("Could not retrieve connection info from pool", e);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PooledConnectionManager getConnectionManager(final UserPassKey upkey) {
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>SharedPoolDataSource</code> {@link Reference}.
|
||||
*/
|
||||
@Override
|
||||
public Reference getReference() throws NamingException {
|
||||
final Reference ref = new Reference(getClass().getName(), SharedPoolDataSourceFactory.class.getName(), null);
|
||||
ref.add(new StringRefAddr("instanceKey", getInstanceKey()));
|
||||
return ref;
|
||||
}
|
||||
|
||||
private void registerPool(final String userName, final String password) throws NamingException, SQLException {
|
||||
|
||||
final ConnectionPoolDataSource cpds = testCPDS(userName, password);
|
||||
|
||||
// Create an object pool to contain our PooledConnections
|
||||
factory = new KeyedCPDSConnectionFactory(cpds, getValidationQuery(), getValidationQueryTimeout(),
|
||||
isRollbackAfterValidation());
|
||||
factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
|
||||
|
||||
final GenericKeyedObjectPoolConfig<PooledConnectionAndInfo> config = new GenericKeyedObjectPoolConfig<>();
|
||||
config.setBlockWhenExhausted(getDefaultBlockWhenExhausted());
|
||||
config.setEvictionPolicyClassName(getDefaultEvictionPolicyClassName());
|
||||
config.setLifo(getDefaultLifo());
|
||||
config.setMaxIdlePerKey(getDefaultMaxIdle());
|
||||
config.setMaxTotal(getMaxTotal());
|
||||
config.setMaxTotalPerKey(getDefaultMaxTotal());
|
||||
config.setMaxWaitMillis(getDefaultMaxWaitMillis());
|
||||
config.setMinEvictableIdleTimeMillis(getDefaultMinEvictableIdleTimeMillis());
|
||||
config.setMinIdlePerKey(getDefaultMinIdle());
|
||||
config.setNumTestsPerEvictionRun(getDefaultNumTestsPerEvictionRun());
|
||||
config.setSoftMinEvictableIdleTimeMillis(getDefaultSoftMinEvictableIdleTimeMillis());
|
||||
config.setTestOnCreate(getDefaultTestOnCreate());
|
||||
config.setTestOnBorrow(getDefaultTestOnBorrow());
|
||||
config.setTestOnReturn(getDefaultTestOnReturn());
|
||||
config.setTestWhileIdle(getDefaultTestWhileIdle());
|
||||
config.setTimeBetweenEvictionRunsMillis(getDefaultTimeBetweenEvictionRunsMillis());
|
||||
|
||||
final KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> tmpPool = new GenericKeyedObjectPool<>(factory,
|
||||
config);
|
||||
factory.setPool(tmpPool);
|
||||
pool = tmpPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupDefaults(final Connection connection, final String userName) throws SQLException {
|
||||
final Boolean defaultAutoCommit = isDefaultAutoCommit();
|
||||
if (defaultAutoCommit != null && connection.getAutoCommit() != defaultAutoCommit.booleanValue()) {
|
||||
connection.setAutoCommit(defaultAutoCommit.booleanValue());
|
||||
}
|
||||
|
||||
final int defaultTransactionIsolation = getDefaultTransactionIsolation();
|
||||
if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) {
|
||||
connection.setTransactionIsolation(defaultTransactionIsolation);
|
||||
}
|
||||
|
||||
final Boolean defaultReadOnly = isDefaultReadOnly();
|
||||
if (defaultReadOnly != null && connection.isReadOnly() != defaultReadOnly.booleanValue()) {
|
||||
connection.setReadOnly(defaultReadOnly.booleanValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports Serialization interface.
|
||||
*
|
||||
* @param in
|
||||
* a <code>java.io.ObjectInputStream</code> value
|
||||
* @throws IOException
|
||||
* if an error occurs
|
||||
* @throws ClassNotFoundException
|
||||
* if an error occurs
|
||||
*/
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
try {
|
||||
in.defaultReadObject();
|
||||
final SharedPoolDataSource oldDS = (SharedPoolDataSource) new SharedPoolDataSourceFactory()
|
||||
.getObjectInstance(getReference(), null, null, null);
|
||||
this.pool = oldDS.pool;
|
||||
} catch (final NamingException e) {
|
||||
throw new IOException("NamingException: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toStringFields(final StringBuilder builder) {
|
||||
super.toStringFields(builder);
|
||||
builder.append(", maxTotal=");
|
||||
builder.append(maxTotal);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import javax.naming.RefAddr;
|
||||
import javax.naming.Reference;
|
||||
|
||||
/**
|
||||
* A JNDI ObjectFactory which creates <code>SharedPoolDataSource</code>s
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SharedPoolDataSourceFactory extends InstanceKeyDataSourceFactory {
|
||||
private static final String SHARED_POOL_CLASSNAME = SharedPoolDataSource.class.getName();
|
||||
|
||||
@Override
|
||||
protected boolean isCorrectClass(final String className) {
|
||||
return SHARED_POOL_CLASSNAME.equals(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceKeyDataSource getNewInstance(final Reference ref) {
|
||||
final SharedPoolDataSource spds = new SharedPoolDataSource();
|
||||
final RefAddr ra = ref.get("maxTotal");
|
||||
if (ra != null && ra.getContent() != null) {
|
||||
spds.setMaxTotal(Integer.parseInt(ra.getContent().toString()));
|
||||
}
|
||||
return spds;
|
||||
}
|
||||
}
|
||||
134
java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java
Normal file
134
java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.tomcat.dbcp.dbcp2.Utils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Holds a user name and password pair. Serves as a poolable object key for the KeyedObjectPool backing a
|
||||
* SharedPoolDataSource. Two instances with the same user name are considered equal. This ensures that there will be
|
||||
* only one keyed pool for each user in the pool. The password is used (along with the user name) by the
|
||||
* KeyedCPDSConnectionFactory when creating new connections.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* {@link InstanceKeyDataSource#getConnection(String, String)} validates that the password used to create a connection
|
||||
* matches the password provided by the client.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
class UserPassKey implements Serializable {
|
||||
private static final long serialVersionUID = 5142970911626584817L;
|
||||
private final String userName;
|
||||
private final char[] userPassword;
|
||||
|
||||
/**
|
||||
* @since 2.4.0
|
||||
*/
|
||||
UserPassKey(final String userName) {
|
||||
this(userName, (char[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.4.0
|
||||
*/
|
||||
UserPassKey(final String userName, final char[] password) {
|
||||
this.userName = userName;
|
||||
this.userPassword = password;
|
||||
}
|
||||
|
||||
UserPassKey(final String userName, final String userPassword) {
|
||||
this(userName, Utils.toCharArray(userPassword));
|
||||
}
|
||||
|
||||
/**
|
||||
* Only takes the user name into account.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final UserPassKey other = (UserPassKey) obj;
|
||||
if (userName == null) {
|
||||
if (other.userName != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!userName.equals(other.userName)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of password.
|
||||
*
|
||||
* @return value of password.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return Utils.toString(userPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of password.
|
||||
*
|
||||
* @return value of password.
|
||||
*/
|
||||
public char[] getPasswordCharArray() {
|
||||
return userPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of user name.
|
||||
*
|
||||
* @return value of user name.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only takes the user name into account.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((userName == null) ? 0 : userName.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer(super.toString());
|
||||
sb.append("[");
|
||||
sb.append(userName);
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
183
java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java
Normal file
183
java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This package contains two DataSources: <code>PerUserPoolDataSource</code> and
|
||||
* <code>SharedPoolDataSource</code> which provide a database connection pool.
|
||||
* Below are a couple of usage examples. One shows deployment into a JNDI system.
|
||||
* The other is a simple example initializing the pool using standard java code.
|
||||
* </p>
|
||||
*
|
||||
* <h2>JNDI</h2>
|
||||
*
|
||||
* <p>
|
||||
* Most
|
||||
* J2EE containers will provide some way of deploying resources into JNDI. The
|
||||
* method will vary among containers, but once the resource is available via
|
||||
* JNDI, the application can access the resource in a container independent
|
||||
* manner. The following example shows deployment into tomcat (catalina).
|
||||
* </p>
|
||||
* <p>In server.xml, the following would be added to the <Context> for your
|
||||
* webapp:
|
||||
* </p>
|
||||
*
|
||||
* <code>
|
||||
* <Resource name="jdbc/bookstore" auth="Container"
|
||||
* type="org.apache.tomcat.dbcp.dbcp2.datasources.PerUserPoolPoolDataSource"/>
|
||||
* <ResourceParams name="jdbc/bookstore">
|
||||
* <parameter>
|
||||
* <name>factory</name>
|
||||
* <value>org.apache.tomcat.dbcp.dbcp2.datasources.PerUserPoolDataSourceFactory</value>
|
||||
* </parameter>
|
||||
* <parameter>
|
||||
* <name>dataSourceName</name><value>java:comp/env/jdbc/bookstoreCPDS</value>
|
||||
* </parameter>
|
||||
* <parameter>
|
||||
* <name>defaultMaxTotal</name><value>30</value>
|
||||
* </parameter>
|
||||
* </ResourceParams>
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* In web.xml. Note that elements must be given in the order of the dtd
|
||||
* described in the servlet specification:
|
||||
* </p>
|
||||
*
|
||||
* <code>
|
||||
* <resource-ref>
|
||||
* <description>
|
||||
* Resource reference to a factory for java.sql.Connection
|
||||
* instances that may be used for talking to a particular
|
||||
* database that is configured in the server.xml file.
|
||||
* </description>
|
||||
* <res-ref-name>
|
||||
* jdbc/bookstore
|
||||
* </res-ref-name>
|
||||
* <res-type>
|
||||
* org.apache.tomcat.dbcp.dbcp2.datasources.PerUserPoolDataSource
|
||||
* </res-type>
|
||||
* <res-auth>
|
||||
* Container
|
||||
* </res-auth>
|
||||
* </resource-ref>
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* Apache Tomcat deploys all objects configured similarly to above within the
|
||||
* <strong>java:comp/env</strong> namespace. So the JNDI path given for
|
||||
* the dataSourceName parameter is valid for a
|
||||
* <code>ConnectionPoolDataSource</code> that is deployed as given in the
|
||||
* <a href="../cpdsadapter/package.html">cpdsadapter example</a>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The <code>DataSource</code> is now available to the application as shown
|
||||
* below:
|
||||
* </p>
|
||||
*
|
||||
* <code>
|
||||
*
|
||||
* Context ctx = new InitialContext();
|
||||
* DataSource ds = (DataSource)
|
||||
* ctx.lookup("java:comp/env/jdbc/bookstore");
|
||||
* Connection con = null;
|
||||
* try
|
||||
* {
|
||||
* con = ds.getConnection();
|
||||
* ...
|
||||
* use the connection
|
||||
* ...
|
||||
* }
|
||||
* finally
|
||||
* {
|
||||
* if (con != null)
|
||||
* con.close();
|
||||
* }
|
||||
*
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* The reference to the <code>DataSource</code> could be maintained, for
|
||||
* multiple getConnection() requests. Or the <code>DataSource</code> can be
|
||||
* looked up in different parts of the application code.
|
||||
* <code>PerUserPoolDataSourceFactory</code> and
|
||||
* <code>SharedPoolDataSourceFactory</code> will maintain the state of the pool
|
||||
* between different lookups. This behavior may be different in other
|
||||
* implementations.
|
||||
* </p>
|
||||
*
|
||||
* <h2>Without JNDI</h2>
|
||||
*
|
||||
* <p>
|
||||
* Connection pooling is useful in applications regardless of whether they run
|
||||
* in a J2EE environment and a <code>DataSource</code> can be used within a
|
||||
* simpler environment. The example below shows SharedPoolDataSource using
|
||||
* DriverAdapterCPDS as the backend source, though any CPDS is applicable.
|
||||
* </p>
|
||||
*
|
||||
* <code>
|
||||
*
|
||||
* public class Pool
|
||||
* {
|
||||
* private static DataSource ds;
|
||||
*
|
||||
* static
|
||||
* {
|
||||
* DriverAdapterCPDS cpds = new DriverAdapterCPDS();
|
||||
* cpds.setDriver("org.gjt.mm.mysql.Driver");
|
||||
* cpds.setUrl("jdbc:mysql://localhost:3306/bookstore");
|
||||
* cpds.setUser("foo");
|
||||
* cpds.setPassword(null);
|
||||
*
|
||||
* SharedPoolDataSource tds = new SharedPoolDataSource();
|
||||
* tds.setConnectionPoolDataSource(cpds);
|
||||
* tds.setMaxTotal(10);
|
||||
* tds.setMaxWaitMillis(50);
|
||||
*
|
||||
* ds = tds;
|
||||
* }
|
||||
*
|
||||
* public static getConnection()
|
||||
* {
|
||||
* return ds.getConnection();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* This class can then be used wherever a connection is needed:
|
||||
* </p>
|
||||
*
|
||||
* <code>
|
||||
* Connection con = null;
|
||||
* try
|
||||
* {
|
||||
* con = Pool.getConnection();
|
||||
* ...
|
||||
* use the connection
|
||||
* ...
|
||||
* }
|
||||
* finally
|
||||
* {
|
||||
* if (con != null)
|
||||
* con.close();
|
||||
* }
|
||||
* </code>
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2.datasources;
|
||||
131
java/org/apache/tomcat/dbcp/dbcp2/package-info.java
Normal file
131
java/org/apache/tomcat/dbcp/dbcp2/package-info.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Database Connection Pool API.
|
||||
* </p>
|
||||
*
|
||||
* <b>Overview in Dialog Form</b>
|
||||
* <p>
|
||||
* Q: How do I use the DBCP package?
|
||||
* </p>
|
||||
* <p>
|
||||
* A: There are two primary ways to access the DBCP pool, as a {@link java.sql.Driver Driver}, or as a
|
||||
* {@link javax.sql.DataSource DataSource}. You'll want to create an instance of
|
||||
* {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver} or {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource}. When using one
|
||||
* of these interfaces, you can just use your JDBC objects the way you normally would. Closing a
|
||||
* {@link java.sql.Connection} will simply return it to its pool.
|
||||
* </p>
|
||||
* <p>
|
||||
* Q: But {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver PoolingDriver} and
|
||||
* {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource PoolingDataSource} both expect an
|
||||
* {@link org.apache.tomcat.dbcp.pool2.ObjectPool ObjectPool} as an input. Where do I get one of those?
|
||||
* </p>
|
||||
* <p>
|
||||
* A: The {@link org.apache.tomcat.dbcp.pool2.ObjectPool ObjectPool} interface is defined in Commons Pool. You can use one
|
||||
* of the provided implementations such as {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool} or
|
||||
* {@link org.apache.tomcat.dbcp.pool2.impl.SoftReferenceObjectPool SoftReferenceObjectPool} or you can create your own.
|
||||
* </p>
|
||||
* <p>
|
||||
* Q: Ok, I've found an {@link org.apache.tomcat.dbcp.pool2.ObjectPool ObjectPool} implementation that I think suits my
|
||||
* connection pooling needs. But it wants a {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory PooledObjectFactory}.
|
||||
* What should I use for that?
|
||||
* </p>
|
||||
* <p>
|
||||
* A: The DBCP package provides a class for this purpose. It's called
|
||||
* {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory}. It implements the factory and lifecycle methods of
|
||||
* {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory} for {@link java.sql.Connection}s. But it doesn't create the
|
||||
* actual database {@link java.sql.Connection}s itself, it uses a {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} for
|
||||
* that. The {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory} will take {@link java.sql.Connection}s created
|
||||
* by the {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} and wrap them with classes that implement the pooling
|
||||
* behaviour.
|
||||
* </p>
|
||||
* <p>
|
||||
* Several implementations of {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} are provided--one that uses
|
||||
* {@link java.sql.DriverManager} to create connections
|
||||
* ({@link org.apache.tomcat.dbcp.dbcp2.DriverManagerConnectionFactory}), one that uses a {@link java.sql.Driver} to create
|
||||
* connections ({@link org.apache.tomcat.dbcp.dbcp2.DriverConnectionFactory}), one that uses a {@link javax.sql.DataSource}
|
||||
* to create connections ({@link org.apache.tomcat.dbcp.dbcp2.DataSourceConnectionFactory}).
|
||||
* </p>
|
||||
* <p>
|
||||
* Q: I think I'm starting to get it, but can you walk me though it again?
|
||||
* </p>
|
||||
* <p>
|
||||
* A: Sure. Let's assume you want to create a {@link javax.sql.DataSource} that pools {@link java.sql.Connection}s.
|
||||
* Let's also assume that those pooled {@link java.sql.Connection}s should be obtained from the
|
||||
* {@link java.sql.DriverManager}. You'll want to create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource}.
|
||||
* </p>
|
||||
* <p>
|
||||
* The {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource} uses an underlying {@link org.apache.tomcat.dbcp.pool2.ObjectPool}
|
||||
* to create and store its {@link java.sql.Connection}.
|
||||
* </p>
|
||||
* <p>
|
||||
* To create a {@link org.apache.tomcat.dbcp.pool2.ObjectPool}, you'll need a
|
||||
* {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory} that creates the actual {@link java.sql.Connection}s. That's
|
||||
* what {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory} is for.
|
||||
* </p>
|
||||
* <p>
|
||||
* To create the {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory}, you'll need at least two things:
|
||||
* </p>
|
||||
* <ol>
|
||||
* <li>A {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} from which the actual database {@link java.sql.Connection}s
|
||||
* will be obtained.</li>
|
||||
* <li>An empty and factory-less {@link org.apache.tomcat.dbcp.pool2.ObjectPool} in which the {@link java.sql.Connection}s
|
||||
* will be stored. <br>
|
||||
* When you pass an {@link org.apache.tomcat.dbcp.pool2.ObjectPool} into the
|
||||
* {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory}, it will automatically register itself as the
|
||||
* {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory} for that pool.</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* In code, that might look like this:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* GenericObjectPool connectionPool = new GenericObjectPool(null);
|
||||
* ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string", "userName",
|
||||
* "password");
|
||||
* PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,
|
||||
* connectionPool, null, null, false, true);
|
||||
* PoolingDataSource dataSource = new PoolingDataSource(connectionPool);
|
||||
* </pre>
|
||||
* <p>
|
||||
* To create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver}, we do the same thing, except that instead of creating a
|
||||
* {@link javax.sql.DataSource} on the last line, we create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver}, and
|
||||
* register the {@code connectionPool} with it. E.g.,:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* GenericObjectPool connectionPool = new GenericObjectPool(null);
|
||||
* ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string", "userName",
|
||||
* "password");
|
||||
* PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,
|
||||
* connectionPool, null, null, false, true);
|
||||
* PoolingDriver driver = new PoolingDriver();
|
||||
* driver.registerPool("example", connectionPool);
|
||||
* </pre>
|
||||
* <p>
|
||||
* Since the {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver} registers itself with the {@link java.sql.DriverManager}
|
||||
* when it is created, now you can just go to the {@link java.sql.DriverManager} to create your
|
||||
* {@link java.sql.Connection}s, like you normally would:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* Connection conn = DriverManager.getConnection("jdbc:apache:commons:dbcp:example");
|
||||
* </pre>
|
||||
*/
|
||||
package org.apache.tomcat.dbcp.dbcp2;
|
||||
Reference in New Issue
Block a user