init
This commit is contained in:
60
java/org/apache/tomcat/ContextBind.java
Normal file
60
java/org/apache/tomcat/ContextBind.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface ContextBind {
|
||||
|
||||
/**
|
||||
* Change the current thread context class loader to the web application
|
||||
* class loader. If no web application class loader is defined, or if the
|
||||
* current thread is already using the web application class loader then no
|
||||
* change will be made. If the class loader is changed and a
|
||||
* {@link org.apache.catalina.ThreadBindingListener} is configured then
|
||||
* {@link org.apache.catalina.ThreadBindingListener#bind()} will be called
|
||||
* after the change has been made.
|
||||
*
|
||||
* @param usePrivilegedAction
|
||||
* Should a {@link java.security.PrivilegedAction} be used when
|
||||
* obtaining the current thread context class loader and setting
|
||||
* the new one?
|
||||
* @param originalClassLoader
|
||||
* The current class loader if known to save this method having to
|
||||
* look it up
|
||||
*
|
||||
* @return If the class loader has been changed by the method it will return
|
||||
* the thread context class loader in use when the method was
|
||||
* called. If no change was made then this method returns null.
|
||||
*/
|
||||
ClassLoader bind(boolean usePrivilegedAction, ClassLoader originalClassLoader);
|
||||
|
||||
/**
|
||||
* Restore the current thread context class loader to the original class
|
||||
* loader in used before {@link #bind(boolean, ClassLoader)} was called. If
|
||||
* no original class loader is passed to this method then no change will be
|
||||
* made. If the class loader is changed and a
|
||||
* {@link org.apache.catalina.ThreadBindingListener} is configured then
|
||||
* {@link org.apache.catalina.ThreadBindingListener#unbind()} will be called
|
||||
* before the change is made.
|
||||
*
|
||||
* @param usePrivilegedAction
|
||||
* Should a {@link java.security.PrivilegedAction} be used when
|
||||
* setting the current thread context class loader?
|
||||
* @param originalClassLoader
|
||||
* The class loader to restore as the thread context class loader
|
||||
*/
|
||||
void unbind(boolean usePrivilegedAction, ClassLoader originalClassLoader);
|
||||
}
|
||||
42
java/org/apache/tomcat/InstanceManager.java
Normal file
42
java/org/apache/tomcat/InstanceManager.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
public interface InstanceManager {
|
||||
|
||||
Object newInstance(Class<?> clazz) throws IllegalAccessException, InvocationTargetException,
|
||||
NamingException, InstantiationException, IllegalArgumentException,
|
||||
NoSuchMethodException, SecurityException;
|
||||
|
||||
Object newInstance(String className) throws IllegalAccessException, InvocationTargetException,
|
||||
NamingException, InstantiationException, ClassNotFoundException,
|
||||
IllegalArgumentException, NoSuchMethodException, SecurityException;
|
||||
|
||||
Object newInstance(String fqcn, ClassLoader classLoader) throws IllegalAccessException,
|
||||
InvocationTargetException, NamingException, InstantiationException,
|
||||
ClassNotFoundException, IllegalArgumentException, NoSuchMethodException,
|
||||
SecurityException;
|
||||
|
||||
void newInstance(Object o)
|
||||
throws IllegalAccessException, InvocationTargetException, NamingException;
|
||||
|
||||
void destroyInstance(Object o) throws IllegalAccessException, InvocationTargetException;
|
||||
}
|
||||
35
java/org/apache/tomcat/InstanceManagerBindings.java
Normal file
35
java/org/apache/tomcat/InstanceManagerBindings.java
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public final class InstanceManagerBindings {
|
||||
|
||||
private static final Map<ClassLoader, InstanceManager> bindings = new ConcurrentHashMap<>();
|
||||
|
||||
public static final void bind(ClassLoader classLoader, InstanceManager instanceManager) {
|
||||
bindings.put(classLoader, instanceManager);
|
||||
}
|
||||
public static final void unbind(ClassLoader classLoader) {
|
||||
bindings.remove(classLoader);
|
||||
}
|
||||
public static final InstanceManager get(ClassLoader classLoader) {
|
||||
return bindings.get(classLoader);
|
||||
}
|
||||
}
|
||||
78
java/org/apache/tomcat/InstrumentableClassLoader.java
Normal file
78
java/org/apache/tomcat/InstrumentableClassLoader.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
|
||||
/**
|
||||
* Specifies a class loader capable of being decorated with
|
||||
* {@link ClassFileTransformer}s. These transformers can instrument
|
||||
* (or weave) the byte code of classes loaded through this class loader
|
||||
* to alter their behavior. Currently only
|
||||
* {@link org.apache.catalina.loader.WebappClassLoaderBase} implements this
|
||||
* interface. This allows web application frameworks or JPA providers
|
||||
* bundled with a web application to instrument web application classes
|
||||
* as necessary.
|
||||
* <p>
|
||||
* You should always program against the methods of this interface
|
||||
* (whether using reflection or otherwise). The methods in
|
||||
* {@code WebappClassLoaderBase} are protected by the default security
|
||||
* manager if one is in use.
|
||||
*
|
||||
* @since 8.0, 7.0.64
|
||||
*/
|
||||
public interface InstrumentableClassLoader {
|
||||
|
||||
/**
|
||||
* Adds the specified class file transformer to this class loader. The
|
||||
* transformer will then be able to instrument the bytecode of any
|
||||
* classes loaded by this class loader after the invocation of this
|
||||
* method.
|
||||
*
|
||||
* @param transformer The transformer to add to the class loader
|
||||
* @throws IllegalArgumentException if the {@literal transformer} is null.
|
||||
*/
|
||||
void addTransformer(ClassFileTransformer transformer);
|
||||
|
||||
/**
|
||||
* Removes the specified class file transformer from this class loader.
|
||||
* It will no longer be able to instrument the byte code of any classes
|
||||
* loaded by the class loader after the invocation of this method.
|
||||
* However, any classes already instrumented by this transformer before
|
||||
* this method call will remain in their instrumented state.
|
||||
*
|
||||
* @param transformer The transformer to remove
|
||||
*/
|
||||
void removeTransformer(ClassFileTransformer transformer);
|
||||
|
||||
/**
|
||||
* Returns a copy of this class loader without any class file
|
||||
* transformers. This is a tool often used by Java Persistence API
|
||||
* providers to inspect entity classes in the absence of any
|
||||
* instrumentation, something that can't be guaranteed within the
|
||||
* context of a {@link ClassFileTransformer}'s
|
||||
* {@link ClassFileTransformer#transform(ClassLoader, String, Class,
|
||||
* java.security.ProtectionDomain, byte[]) transform} method.
|
||||
* <p>
|
||||
* The returned class loader's resource cache will have been cleared
|
||||
* so that classes already instrumented will not be retained or
|
||||
* returned.
|
||||
*
|
||||
* @return the transformer-free copy of this class loader.
|
||||
*/
|
||||
ClassLoader copyWithoutTransformers();
|
||||
}
|
||||
151
java/org/apache/tomcat/Jar.java
Normal file
151
java/org/apache/tomcat/Jar.java
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* Provides an abstraction for use by the various classes that need to scan
|
||||
* JARs. The classes provided by the JRE for accessing JARs
|
||||
* ({@link java.util.jar.JarFile} and {@link java.util.jar.JarInputStream}) have
|
||||
* significantly different performance characteristics depending on the form of
|
||||
* the URL used to access the JAR. For file based JAR {@link java.net.URL}s,
|
||||
* {@link java.util.jar.JarFile} is faster but for non-file based
|
||||
* {@link java.net.URL}s, {@link java.util.jar.JarFile} creates a copy of the
|
||||
* JAR in the temporary directory so {@link java.util.jar.JarInputStream} is
|
||||
* faster.
|
||||
*/
|
||||
public interface Jar extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* @return The URL for accessing the JAR file.
|
||||
*/
|
||||
URL getJarFileURL();
|
||||
|
||||
/**
|
||||
* Determines if a specific entry exists within the JAR.
|
||||
*
|
||||
* @param name Entry to look for
|
||||
* @return Implementations will always return {@code false}
|
||||
*
|
||||
* @throws IOException if an I/O error occurs while processing the JAR file
|
||||
* entries
|
||||
*
|
||||
* @deprecated Unused. This will be removed in Tomcat 9 onwards.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean entryExists(String name) throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Obtain an {@link InputStream} for a given entry in a JAR. The caller is
|
||||
* responsible for closing the stream.
|
||||
*
|
||||
* @param name Entry to obtain an {@link InputStream} for
|
||||
* @return An {@link InputStream} for the specified entry or null if
|
||||
* the entry does not exist
|
||||
*
|
||||
* @throws IOException if an I/O error occurs while processing the JAR file
|
||||
*/
|
||||
InputStream getInputStream(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Obtain the last modified time for the given resource in the JAR.
|
||||
*
|
||||
* @param name Entry to obtain the modification time for
|
||||
*
|
||||
* @return The time (in the same format as
|
||||
* {@link System#currentTimeMillis()} that the resource was last
|
||||
* modified. Returns -1 if the entry does not exist
|
||||
*
|
||||
* @throws IOException if an I/O error occurs while processing the JAR file
|
||||
*/
|
||||
long getLastModified(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Determine if the given resource in present in the JAR.
|
||||
*
|
||||
* @param name Entry to look for
|
||||
*
|
||||
* @return {@code true} if the entry is present in the JAR, otherwise
|
||||
* {@code false}
|
||||
*
|
||||
* @throws IOException if an I/O error occurs while processing the JAR file
|
||||
*/
|
||||
boolean exists(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Close any resources associated with this JAR.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Moves the internal pointer to the next entry in the JAR.
|
||||
*/
|
||||
void nextEntry();
|
||||
|
||||
/**
|
||||
* Obtains the name of the current entry.
|
||||
*
|
||||
* @return The entry name
|
||||
*/
|
||||
String getEntryName();
|
||||
|
||||
/**
|
||||
* Obtains the input stream for the current entry.
|
||||
*
|
||||
* @return The input stream
|
||||
* @throws IOException If the stream cannot be obtained
|
||||
*/
|
||||
InputStream getEntryInputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Obtain, in String form, the URL for an entry in this JAR. Note that for
|
||||
* JARs nested in WAR files, the Tomcat specific war:file:... form will not
|
||||
* be used, rather the jar:jar:file:... form (that the JRE does not
|
||||
* understand will be used). Note that this means that any code using these
|
||||
* URLs will need to understand the jar:jar:file:... form and use the
|
||||
* {@link org.apache.tomcat.util.scan.JarFactory} to ensure resources are
|
||||
* accessed correctly.
|
||||
*
|
||||
* @param entry The entry to generate the URL for
|
||||
*
|
||||
* @return a URL for the specified entry in the JAR
|
||||
*/
|
||||
String getURL(String entry);
|
||||
|
||||
/**
|
||||
* Obtain the manifest for the JAR file.
|
||||
*
|
||||
* @return The manifest for this JAR file.
|
||||
*
|
||||
* @throws IOException If an I/O error occurs trying to obtain the manifest
|
||||
*/
|
||||
Manifest getManifest() throws IOException;
|
||||
|
||||
/**
|
||||
* Resets the internal pointer used to track JAR entries to the beginning of
|
||||
* the JAR.
|
||||
*
|
||||
* @throws IOException If the pointer cannot be reset
|
||||
*/
|
||||
void reset() throws IOException;
|
||||
}
|
||||
31
java/org/apache/tomcat/JarScanFilter.java
Normal file
31
java/org/apache/tomcat/JarScanFilter.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface JarScanFilter {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param jarScanType The type of JAR scan currently being performed
|
||||
* @param jarName The name of the JAR file (without any path
|
||||
* information) to be checked to see if it should
|
||||
* be included in the results or not
|
||||
* @return <code>true</code> if the JAR should be returned in the results,
|
||||
* <code>false</code> if it should be excluded
|
||||
*/
|
||||
boolean check(JarScanType jarScanType, String jarName);
|
||||
}
|
||||
23
java/org/apache/tomcat/JarScanType.java
Normal file
23
java/org/apache/tomcat/JarScanType.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public enum JarScanType {
|
||||
TLD,
|
||||
PLUGGABILITY,
|
||||
OTHER
|
||||
}
|
||||
45
java/org/apache/tomcat/JarScanner.java
Normal file
45
java/org/apache/tomcat/JarScanner.java
Normal file
@@ -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;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
/**
|
||||
* Scans a web application and classloader hierarchy for JAR files. Uses
|
||||
* include TLD scanning and web-fragment.xml scanning. Uses a call-back
|
||||
* mechanism so the caller can process each JAR found.
|
||||
*/
|
||||
public interface JarScanner {
|
||||
|
||||
/**
|
||||
* Scan the provided ServletContext and classloader for JAR files. Each JAR
|
||||
* file found will be passed to the callback handler to be processed.
|
||||
*
|
||||
* @param scanType The type of JAR scan to perform. This is passed to
|
||||
* the filter which uses it to determine how to
|
||||
* filter the results
|
||||
* @param context The ServletContext - used to locate and access
|
||||
* WEB-INF/lib
|
||||
* @param callback The handler to process any JARs found
|
||||
*/
|
||||
public void scan(JarScanType scanType, ServletContext context,
|
||||
JarScannerCallback callback);
|
||||
|
||||
public JarScanFilter getJarScanFilter();
|
||||
|
||||
public void setJarScanFilter(JarScanFilter jarScanFilter);
|
||||
}
|
||||
67
java/org/apache/tomcat/JarScannerCallback.java
Normal file
67
java/org/apache/tomcat/JarScannerCallback.java
Normal file
@@ -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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This interface is implemented by clients of the {@link JarScanner} to enable
|
||||
* them to receive notification of a discovered JAR.
|
||||
*/
|
||||
public interface JarScannerCallback {
|
||||
|
||||
/**
|
||||
* A JAR was found and may be accessed for further processing via the
|
||||
* provided URL connection. The caller is responsible for closing the JAR.
|
||||
*
|
||||
* @param jar The JAR to process
|
||||
* @param webappPath The path, if any, to the JAR within the web application
|
||||
* @param isWebapp Indicates if the JAR was found within a web
|
||||
* application. If <code>false</code> the JAR should
|
||||
* be treated as being provided by the container
|
||||
*
|
||||
* @throws IOException if an I/O error occurs while scanning the JAR
|
||||
*/
|
||||
public void scan(Jar jar, String webappPath, boolean isWebapp)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* A directory was found that is to be treated as an unpacked JAR. The
|
||||
* directory may be accessed for further processing via the provided file.
|
||||
*
|
||||
* @param file The directory containing the unpacked JAR.
|
||||
* @param webappPath The path, if any, to the file within the web
|
||||
* application
|
||||
* @param isWebapp Indicates if the JAR was found within a web
|
||||
* application. If <code>false</code> the JAR should
|
||||
* be treated as being provided by the container
|
||||
*
|
||||
* @throws IOException if an I/O error occurs while scanning the JAR
|
||||
*/
|
||||
public void scan(File file, String webappPath, boolean isWebapp) throws IOException;
|
||||
|
||||
/**
|
||||
* A directory structure was found within the web application at
|
||||
* /WEB-INF/classes that should be handled as an unpacked JAR. Note that all
|
||||
* resource access must be via the ServletContext to ensure that any
|
||||
* additional resources are visible.
|
||||
*
|
||||
* @throws IOException if an I/O error occurs while scanning WEB-INF/classes
|
||||
*/
|
||||
public void scanWebInfClasses() throws IOException;
|
||||
}
|
||||
25
java/org/apache/tomcat/PeriodicEventListener.java
Normal file
25
java/org/apache/tomcat/PeriodicEventListener.java
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface PeriodicEventListener {
|
||||
/**
|
||||
* Execute a periodic task, such as reloading, etc.
|
||||
*/
|
||||
public void periodicEvent();
|
||||
}
|
||||
68
java/org/apache/tomcat/SimpleInstanceManager.java
Normal file
68
java/org/apache/tomcat/SimpleInstanceManager.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
|
||||
/**
|
||||
* SimpleInstanceManager
|
||||
*
|
||||
* Implement the org.apache.tomcat.InstanceManager interface.
|
||||
*/
|
||||
public class SimpleInstanceManager implements InstanceManager {
|
||||
|
||||
public SimpleInstanceManager() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object newInstance(Class<?> clazz) throws IllegalAccessException,
|
||||
InvocationTargetException, NamingException, InstantiationException, NoSuchMethodException {
|
||||
return prepareInstance(clazz.getConstructor().newInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object newInstance(String className) throws IllegalAccessException,
|
||||
InvocationTargetException, NamingException, InstantiationException,
|
||||
ClassNotFoundException, NoSuchMethodException {
|
||||
Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(className);
|
||||
return prepareInstance(clazz.getConstructor().newInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object newInstance(String fqcn, ClassLoader classLoader) throws IllegalAccessException,
|
||||
InvocationTargetException, NamingException, InstantiationException,
|
||||
ClassNotFoundException, NoSuchMethodException {
|
||||
Class<?> clazz = classLoader.loadClass(fqcn);
|
||||
return prepareInstance(clazz.getConstructor().newInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newInstance(Object o) throws IllegalAccessException, InvocationTargetException,
|
||||
NamingException {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyInstance(Object o) throws IllegalAccessException, InvocationTargetException {
|
||||
}
|
||||
|
||||
private Object prepareInstance(Object o) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
161
java/org/apache/tomcat/buildutil/CheckEol.java
Normal file
161
java/org/apache/tomcat/buildutil/CheckEol.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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.buildutil;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
import org.apache.tools.ant.Project;
|
||||
import org.apache.tools.ant.Task;
|
||||
import org.apache.tools.ant.types.FileSet;
|
||||
|
||||
/**
|
||||
* Ant task that checks that all the files in the given fileset have end-of-line
|
||||
* delimiters that are appropriate for the current OS.
|
||||
*
|
||||
* <p>
|
||||
* The goal is to check whether we have problems with svn:eol-style property
|
||||
* when files are committed on one OS and then checked on another one.
|
||||
*/
|
||||
public class CheckEol extends Task {
|
||||
|
||||
/** The files to be checked */
|
||||
private final List<FileSet> filesets = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Sets the files to be checked
|
||||
*
|
||||
* @param fs The fileset to be checked.
|
||||
*/
|
||||
public void addFileset( FileSet fs ) {
|
||||
filesets.add( fs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the check
|
||||
*
|
||||
* @throws BuildException if an error occurs during execution of
|
||||
* this task.
|
||||
*/
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
|
||||
Mode mode = null;
|
||||
if ("\n".equals(System.lineSeparator())) {
|
||||
mode = Mode.LF;
|
||||
} else if ("\r\n".equals(System.lineSeparator())) {
|
||||
mode = Mode.CRLF;
|
||||
} else {
|
||||
log("Line ends check skipped, because OS line ends setting is neither LF nor CRLF.",
|
||||
Project.MSG_VERBOSE);
|
||||
return;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
||||
List<CheckFailure> errors = new ArrayList<>();
|
||||
|
||||
// Step through each file and check.
|
||||
for (FileSet fs : filesets) {
|
||||
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
|
||||
File basedir = ds.getBasedir();
|
||||
String[] files = ds.getIncludedFiles();
|
||||
if (files.length > 0) {
|
||||
log("Checking line ends in " + files.length + " file(s)");
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File file = new File(basedir, files[i]);
|
||||
log("Checking file '" + file + "' for correct line ends",
|
||||
Project.MSG_DEBUG);
|
||||
try {
|
||||
check(file, errors, mode);
|
||||
} catch (IOException e) {
|
||||
throw new BuildException("Could not check file '"
|
||||
+ file.getAbsolutePath() + "'", e);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
log("Done line ends check in " + count + " file(s), "
|
||||
+ errors.size() + " error(s) found.");
|
||||
}
|
||||
if (errors.size() > 0) {
|
||||
String message = "The following files have wrong line ends: "
|
||||
+ errors;
|
||||
// We need to explicitly write the message to the log, because
|
||||
// long BuildException messages may be trimmed. E.g. I observed
|
||||
// this problem with Eclipse IDE 3.7.
|
||||
log(message, Project.MSG_ERR);
|
||||
throw new BuildException(message);
|
||||
}
|
||||
}
|
||||
|
||||
private enum Mode {
|
||||
LF, CRLF
|
||||
}
|
||||
|
||||
private static class CheckFailure {
|
||||
private final File file;
|
||||
private final int line;
|
||||
private final String value;
|
||||
|
||||
public CheckFailure(File file, int line, String value) {
|
||||
this.file = file;
|
||||
this.line = line;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return System.lineSeparator() + file + ": uses " + value + " on line " + line;
|
||||
}
|
||||
}
|
||||
|
||||
private void check(File file, List<CheckFailure> errors, Mode mode) throws IOException {
|
||||
try (FileInputStream fis = new FileInputStream(file);
|
||||
BufferedInputStream is = new BufferedInputStream(fis)) {
|
||||
int line = 1;
|
||||
int prev = -1;
|
||||
int ch;
|
||||
while ((ch = is.read()) != -1) {
|
||||
if (ch == '\n') {
|
||||
if (mode == Mode.LF && prev == '\r') {
|
||||
errors.add(new CheckFailure(file, line, "CRLF"));
|
||||
return;
|
||||
} else if (mode == Mode.CRLF && prev != '\r') {
|
||||
errors.add(new CheckFailure(file, line, "LF"));
|
||||
return;
|
||||
}
|
||||
line++;
|
||||
} else if (prev == '\r') {
|
||||
errors.add(new CheckFailure(file, line, "CR"));
|
||||
return;
|
||||
}
|
||||
prev = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
413
java/org/apache/tomcat/buildutil/SignCode.java
Normal file
413
java/org/apache/tomcat/buildutil/SignCode.java
Normal file
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* 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.buildutil;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import javax.xml.soap.MessageFactory;
|
||||
import javax.xml.soap.SOAPBody;
|
||||
import javax.xml.soap.SOAPConnection;
|
||||
import javax.xml.soap.SOAPConnectionFactory;
|
||||
import javax.xml.soap.SOAPConstants;
|
||||
import javax.xml.soap.SOAPElement;
|
||||
import javax.xml.soap.SOAPEnvelope;
|
||||
import javax.xml.soap.SOAPException;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
import javax.xml.soap.SOAPPart;
|
||||
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
import org.apache.tomcat.util.codec.binary.Base64;
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
import org.apache.tools.ant.Task;
|
||||
import org.apache.tools.ant.types.FileSet;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Ant task that submits a file to the Digicert (formally Symantec) code-signing
|
||||
* service. The service is defined by the published
|
||||
* <a href="https://api.ws.digicert.com/webtrust/SigningService?wsdl">WSDL</a>.
|
||||
* Note that while the service has migrated to a Digicert domain, the namespace
|
||||
* continues to use a Symantec domain.
|
||||
*/
|
||||
public class SignCode extends Task {
|
||||
|
||||
private static final URL SIGNING_SERVICE_URL;
|
||||
|
||||
private static final String NS = "cod";
|
||||
|
||||
private static final MessageFactory SOAP_MSG_FACTORY;
|
||||
|
||||
static {
|
||||
try {
|
||||
SIGNING_SERVICE_URL = new URL(
|
||||
"https://api-appsec.pki.digicert.com/webtrust/SigningService");
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
try {
|
||||
SOAP_MSG_FACTORY = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
|
||||
} catch (SOAPException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final List<FileSet> filesets = new ArrayList<>();
|
||||
private String userName;
|
||||
private String password;
|
||||
private String partnerCode;
|
||||
private String keyStore;
|
||||
private String keyStorePassword;
|
||||
private String applicationName;
|
||||
private String applicationVersion;
|
||||
private String signingService;
|
||||
private boolean debug;
|
||||
|
||||
public void addFileset(FileSet fileset) {
|
||||
filesets.add(fileset);
|
||||
}
|
||||
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
public void setPartnerCode(String partnerCode) {
|
||||
this.partnerCode = partnerCode;
|
||||
}
|
||||
|
||||
|
||||
public void setKeyStore(String keyStore) {
|
||||
this.keyStore = keyStore;
|
||||
}
|
||||
|
||||
|
||||
public void setKeyStorePassword(String keyStorePassword) {
|
||||
this.keyStorePassword = keyStorePassword;
|
||||
}
|
||||
|
||||
|
||||
public void setApplicationName(String applicationName) {
|
||||
this.applicationName = applicationName;
|
||||
}
|
||||
|
||||
|
||||
public void setApplicationVersion(String applicationVersion) {
|
||||
this.applicationVersion = applicationVersion;
|
||||
}
|
||||
|
||||
|
||||
public void setSigningService(String signingService) {
|
||||
this.signingService = signingService;
|
||||
}
|
||||
|
||||
|
||||
public void setDebug(String debug) {
|
||||
this.debug = Boolean.parseBoolean(debug);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
|
||||
List<File> filesToSign = new ArrayList<>();
|
||||
|
||||
// Process the filesets and populate the list of files that need to be
|
||||
// signed.
|
||||
for (FileSet fileset : filesets) {
|
||||
DirectoryScanner ds = fileset.getDirectoryScanner(getProject());
|
||||
File basedir = ds.getBasedir();
|
||||
String[] files = ds.getIncludedFiles();
|
||||
if (files.length > 0) {
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File file = new File(basedir, files[i]);
|
||||
filesToSign.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the TLS client
|
||||
System.setProperty("javax.net.ssl.keyStore", keyStore);
|
||||
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);
|
||||
|
||||
try {
|
||||
String signingSetID = makeSigningRequest(filesToSign);
|
||||
downloadSignedFiles(filesToSign, signingSetID);
|
||||
} catch (SOAPException | IOException e) {
|
||||
throw new BuildException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String makeSigningRequest(List<File> filesToSign) throws SOAPException, IOException {
|
||||
log("Constructing the code signing request");
|
||||
|
||||
SOAPMessage message = SOAP_MSG_FACTORY.createMessage();
|
||||
SOAPBody body = populateEnvelope(message, NS);
|
||||
|
||||
SOAPElement requestSigning = body.addChildElement("requestSigning", NS);
|
||||
SOAPElement requestSigningRequest =
|
||||
requestSigning.addChildElement("requestSigningRequest", NS);
|
||||
|
||||
addCredentials(requestSigningRequest, this.userName, this.password, this.partnerCode);
|
||||
|
||||
SOAPElement applicationName =
|
||||
requestSigningRequest.addChildElement("applicationName", NS);
|
||||
applicationName.addTextNode(this.applicationName);
|
||||
|
||||
SOAPElement applicationVersion =
|
||||
requestSigningRequest.addChildElement("applicationVersion", NS);
|
||||
applicationVersion.addTextNode(this.applicationVersion);
|
||||
|
||||
SOAPElement signingServiceName =
|
||||
requestSigningRequest.addChildElement("signingServiceName", NS);
|
||||
signingServiceName.addTextNode(this.signingService);
|
||||
|
||||
List<String> fileNames = getFileNames(filesToSign);
|
||||
|
||||
SOAPElement commaDelimitedFileNames =
|
||||
requestSigningRequest.addChildElement("commaDelimitedFileNames", NS);
|
||||
commaDelimitedFileNames.addTextNode(StringUtils.join(fileNames));
|
||||
|
||||
SOAPElement application =
|
||||
requestSigningRequest.addChildElement("application", NS);
|
||||
application.addTextNode(getApplicationString(fileNames, filesToSign));
|
||||
|
||||
// Send the message
|
||||
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
|
||||
SOAPConnection connection = soapConnectionFactory.createConnection();
|
||||
|
||||
log("Sending signing request to server and waiting for response");
|
||||
SOAPMessage response = connection.call(message, SIGNING_SERVICE_URL);
|
||||
|
||||
if (debug) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(2 * 1024);
|
||||
response.writeTo(baos);
|
||||
log(baos.toString("UTF-8"));
|
||||
}
|
||||
|
||||
log("Processing response");
|
||||
SOAPElement responseBody = response.getSOAPBody();
|
||||
|
||||
// Should come back signed
|
||||
NodeList bodyNodes = responseBody.getChildNodes();
|
||||
NodeList requestSigningResponseNodes = bodyNodes.item(0).getChildNodes();
|
||||
NodeList returnNodes = requestSigningResponseNodes.item(0).getChildNodes();
|
||||
|
||||
String signingSetID = null;
|
||||
String signingSetStatus = null;
|
||||
|
||||
for (int i = 0; i < returnNodes.getLength(); i++) {
|
||||
Node returnNode = returnNodes.item(i);
|
||||
if (returnNode.getLocalName().equals("signingSetID")) {
|
||||
signingSetID = returnNode.getTextContent();
|
||||
} else if (returnNode.getLocalName().equals("signingSetStatus")) {
|
||||
signingSetStatus = returnNode.getTextContent();
|
||||
}
|
||||
}
|
||||
|
||||
if (!signingService.contains("TEST") && !"SIGNED".equals(signingSetStatus) ||
|
||||
signingService.contains("TEST") && !"INITIALIZED".equals(signingSetStatus) ) {
|
||||
throw new BuildException("Signing failed. Status was: " + signingSetStatus);
|
||||
}
|
||||
|
||||
return signingSetID;
|
||||
}
|
||||
|
||||
|
||||
private void downloadSignedFiles(List<File> filesToSign, String id)
|
||||
throws SOAPException, IOException {
|
||||
|
||||
log("Downloading signed files. The signing set ID is: " + id);
|
||||
|
||||
SOAPMessage message = SOAP_MSG_FACTORY.createMessage();
|
||||
SOAPBody body = populateEnvelope(message, NS);
|
||||
|
||||
SOAPElement getSigningSetDetails = body.addChildElement("getSigningSetDetails", NS);
|
||||
SOAPElement getSigningSetDetailsRequest =
|
||||
getSigningSetDetails.addChildElement("getSigningSetDetailsRequest", NS);
|
||||
|
||||
addCredentials(getSigningSetDetailsRequest, this.userName, this.password, this.partnerCode);
|
||||
|
||||
SOAPElement signingSetID =
|
||||
getSigningSetDetailsRequest.addChildElement("signingSetID", NS);
|
||||
signingSetID.addTextNode(id);
|
||||
|
||||
SOAPElement returnApplication =
|
||||
getSigningSetDetailsRequest.addChildElement("returnApplication", NS);
|
||||
returnApplication.addTextNode("true");
|
||||
|
||||
// Send the message
|
||||
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
|
||||
SOAPConnection connection = soapConnectionFactory.createConnection();
|
||||
|
||||
log("Requesting signed files from server and waiting for response");
|
||||
SOAPMessage response = connection.call(message, SIGNING_SERVICE_URL);
|
||||
|
||||
log("Processing response");
|
||||
SOAPElement responseBody = response.getSOAPBody();
|
||||
|
||||
// Check for success
|
||||
|
||||
// Extract the signed file(s) from the ZIP
|
||||
NodeList bodyNodes = responseBody.getChildNodes();
|
||||
NodeList getSigningSetDetailsResponseNodes = bodyNodes.item(0).getChildNodes();
|
||||
NodeList returnNodes = getSigningSetDetailsResponseNodes.item(0).getChildNodes();
|
||||
|
||||
String result = null;
|
||||
String data = null;
|
||||
|
||||
for (int i = 0; i < returnNodes.getLength(); i++) {
|
||||
Node returnNode = returnNodes.item(i);
|
||||
if (returnNode.getLocalName().equals("result")) {
|
||||
result = returnNode.getChildNodes().item(0).getTextContent();
|
||||
} else if (returnNode.getLocalName().equals("signingSet")) {
|
||||
data = returnNode.getChildNodes().item(1).getTextContent();
|
||||
}
|
||||
}
|
||||
|
||||
if (!"0".equals(result)) {
|
||||
throw new BuildException("Download failed. Result code was: " + result);
|
||||
}
|
||||
|
||||
extractFilesFromApplicationString(data, filesToSign);
|
||||
}
|
||||
|
||||
|
||||
private static SOAPBody populateEnvelope(SOAPMessage message, String namespace)
|
||||
throws SOAPException {
|
||||
SOAPPart soapPart = message.getSOAPPart();
|
||||
SOAPEnvelope envelope = soapPart.getEnvelope();
|
||||
envelope.addNamespaceDeclaration(
|
||||
"soapenv","http://schemas.xmlsoap.org/soap/envelope/");
|
||||
envelope.addNamespaceDeclaration(
|
||||
namespace,"http://api.ws.symantec.com/webtrust/codesigningservice");
|
||||
return envelope.getBody();
|
||||
}
|
||||
|
||||
|
||||
private static void addCredentials(SOAPElement requestSigningRequest,
|
||||
String user, String pwd, String code) throws SOAPException {
|
||||
SOAPElement authToken = requestSigningRequest.addChildElement("authToken", NS);
|
||||
SOAPElement userName = authToken.addChildElement("userName", NS);
|
||||
userName.addTextNode(user);
|
||||
SOAPElement password = authToken.addChildElement("password", NS);
|
||||
password.addTextNode(pwd);
|
||||
SOAPElement partnerCode = authToken.addChildElement("partnerCode", NS);
|
||||
partnerCode.addTextNode(code);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Signing service requires unique files names. Since files will be returned
|
||||
* in order, use dummy names that we know are unique but retain the file
|
||||
* extension since the signing service appears to use it to figure out what
|
||||
* to sign and how to sign it.
|
||||
*/
|
||||
private static List<String> getFileNames(List<File> filesToSign) {
|
||||
List<String> result = new ArrayList<>(filesToSign.size());
|
||||
|
||||
for (int i = 0; i < filesToSign.size(); i++) {
|
||||
File f = filesToSign.get(i);
|
||||
String fileName = f.getName();
|
||||
int extIndex = fileName.lastIndexOf('.');
|
||||
String newName;
|
||||
if (extIndex < 0) {
|
||||
newName = Integer.toString(i);
|
||||
} else {
|
||||
newName = Integer.toString(i) + fileName.substring(extIndex);
|
||||
}
|
||||
result.add(newName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Zips the files, base 64 encodes the resulting zip and then returns the
|
||||
* string. It would be far more efficient to stream this directly to the
|
||||
* signing server but the files that need to be signed are relatively small
|
||||
* and this simpler to write.
|
||||
*
|
||||
* @param fileNames Modified names of files
|
||||
* @param files Files to be signed
|
||||
*/
|
||||
private static String getApplicationString(List<String> fileNames, List<File> files)
|
||||
throws IOException {
|
||||
// 16 MB should be more than enough for Tomcat
|
||||
// TODO: Refactoring this entire class so it uses streaming rather than
|
||||
// buffering the entire set of files in memory would make it more
|
||||
// widely useful.
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(16 * 1024 * 1024);
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
byte[] buf = new byte[32 * 1024];
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
try (FileInputStream fis = new FileInputStream(files.get(i))) {
|
||||
ZipEntry zipEntry = new ZipEntry(fileNames.get(i));
|
||||
zos.putNextEntry(zipEntry);
|
||||
int numRead;
|
||||
while ( (numRead = fis.read(buf)) >= 0) {
|
||||
zos.write(buf, 0, numRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Base64.encodeBase64String(baos.toByteArray());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes base64 encoding, unzips the files and writes the new files over
|
||||
* the top of the old ones.
|
||||
*/
|
||||
private static void extractFilesFromApplicationString(String data, List<File> files)
|
||||
throws IOException {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decodeBase64(data));
|
||||
try (ZipInputStream zis = new ZipInputStream(bais)) {
|
||||
byte[] buf = new byte[32 * 1024];
|
||||
for (int i = 0; i < files.size(); i ++) {
|
||||
try (FileOutputStream fos = new FileOutputStream(files.get(i))) {
|
||||
zis.getNextEntry();
|
||||
int numRead;
|
||||
while ( (numRead = zis.read(buf)) >= 0) {
|
||||
fos.write(buf, 0 , numRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
179
java/org/apache/tomcat/buildutil/Txt2Html.java
Normal file
179
java/org/apache/tomcat/buildutil/Txt2Html.java
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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.buildutil;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
import org.apache.tools.ant.Project;
|
||||
import org.apache.tools.ant.Task;
|
||||
import org.apache.tools.ant.types.FileSet;
|
||||
|
||||
/**
|
||||
* Ant task to convert a given set of files from Text to HTML.
|
||||
* Inserts an HTML header including pre tags and replaces special characters
|
||||
* with their HTML escaped equivalents.
|
||||
*
|
||||
* <p>This task is currently used by the ant script to build our examples</p>
|
||||
*
|
||||
* @author Mark Roth
|
||||
*/
|
||||
public class Txt2Html
|
||||
extends Task
|
||||
{
|
||||
|
||||
/** The directory to contain the resulting files */
|
||||
private File todir;
|
||||
|
||||
/** The file to be converted into HTML */
|
||||
private final List<FileSet> filesets = new LinkedList<>();
|
||||
|
||||
/**
|
||||
* The encoding of the source files (.java and .jsp). Once they use
|
||||
* UTF-8, this will need to be updated.
|
||||
*/
|
||||
private static final String SOURCE_ENCODING = "ISO-8859-1";
|
||||
|
||||
/**
|
||||
* Line terminator to be used for separating lines of the generated
|
||||
* HTML page, to be independent from "line.separator" system property.
|
||||
*/
|
||||
private static final String LINE_SEPARATOR = "\r\n";
|
||||
|
||||
/**
|
||||
* Sets the directory to contain the resulting files
|
||||
*
|
||||
* @param todir The directory
|
||||
*/
|
||||
public void setTodir( File todir ) {
|
||||
this.todir = todir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the files to be converted into HTML
|
||||
*
|
||||
* @param fs The fileset to be converted.
|
||||
*/
|
||||
public void addFileset( FileSet fs ) {
|
||||
filesets.add( fs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the conversion
|
||||
*
|
||||
* @throws BuildException if an error occurs during execution of
|
||||
* this task.
|
||||
*/
|
||||
@Override
|
||||
public void execute()
|
||||
throws BuildException
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
// Step through each file and convert.
|
||||
for (FileSet fs : filesets) {
|
||||
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
|
||||
File basedir = ds.getBasedir();
|
||||
String[] files = ds.getIncludedFiles();
|
||||
for( int i = 0; i < files.length; i++ ) {
|
||||
File from = new File( basedir, files[i] );
|
||||
File to = new File( todir, files[i] + ".html" );
|
||||
if( !to.exists() ||
|
||||
(from.lastModified() > to.lastModified()) )
|
||||
{
|
||||
log( "Converting file '" + from.getAbsolutePath() +
|
||||
"' to '" + to.getAbsolutePath(), Project.MSG_VERBOSE );
|
||||
try {
|
||||
convert( from, to );
|
||||
}
|
||||
catch( IOException e ) {
|
||||
throw new BuildException( "Could not convert '" +
|
||||
from.getAbsolutePath() + "' to '" +
|
||||
to.getAbsolutePath() + "'", e );
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if( count > 0 ) {
|
||||
log( "Converted " + count + " file" + (count > 1 ? "s" : "") +
|
||||
" to " + todir.getAbsolutePath() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual copy and conversion
|
||||
*
|
||||
* @param from The input file
|
||||
* @param to The output file
|
||||
* @throws IOException Thrown if an error occurs during the conversion
|
||||
*/
|
||||
private void convert( File from, File to )
|
||||
throws IOException
|
||||
{
|
||||
// Open files:
|
||||
try (BufferedReader in = new BufferedReader(new InputStreamReader(
|
||||
new FileInputStream(from), SOURCE_ENCODING))) {
|
||||
try (PrintWriter out = new PrintWriter(new OutputStreamWriter(
|
||||
new FileOutputStream(to), "UTF-8"))) {
|
||||
|
||||
// Output header:
|
||||
out.print("<!DOCTYPE html><html><head><meta charset=\"UTF-8\" />"
|
||||
+ "<title>Source Code</title></head><body><pre>" );
|
||||
|
||||
// Convert, line-by-line:
|
||||
String line;
|
||||
while( (line = in.readLine()) != null ) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
int len = line.length();
|
||||
for( int i = 0; i < len; i++ ) {
|
||||
char c = line.charAt( i );
|
||||
switch( c ) {
|
||||
case '&':
|
||||
result.append( "&" );
|
||||
break;
|
||||
case '<':
|
||||
result.append( "<" );
|
||||
break;
|
||||
default:
|
||||
result.append( c );
|
||||
}
|
||||
}
|
||||
out.print( result.toString() + LINE_SEPARATOR );
|
||||
}
|
||||
|
||||
// Output footer:
|
||||
out.print( "</pre></body></html>" );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
65
java/org/apache/tomcat/buildutil/translate/BackportBase.java
Normal file
65
java/org/apache/tomcat/buildutil/translate/BackportBase.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.buildutil.translate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Base class providing common implementation for back-port utilities.
|
||||
*/
|
||||
public abstract class BackportBase {
|
||||
|
||||
protected final Map<String,Properties> sourceTranslations = new HashMap<>();
|
||||
protected final Map<String,Properties> targetTranslations = new HashMap<>();
|
||||
protected final File targetRoot;
|
||||
protected final Properties sourceEnglish;
|
||||
protected final Properties targetEnglish;
|
||||
protected final File storageDir;
|
||||
|
||||
protected BackportBase(String... args) throws IOException {
|
||||
if (args.length != 1) {
|
||||
throw new IllegalArgumentException("Missing back-port target");
|
||||
}
|
||||
targetRoot = new File(args[0]);
|
||||
|
||||
if (!targetRoot.isDirectory()) {
|
||||
throw new IllegalArgumentException("Back-port target not a directory");
|
||||
}
|
||||
|
||||
File sourceRoot = new File(".");
|
||||
for (String dir : Constants.SEARCH_DIRS) {
|
||||
File directory = new File(dir);
|
||||
Utils.processDirectory(sourceRoot, directory, sourceTranslations);
|
||||
}
|
||||
|
||||
for (String dir : Constants.SEARCH_DIRS) {
|
||||
File directory = new File(targetRoot, dir);
|
||||
Utils.processDirectory(targetRoot, directory, targetTranslations);
|
||||
}
|
||||
|
||||
sourceEnglish = sourceTranslations.get("");
|
||||
targetEnglish = targetTranslations.get("");
|
||||
|
||||
storageDir = new File(targetRoot, Constants.STORAGE_DIR);
|
||||
}
|
||||
|
||||
protected abstract void execute() throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.buildutil.translate;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Generates a set of English property files to back-port updates to a previous
|
||||
* version. Where a key exists in the source and target versions the value is
|
||||
* copied from the source to the target, overwriting the value in the target.
|
||||
* The expectation is that the changes will be manually reviewed before
|
||||
* committing them.
|
||||
*/
|
||||
public class BackportEnglish extends BackportBase {
|
||||
|
||||
public static void main(String... args) throws IOException {
|
||||
BackportEnglish backport = new BackportEnglish(args);
|
||||
backport.execute();
|
||||
}
|
||||
|
||||
|
||||
protected BackportEnglish(String[] args) throws IOException {
|
||||
super(args);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void execute() throws IOException {
|
||||
for (Object key : sourceEnglish.keySet()) {
|
||||
if (targetEnglish.containsKey(key)) {
|
||||
targetEnglish.put(key, sourceEnglish.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
Utils.export("", targetEnglish, storageDir);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.buildutil.translate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Generates a set of translated property files to back-port updates to a
|
||||
* previous version. If the source and target use the same value for the English
|
||||
* key then any translated value for that key is copied from the source to the
|
||||
* target.
|
||||
*/
|
||||
public class BackportTranslations extends BackportBase {
|
||||
|
||||
public static void main(String... args) throws IOException {
|
||||
BackportTranslations backport = new BackportTranslations(args);
|
||||
backport.execute();
|
||||
}
|
||||
|
||||
protected BackportTranslations(String[] args) throws IOException {
|
||||
super(args);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void execute() throws IOException {
|
||||
for (String langauge : targetTranslations.keySet()) {
|
||||
// Skip source
|
||||
if (langauge.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Properties sourceTranslated = sourceTranslations.get(langauge);
|
||||
Properties targetTranslated = targetTranslations.get(langauge);
|
||||
if (targetTranslated == null) {
|
||||
targetTranslated = new Properties();
|
||||
targetTranslations.put(langauge, targetTranslated);
|
||||
}
|
||||
|
||||
for (Object key : targetEnglish.keySet()) {
|
||||
if (sourceTranslated.containsKey(key) &&
|
||||
targetEnglish.get(key).equals(sourceEnglish.get(key))) {
|
||||
|
||||
targetTranslated.put(key, sourceTranslated.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
// Remove translated values for keys that have been removed
|
||||
Iterator<Map.Entry<Object,Object>> iter = targetTranslated.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<Object,Object> entry = iter.next();
|
||||
if (!targetEnglish.containsKey(entry.getKey())) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
Utils.export(langauge, targetTranslated, storageDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
java/org/apache/tomcat/buildutil/translate/Constants.java
Normal file
29
java/org/apache/tomcat/buildutil/translate/Constants.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.buildutil.translate;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String L10N_PREFIX = "LocalStrings";
|
||||
public static final String L10N_SUFFIX = ".properties";
|
||||
|
||||
public static final String[] SEARCH_DIRS = new String[] { "java", "webapps" };
|
||||
|
||||
public static final String STORAGE_DIR = ".settings/translations";
|
||||
|
||||
public static final String END_PACKAGE_MARKER = ".zzz.";
|
||||
}
|
||||
133
java/org/apache/tomcat/buildutil/translate/Import.java
Normal file
133
java/org/apache/tomcat/buildutil/translate/Import.java
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.buildutil.translate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
public class Import {
|
||||
|
||||
public static void main(String... args) throws IOException {
|
||||
File root = new File(Constants.STORAGE_DIR);
|
||||
|
||||
for (File f : root.listFiles()) {
|
||||
// Not robust but good enough
|
||||
if (f.isFile() && f.getName().startsWith(Constants.L10N_PREFIX)) {
|
||||
processFile(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private static void processFile(File f) throws IOException {
|
||||
String language = Utils.getLanguage(f.getName());
|
||||
|
||||
// Unlike the master branch, don't skip the original so we can import
|
||||
// updates to the English translations
|
||||
Properties props = Utils.load(f);
|
||||
Object[] objKeys = props.keySet().toArray();
|
||||
Arrays.sort(objKeys);
|
||||
|
||||
String currentPkg = null;
|
||||
Writer w = null;
|
||||
String currentGroup = "zzz";
|
||||
|
||||
for (Object objKey : objKeys) {
|
||||
String key = (String) objKey;
|
||||
CompositeKey cKey = new CompositeKey(key);
|
||||
|
||||
if (!cKey.pkg.equals(currentPkg)) {
|
||||
currentPkg = cKey.pkg;
|
||||
if (w != null) {
|
||||
w.close();
|
||||
}
|
||||
File outFile = new File(currentPkg.replace('.', File.separatorChar), Constants.L10N_PREFIX + language + Constants.L10N_SUFFIX);
|
||||
FileOutputStream fos = new FileOutputStream(outFile);
|
||||
w = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
|
||||
insertLicense(w);
|
||||
}
|
||||
|
||||
if (!currentGroup.equals(cKey.group)) {
|
||||
currentGroup = cKey.group;
|
||||
w.write(System.lineSeparator());
|
||||
}
|
||||
|
||||
w.write(cKey.key + "=" + Utils.formatValue(props.getProperty(key)));
|
||||
w.write(System.lineSeparator());
|
||||
}
|
||||
if (w != null) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void insertLicense(Writer w) throws IOException {
|
||||
w.write("# Licensed to the Apache Software Foundation (ASF) under one or more");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# contributor license agreements. See the NOTICE file distributed with");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# this work for additional information regarding copyright ownership.");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# The ASF licenses this file to You under the Apache License, Version 2.0");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# (the \"License\"); you may not use this file except in compliance with");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# the License. You may obtain a copy of the License at");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("#");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# http://www.apache.org/licenses/LICENSE-2.0");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("#");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# Unless required by applicable law or agreed to in writing, software");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# distributed under the License is distributed on an \"AS IS\" BASIS,");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# See the License for the specific language governing permissions and");
|
||||
w.write(System.lineSeparator());
|
||||
w.write("# limitations under the License.");
|
||||
w.write(System.lineSeparator());
|
||||
}
|
||||
private static class CompositeKey {
|
||||
|
||||
public final String pkg;
|
||||
public final String key;
|
||||
public final String group;
|
||||
|
||||
public CompositeKey(String in) {
|
||||
int posPkg = in.indexOf(Constants.END_PACKAGE_MARKER);
|
||||
pkg = in.substring(0, posPkg);
|
||||
key = in.substring(posPkg + Constants.END_PACKAGE_MARKER.length());
|
||||
int posGroup = key.indexOf('.');
|
||||
if (posGroup == -1) {
|
||||
group = "";
|
||||
} else {
|
||||
group = key.substring(0, posGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
149
java/org/apache/tomcat/buildutil/translate/Utils.java
Normal file
149
java/org/apache/tomcat/buildutil/translate/Utils.java
Normal file
@@ -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.buildutil.translate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Utils {
|
||||
|
||||
private static final Pattern ADD_CONTINUATION = Pattern.compile("\\n", Pattern.MULTILINE);
|
||||
private static final Pattern ESCAPE_LEADING_SPACE = Pattern.compile("^(\\s)", Pattern.MULTILINE);
|
||||
private static final Pattern FIX_SINGLE_QUOTE = Pattern.compile("(?<!')'(?!')", Pattern.MULTILINE);
|
||||
|
||||
private Utils() {
|
||||
// Utility class. Hide default constructor.
|
||||
}
|
||||
|
||||
|
||||
static String getLanguage(String name) {
|
||||
return name.substring(Constants.L10N_PREFIX.length(), name.length() - Constants.L10N_SUFFIX.length());
|
||||
}
|
||||
|
||||
|
||||
static Properties load(File f) {
|
||||
Properties props = new Properties();
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(f);
|
||||
Reader r = new InputStreamReader(fis, StandardCharsets.UTF_8)) {
|
||||
props.load(r);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
|
||||
static String formatValue(String in) {
|
||||
String result = ADD_CONTINUATION.matcher(in).replaceAll("\\\\n\\\\\n");
|
||||
if (result.endsWith("\\\n")) {
|
||||
result = result.substring(0, result.length() - 2);
|
||||
}
|
||||
result = ESCAPE_LEADING_SPACE.matcher(result).replaceAll("\\\\$1");
|
||||
|
||||
if (result.contains("\n\\\t")) {
|
||||
result = result.replace("\n\\\t", "\n\\t");
|
||||
}
|
||||
|
||||
if (result.contains("[{0}]")) {
|
||||
result = FIX_SINGLE_QUOTE.matcher(result).replaceAll("''");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void processDirectory(File root, File dir, Map<String,Properties> translations) throws IOException {
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null) {
|
||||
throw new IllegalArgumentException("Not a directory [" + dir.getAbsolutePath() + "]");
|
||||
}
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
processDirectory(root, f, translations);
|
||||
} else if (f.isFile()) {
|
||||
processFile(root, f, translations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void processFile(File root, File f, Map<String,Properties> translations) throws IOException {
|
||||
String name = f.getName();
|
||||
|
||||
// non-l10n files
|
||||
if (!name.startsWith(Constants.L10N_PREFIX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine language
|
||||
String language = Utils.getLanguage(name);
|
||||
|
||||
String keyPrefix = getKeyPrefix(root, f);
|
||||
Properties props = Utils.load(f);
|
||||
|
||||
// Create a Map for the language if one does not exist.
|
||||
Properties translation = translations.get(language);
|
||||
if (translation == null) {
|
||||
translation = new Properties();
|
||||
translations.put(language, translation);
|
||||
}
|
||||
|
||||
// Add the properties from this file to the combined file, prefixing the
|
||||
// key with the package name to ensure uniqueness.
|
||||
for (Object obj : props.keySet()) {
|
||||
String key = (String) obj;
|
||||
String value = props.getProperty(key);
|
||||
|
||||
translation.put(keyPrefix + key, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static String getKeyPrefix(File root, File f) throws IOException {
|
||||
String prefix = f.getParentFile().getCanonicalPath();
|
||||
prefix = prefix.substring(root.getCanonicalPath().length() + 1);
|
||||
prefix = prefix.replace(File.separatorChar, '.');
|
||||
prefix = prefix + Constants.END_PACKAGE_MARKER;
|
||||
return prefix;
|
||||
}
|
||||
|
||||
|
||||
static void export(String language, Properties translation, File storageDir) {
|
||||
File out = new File(storageDir, Constants.L10N_PREFIX + language + Constants.L10N_SUFFIX);
|
||||
try (FileOutputStream fos = new FileOutputStream(out);
|
||||
Writer w = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
|
||||
String[] keys = translation.keySet().toArray(new String[0]);
|
||||
Arrays.sort(keys);
|
||||
for (Object key : keys) {
|
||||
w.write(key + "=" + Utils.formatValue(translation.getProperty((String) key)) + "\n");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
/**
|
||||
* A base implementation of <code>KeyedPooledObjectFactory</code>.
|
||||
* <p>
|
||||
* All operations defined here are essentially no-op's.
|
||||
* </p>
|
||||
* <p>
|
||||
* This class is immutable, and therefore thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @see KeyedPooledObjectFactory
|
||||
*
|
||||
* @param <K> The type of keys managed by this factory.
|
||||
* @param <V> Type of element managed by this factory.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class BaseKeyedPooledObjectFactory<K, V> extends BaseObject
|
||||
implements KeyedPooledObjectFactory<K, V> {
|
||||
|
||||
/**
|
||||
* Create an instance that can be served by the pool.
|
||||
*
|
||||
* @param key the key used when constructing the object
|
||||
* @return an instance that can be served by the pool
|
||||
*
|
||||
* @throws Exception if there is a problem creating a new instance,
|
||||
* this will be propagated to the code requesting an object.
|
||||
*/
|
||||
public abstract V create(K key)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Wrap the provided instance with an implementation of
|
||||
* {@link PooledObject}.
|
||||
*
|
||||
* @param value the instance to wrap
|
||||
*
|
||||
* @return The provided instance, wrapped by a {@link PooledObject}
|
||||
*/
|
||||
public abstract PooledObject<V> wrap(V value);
|
||||
|
||||
@Override
|
||||
public PooledObject<V> makeObject(final K key) throws Exception {
|
||||
return wrap(create(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy an instance no longer needed by the pool.
|
||||
* <p>
|
||||
* The default implementation is a no-op.
|
||||
* </p>
|
||||
*
|
||||
* @param key the key used when selecting the instance
|
||||
* @param p a {@code PooledObject} wrapping the instance to be destroyed
|
||||
*/
|
||||
@Override
|
||||
public void destroyObject(final K key, final PooledObject<V> p)
|
||||
throws Exception {
|
||||
// The default implementation is a no-op.
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the instance is safe to be returned by the pool.
|
||||
* <p>
|
||||
* The default implementation always returns {@code true}.
|
||||
* </p>
|
||||
*
|
||||
* @param key the key used when selecting the object
|
||||
* @param p a {@code PooledObject} wrapping the instance to be validated
|
||||
* @return always <code>true</code> in the default implementation
|
||||
*/
|
||||
@Override
|
||||
public boolean validateObject(final K key, final PooledObject<V> p) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinitialize an instance to be returned by the pool.
|
||||
* <p>
|
||||
* The default implementation is a no-op.
|
||||
* </p>
|
||||
*
|
||||
* @param key the key used when selecting the object
|
||||
* @param p a {@code PooledObject} wrapping the instance to be activated
|
||||
*/
|
||||
@Override
|
||||
public void activateObject(final K key, final PooledObject<V> p)
|
||||
throws Exception {
|
||||
// The default implementation is a no-op.
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninitialize an instance to be returned to the idle object pool.
|
||||
* <p>
|
||||
* The default implementation is a no-op.
|
||||
* </p>
|
||||
*
|
||||
* @param key the key used when selecting the object
|
||||
* @param p a {@code PooledObject} wrapping the instance to be passivated
|
||||
*/
|
||||
@Override
|
||||
public void passivateObject(final K key, final PooledObject<V> p)
|
||||
throws Exception {
|
||||
// The default implementation is a no-op.
|
||||
}
|
||||
}
|
||||
45
java/org/apache/tomcat/dbcp/pool2/BaseObject.java
Normal file
45
java/org/apache/tomcat/dbcp/pool2/BaseObject.java
Normal file
@@ -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.pool2;
|
||||
|
||||
/**
|
||||
* A base class for common functionality.
|
||||
*
|
||||
* @since 2.4.3
|
||||
*/
|
||||
public abstract class BaseObject {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append(getClass().getSimpleName());
|
||||
builder.append(" [");
|
||||
toStringAppendFields(builder);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by sub-classes to include the fields defined by the sub-class in the
|
||||
* {@link #toString()} output.
|
||||
*
|
||||
* @param builder Field names and values are appended to this object
|
||||
*/
|
||||
protected void toStringAppendFields(final StringBuilder builder) {
|
||||
// do nothing by default, needed for b/w compatibility.
|
||||
}
|
||||
}
|
||||
144
java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
Normal file
144
java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
/**
|
||||
* A simple base implementation of {@link ObjectPool}.
|
||||
* Optional operations are implemented to either do nothing, return a value
|
||||
* indicating it is unsupported or throw {@link UnsupportedOperationException}.
|
||||
* <p>
|
||||
* This class is intended to be thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> Type of element pooled in this pool.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class BaseObjectPool<T> extends BaseObject implements ObjectPool<T> {
|
||||
|
||||
@Override
|
||||
public abstract T borrowObject() throws Exception;
|
||||
|
||||
@Override
|
||||
public abstract void returnObject(T obj) throws Exception;
|
||||
|
||||
@Override
|
||||
public abstract void invalidateObject(T obj) throws Exception;
|
||||
|
||||
/**
|
||||
* Not supported in this base implementation.
|
||||
*
|
||||
* @return a negative value.
|
||||
*/
|
||||
@Override
|
||||
public int getNumIdle() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported in this base implementation.
|
||||
*
|
||||
* @return a negative value.
|
||||
*/
|
||||
@Override
|
||||
public int getNumActive() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported in this base implementation.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the pool does not implement this
|
||||
* method
|
||||
*/
|
||||
@Override
|
||||
public void clear() throws Exception, UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported in this base implementation. Subclasses should override
|
||||
* this behavior.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the pool does not implement this
|
||||
* method
|
||||
*/
|
||||
@Override
|
||||
public void addObject() throws Exception, UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link ObjectPool#addObject()} <code>count</code>
|
||||
* number of times.
|
||||
*
|
||||
* @param count
|
||||
* the number of idle objects to add.
|
||||
* @throws Exception
|
||||
* when {@link ObjectPool#addObject()} fails.
|
||||
* @since 2.8.0
|
||||
*/
|
||||
@Override
|
||||
public void addObjects(final int count) throws Exception {
|
||||
for (int i = 0; i < count; i++) {
|
||||
addObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* This affects the behavior of <code>isClosed</code> and
|
||||
* <code>assertOpen</code>.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this pool instance been closed.
|
||||
*
|
||||
* @return <code>true</code> when this pool has been closed.
|
||||
*/
|
||||
public final boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an <code>IllegalStateException</code> when this pool has been
|
||||
* closed.
|
||||
*
|
||||
* @throws IllegalStateException when this pool has been closed.
|
||||
*
|
||||
* @see #isClosed()
|
||||
*/
|
||||
protected final void assertOpen() throws IllegalStateException {
|
||||
if (isClosed()) {
|
||||
throw new IllegalStateException("Pool not open");
|
||||
}
|
||||
}
|
||||
|
||||
private volatile boolean closed = false;
|
||||
|
||||
@Override
|
||||
protected void toStringAppendFields(final StringBuilder builder) {
|
||||
builder.append("closed=");
|
||||
builder.append(closed);
|
||||
}
|
||||
}
|
||||
104
java/org/apache/tomcat/dbcp/pool2/BasePooledObjectFactory.java
Normal file
104
java/org/apache/tomcat/dbcp/pool2/BasePooledObjectFactory.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
/**
|
||||
* A base implementation of <code>PoolableObjectFactory</code>.
|
||||
* <p>
|
||||
* All operations defined here are essentially no-op's.
|
||||
* <p>
|
||||
* This class is immutable, and therefore thread-safe
|
||||
*
|
||||
* @param <T> Type of element managed in this factory.
|
||||
*
|
||||
* @see PooledObjectFactory
|
||||
* @see BaseKeyedPooledObjectFactory
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class BasePooledObjectFactory<T> extends BaseObject implements PooledObjectFactory<T> {
|
||||
/**
|
||||
* Creates an object instance, to be wrapped in a {@link PooledObject}.
|
||||
* <p>This method <strong>must</strong> support concurrent, multi-threaded
|
||||
* activation.</p>
|
||||
*
|
||||
* @return an instance to be served by the pool
|
||||
*
|
||||
* @throws Exception if there is a problem creating a new instance,
|
||||
* this will be propagated to the code requesting an object.
|
||||
*/
|
||||
public abstract T create() throws Exception;
|
||||
|
||||
/**
|
||||
* Wrap the provided instance with an implementation of
|
||||
* {@link PooledObject}.
|
||||
*
|
||||
* @param obj the instance to wrap
|
||||
*
|
||||
* @return The provided instance, wrapped by a {@link PooledObject}
|
||||
*/
|
||||
public abstract PooledObject<T> wrap(T obj);
|
||||
|
||||
@Override
|
||||
public PooledObject<T> makeObject() throws Exception {
|
||||
return wrap(create());
|
||||
}
|
||||
|
||||
/**
|
||||
* No-op.
|
||||
*
|
||||
* @param p ignored
|
||||
*/
|
||||
@Override
|
||||
public void destroyObject(final PooledObject<T> p)
|
||||
throws Exception {
|
||||
// The default implementation is a no-op.
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation always returns {@code true}.
|
||||
*
|
||||
* @param p ignored
|
||||
*
|
||||
* @return {@code true}
|
||||
*/
|
||||
@Override
|
||||
public boolean validateObject(final PooledObject<T> p) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* No-op.
|
||||
*
|
||||
* @param p ignored
|
||||
*/
|
||||
@Override
|
||||
public void activateObject(final PooledObject<T> p) throws Exception {
|
||||
// The default implementation is a no-op.
|
||||
}
|
||||
|
||||
/**
|
||||
* No-op.
|
||||
*
|
||||
* @param p ignored
|
||||
*/
|
||||
@Override
|
||||
public void passivateObject(final PooledObject<T> p)
|
||||
throws Exception {
|
||||
// The default implementation is a no-op.
|
||||
}
|
||||
}
|
||||
278
java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
Normal file
278
java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.Collection;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* A "keyed" pooling interface.
|
||||
* <p>
|
||||
* A keyed pool maintains a pool of instances for each key value.
|
||||
* </p>
|
||||
* <p>
|
||||
* Example of use:
|
||||
* </p>
|
||||
* <pre style="border:solid thin; padding: 1ex;"
|
||||
* > Object obj = <code style="color:#00C">null</code>;
|
||||
* Object key = <code style="color:#C00">"Key"</code>;
|
||||
*
|
||||
* <code style="color:#00C">try</code> {
|
||||
* obj = pool.borrowObject(key);
|
||||
* <code style="color:#0C0">//...use the object...</code>
|
||||
* } <code style="color:#00C">catch</code>(Exception e) {
|
||||
* <code style="color:#0C0">// invalidate the object</code>
|
||||
* pool.invalidateObject(key, obj);
|
||||
* <code style="color:#0C0">// do not return the object to the pool twice</code>
|
||||
* obj = <code style="color:#00C">null</code>;
|
||||
* } <code style="color:#00C">finally</code> {
|
||||
* <code style="color:#0C0">// make sure the object is returned to the pool</code>
|
||||
* <code style="color:#00C">if</code>(<code style="color:#00C">null</code> != obj) {
|
||||
* pool.returnObject(key, obj);
|
||||
* }
|
||||
* }</pre>
|
||||
* <p>
|
||||
* {@link KeyedObjectPool} implementations <i>may</i> choose to store at most
|
||||
* one instance per key value, or may choose to maintain a pool of instances
|
||||
* for each key (essentially creating a {@link java.util.Map Map} of
|
||||
* {@link ObjectPool pools}).
|
||||
* </p>
|
||||
* <p>
|
||||
* See {@link org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPool
|
||||
* GenericKeyedObjectPool} for an implementation.
|
||||
* </p>
|
||||
*
|
||||
* @param <K> The type of keys maintained by this pool.
|
||||
* @param <V> Type of element pooled in this pool.
|
||||
*
|
||||
* @see KeyedPooledObjectFactory
|
||||
* @see ObjectPool
|
||||
* @see org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPool GenericKeyedObjectPool
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface KeyedObjectPool<K, V> extends Closeable {
|
||||
|
||||
/**
|
||||
* Create an object using the {@link KeyedPooledObjectFactory factory} or
|
||||
* other implementation dependent mechanism, passivate it, and then place it
|
||||
* in the idle object pool. <code>addObject</code> is useful for
|
||||
* "pre-loading" a pool with idle objects (Optional operation).
|
||||
*
|
||||
* @param key the key a new instance should be added to
|
||||
*
|
||||
* @throws Exception
|
||||
* when {@link KeyedPooledObjectFactory#makeObject} fails.
|
||||
* @throws IllegalStateException
|
||||
* after {@link #close} has been called on this pool.
|
||||
* @throws UnsupportedOperationException
|
||||
* when this pool cannot add new idle objects.
|
||||
*/
|
||||
void addObject(K key) throws Exception, IllegalStateException,
|
||||
UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* Calls {@link KeyedObjectPool#addObject(Object)} with each
|
||||
* key in <code>keys</code> for <code>count</code> number of times. This has
|
||||
* the same effect as calling {@link #addObjects(Object, int)}
|
||||
* for each key in the <code>keys</code> collection.
|
||||
*
|
||||
* @param keys
|
||||
* {@link Collection} of keys to add objects for.
|
||||
* @param count
|
||||
* the number of idle objects to add for each <code>key</code>.
|
||||
* @throws Exception
|
||||
* when {@link KeyedObjectPool#addObject(Object)} fails.
|
||||
* @throws IllegalArgumentException
|
||||
* when <code>keyedPool</code>, <code>keys</code>, or any value
|
||||
* in <code>keys</code> is <code>null</code>.
|
||||
* @see #addObjects(Object, int)
|
||||
*/
|
||||
void addObjects(final Collection<K> keys, final int count) throws Exception, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Calls {@link KeyedObjectPool#addObject(Object)}
|
||||
* <code>key</code> <code>count</code> number of times.
|
||||
*
|
||||
* @param key
|
||||
* the key to add objects for.
|
||||
* @param count
|
||||
* the number of idle objects to add for <code>key</code>.
|
||||
* @throws Exception
|
||||
* when {@link KeyedObjectPool#addObject(Object)} fails.
|
||||
* @throws IllegalArgumentException
|
||||
* when <code>key</code> is <code>null</code>.
|
||||
* @since 2.8.0
|
||||
*/
|
||||
void addObjects(final K key, final int count) throws Exception, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Obtains an instance from this pool for the specified <code>key</code>.
|
||||
* <p>
|
||||
* Instances returned from this method will have been either newly created
|
||||
* with {@link KeyedPooledObjectFactory#makeObject makeObject} or will be
|
||||
* a previously idle object and have been activated with
|
||||
* {@link KeyedPooledObjectFactory#activateObject activateObject} and then
|
||||
* (optionally) validated with
|
||||
* {@link KeyedPooledObjectFactory#validateObject validateObject}.
|
||||
* </p>
|
||||
* <p>
|
||||
* By contract, clients <strong>must</strong> return the borrowed object
|
||||
* using {@link #returnObject returnObject},
|
||||
* {@link #invalidateObject invalidateObject}, or a related method as
|
||||
* defined in an implementation or sub-interface, using a <code>key</code>
|
||||
* that is {@link Object#equals equivalent} to the one used to borrow the
|
||||
* instance in the first place.
|
||||
* </p>
|
||||
* <p>
|
||||
* The behaviour of this method when the pool has been exhausted is not
|
||||
* strictly specified (although it may be specified by implementations).
|
||||
* </p>
|
||||
*
|
||||
* @param key the key used to obtain the object
|
||||
*
|
||||
* @return an instance from this pool.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* after {@link #close close} has been called on this pool
|
||||
* @throws Exception
|
||||
* when {@link KeyedPooledObjectFactory#makeObject
|
||||
* makeObject} throws an exception
|
||||
* @throws NoSuchElementException
|
||||
* when the pool is exhausted and cannot or will not return
|
||||
* another instance
|
||||
*/
|
||||
V borrowObject(K key) throws Exception, NoSuchElementException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Clears the pool, removing all pooled instances (optional operation).
|
||||
*
|
||||
* @throws UnsupportedOperationException when this implementation doesn't
|
||||
* support the operation
|
||||
*
|
||||
* @throws Exception if the pool cannot be cleared
|
||||
*/
|
||||
void clear() throws Exception, UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* Clears the specified pool, removing all pooled instances corresponding to
|
||||
* the given <code>key</code> (optional operation).
|
||||
*
|
||||
* @param key the key to clear
|
||||
*
|
||||
* @throws UnsupportedOperationException when this implementation doesn't
|
||||
* support the operation
|
||||
*
|
||||
* @throws Exception if the key cannot be cleared
|
||||
*/
|
||||
void clear(K key) throws Exception, UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* Close this pool, and free any resources associated with it.
|
||||
* <p>
|
||||
* Calling {@link #addObject addObject} or
|
||||
* {@link #borrowObject borrowObject} after invoking this method on a pool
|
||||
* will cause them to throw an {@link IllegalStateException}.
|
||||
* </p>
|
||||
* <p>
|
||||
* Implementations should silently fail if not all resources can be freed.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Returns the total number of instances currently borrowed from this pool but
|
||||
* not yet returned. Returns a negative value if this information is not
|
||||
* available.
|
||||
* @return the total number of instances currently borrowed from this pool but
|
||||
* not yet returned.
|
||||
*/
|
||||
int getNumActive();
|
||||
|
||||
/**
|
||||
* Returns the number of instances currently borrowed from but not yet
|
||||
* returned to the pool corresponding to the given <code>key</code>.
|
||||
* Returns a negative value if this information is not available.
|
||||
*
|
||||
* @param key the key to query
|
||||
* @return the number of instances currently borrowed from but not yet
|
||||
* returned to the pool corresponding to the given <code>key</code>.
|
||||
*/
|
||||
int getNumActive(K key);
|
||||
|
||||
/**
|
||||
* Returns the total number of instances currently idle in this pool.
|
||||
* Returns a negative value if this information is not available.
|
||||
* @return the total number of instances currently idle in this pool.
|
||||
*/
|
||||
int getNumIdle();
|
||||
|
||||
/**
|
||||
* Returns the number of instances corresponding to the given
|
||||
* <code>key</code> currently idle in this pool. Returns a negative value if
|
||||
* this information is not available.
|
||||
*
|
||||
* @param key the key to query
|
||||
* @return the number of instances corresponding to the given
|
||||
* <code>key</code> currently idle in this pool.
|
||||
*/
|
||||
int getNumIdle(K key);
|
||||
|
||||
/**
|
||||
* Invalidates an object from the pool.
|
||||
* <p>
|
||||
* By contract, <code>obj</code> <strong>must</strong> have been obtained
|
||||
* using {@link #borrowObject borrowObject} or a related method as defined
|
||||
* in an implementation or sub-interface using a <code>key</code> that is
|
||||
* equivalent to the one used to borrow the <code>Object</code> in the first
|
||||
* place.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method should be used when an object that has been borrowed is
|
||||
* determined (due to an exception or other problem) to be invalid.
|
||||
* </p>
|
||||
*
|
||||
* @param key the key used to obtain the object
|
||||
* @param obj a {@link #borrowObject borrowed} instance to be returned.
|
||||
*
|
||||
* @throws Exception if the instance cannot be invalidated
|
||||
*/
|
||||
void invalidateObject(K key, V obj) throws Exception;
|
||||
|
||||
/**
|
||||
* Return an instance to the pool. By contract, <code>obj</code>
|
||||
* <strong>must</strong> have been obtained using
|
||||
* {@link #borrowObject borrowObject} or a related method as defined in an
|
||||
* implementation or sub-interface using a <code>key</code> that is
|
||||
* equivalent to the one used to borrow the instance in the first place.
|
||||
*
|
||||
* @param key the key used to obtain the object
|
||||
* @param obj a {@link #borrowObject borrowed} instance to be returned.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if an attempt is made to return an object to the pool that
|
||||
* is in any state other than allocated (i.e. borrowed).
|
||||
* Attempting to return an object more than once or attempting
|
||||
* to return an object that was never borrowed from the pool
|
||||
* will trigger this exception.
|
||||
*
|
||||
* @throws Exception if an instance cannot be returned to the pool
|
||||
*/
|
||||
void returnObject(K key, V obj) throws Exception;
|
||||
}
|
||||
153
java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java
Normal file
153
java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
/**
|
||||
* An interface defining life-cycle methods for
|
||||
* instances to be served by a {@link KeyedObjectPool}.
|
||||
* <p>
|
||||
* By contract, when an {@link KeyedObjectPool}
|
||||
* delegates to a {@link KeyedPooledObjectFactory},
|
||||
* </p>
|
||||
* <ol>
|
||||
* <li>
|
||||
* {@link #makeObject} is called whenever a new instance is needed.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@link #activateObject} is invoked on every instance that has been
|
||||
* {@link #passivateObject passivated} before it is
|
||||
* {@link KeyedObjectPool#borrowObject borrowed} from the pool.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@link #validateObject} may be invoked on {@link #activateObject activated}
|
||||
* instances to make sure they can be
|
||||
* {@link KeyedObjectPool#borrowObject borrowed} from the pool.
|
||||
* <code>validateObject</code> may also be used to test an
|
||||
* instance being {@link KeyedObjectPool#returnObject returned} to the pool
|
||||
* before it is {@link #passivateObject passivated}. It will only be invoked
|
||||
* on an activated instance.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@link #passivateObject passivateObject}
|
||||
* is invoked on every instance when it is returned to the pool.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@link #destroyObject destroyObject}
|
||||
* is invoked on every instance when it is being "dropped" from the
|
||||
* pool (whether due to the response from <code>validateObject</code>,
|
||||
* or for reasons specific to the pool implementation.) There is no
|
||||
* guarantee that the instance being destroyed will
|
||||
* be considered active, passive or in a generally consistent state.
|
||||
* </li>
|
||||
* </ol>
|
||||
* {@link KeyedPooledObjectFactory} must be thread-safe. The only promise
|
||||
* an {@link KeyedObjectPool} makes is that the same instance of an object will
|
||||
* not be passed to more than one method of a
|
||||
* <code>KeyedPoolableObjectFactory</code> at a time.
|
||||
* <p>
|
||||
* While clients of a {@link KeyedObjectPool} borrow and return instances of
|
||||
* the underlying value type V, the factory methods act on instances of
|
||||
* {@link PooledObject PooledObject<V>}. These are the object wrappers that
|
||||
* pools use to track and maintain state informations about the objects that
|
||||
* they manage.
|
||||
* </p>
|
||||
*
|
||||
* @see KeyedObjectPool
|
||||
* @see BaseKeyedPooledObjectFactory
|
||||
*
|
||||
* @param <K> The type of keys managed by this factory.
|
||||
* @param <V> Type of element managed by this factory.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface KeyedPooledObjectFactory<K, V> {
|
||||
|
||||
/**
|
||||
* Create an instance that can be served by the pool and
|
||||
* wrap it in a {@link PooledObject} to be managed by the pool.
|
||||
*
|
||||
* @param key the key used when constructing the object
|
||||
*
|
||||
* @return a {@code PooledObject} wrapping an instance that can
|
||||
* be served by the pool.
|
||||
*
|
||||
* @throws Exception if there is a problem creating a new instance,
|
||||
* this will be propagated to the code requesting an object.
|
||||
*/
|
||||
PooledObject<V> makeObject(K key) throws Exception;
|
||||
|
||||
/**
|
||||
* Destroy an instance no longer needed by the pool.
|
||||
* <p>
|
||||
* It is important for implementations of this method to be aware that there
|
||||
* is no guarantee about what state <code>obj</code> will be in and the
|
||||
* implementation should be prepared to handle unexpected errors.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also, an implementation must take in to consideration that instances lost
|
||||
* to the garbage collector may never be destroyed.
|
||||
* </p>
|
||||
*
|
||||
* @param key the key used when selecting the instance
|
||||
* @param p a {@code PooledObject} wrapping the instance to be destroyed
|
||||
*
|
||||
* @throws Exception should be avoided as it may be swallowed by
|
||||
* the pool implementation.
|
||||
*
|
||||
* @see #validateObject
|
||||
* @see KeyedObjectPool#invalidateObject
|
||||
*/
|
||||
void destroyObject(K key, PooledObject<V> p) throws Exception;
|
||||
|
||||
/**
|
||||
* Ensures that the instance is safe to be returned by the pool.
|
||||
*
|
||||
* @param key the key used when selecting the object
|
||||
* @param p a {@code PooledObject} wrapping the instance to be validated
|
||||
*
|
||||
* @return <code>false</code> if <code>obj</code> is not valid and should
|
||||
* be dropped from the pool, <code>true</code> otherwise.
|
||||
*/
|
||||
boolean validateObject(K key, PooledObject<V> p);
|
||||
|
||||
/**
|
||||
* Reinitialize an instance to be returned by the pool.
|
||||
*
|
||||
* @param key the key used when selecting the object
|
||||
* @param p a {@code PooledObject} wrapping the instance to be activated
|
||||
*
|
||||
* @throws Exception if there is a problem activating <code>obj</code>,
|
||||
* this exception may be swallowed by the pool.
|
||||
*
|
||||
* @see #destroyObject
|
||||
*/
|
||||
void activateObject(K key, PooledObject<V> p) throws Exception;
|
||||
|
||||
/**
|
||||
* Uninitialize an instance to be returned to the idle object pool.
|
||||
*
|
||||
* @param key the key used when selecting the object
|
||||
* @param p a {@code PooledObject} wrapping the instance to be passivated
|
||||
*
|
||||
* @throws Exception if there is a problem passivating <code>obj</code>,
|
||||
* this exception may be swallowed by the pool.
|
||||
*
|
||||
* @see #destroyObject
|
||||
*/
|
||||
void passivateObject(K key, PooledObject<V> p) throws Exception;
|
||||
}
|
||||
|
||||
200
java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
Normal file
200
java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* A pooling simple interface.
|
||||
* <p>
|
||||
* Example of use:
|
||||
* </p>
|
||||
* <pre style="border:solid thin; padding: 1ex;"
|
||||
* > Object obj = <code style="color:#00C">null</code>;
|
||||
*
|
||||
* <code style="color:#00C">try</code> {
|
||||
* obj = pool.borrowObject();
|
||||
* <code style="color:#00C">try</code> {
|
||||
* <code style="color:#0C0">//...use the object...</code>
|
||||
* } <code style="color:#00C">catch</code>(Exception e) {
|
||||
* <code style="color:#0C0">// invalidate the object</code>
|
||||
* pool.invalidateObject(obj);
|
||||
* <code style="color:#0C0">// do not return the object to the pool twice</code>
|
||||
* obj = <code style="color:#00C">null</code>;
|
||||
* } <code style="color:#00C">finally</code> {
|
||||
* <code style="color:#0C0">// make sure the object is returned to the pool</code>
|
||||
* <code style="color:#00C">if</code>(<code style="color:#00C">null</code> != obj) {
|
||||
* pool.returnObject(obj);
|
||||
* }
|
||||
* }
|
||||
* } <code style="color:#00C">catch</code>(Exception e) {
|
||||
* <code style="color:#0C0">// failed to borrow an object</code>
|
||||
* }</pre>
|
||||
* <p>
|
||||
* See {@link BaseObjectPool} for a simple base implementation.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> Type of element pooled in this pool.
|
||||
*
|
||||
* @see PooledObjectFactory
|
||||
* @see KeyedObjectPool
|
||||
* @see BaseObjectPool
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ObjectPool<T> extends Closeable {
|
||||
|
||||
/**
|
||||
* Creates an object using the {@link PooledObjectFactory factory} or other
|
||||
* implementation dependent mechanism, passivate it, and then place it in
|
||||
* the idle object pool. <code>addObject</code> is useful for "pre-loading"
|
||||
* a pool with idle objects. (Optional operation).
|
||||
*
|
||||
* @throws Exception
|
||||
* when {@link PooledObjectFactory#makeObject} fails.
|
||||
* @throws IllegalStateException
|
||||
* after {@link #close} has been called on this pool.
|
||||
* @throws UnsupportedOperationException
|
||||
* when this pool cannot add new idle objects.
|
||||
*/
|
||||
void addObject() throws Exception, IllegalStateException,
|
||||
UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* Calls {@link ObjectPool#addObject()} <code>count</code>
|
||||
* number of times.
|
||||
*
|
||||
* @param count
|
||||
* the number of idle objects to add.
|
||||
* @throws Exception
|
||||
* when {@link ObjectPool#addObject()} fails.
|
||||
* @since 2.8.0
|
||||
*/
|
||||
void addObjects(final int count) throws Exception;
|
||||
|
||||
/**
|
||||
* Obtains an instance from this pool.
|
||||
* <p>
|
||||
* Instances returned from this method will have been either newly created
|
||||
* with {@link PooledObjectFactory#makeObject} or will be a previously
|
||||
* idle object and have been activated with
|
||||
* {@link PooledObjectFactory#activateObject} and then validated with
|
||||
* {@link PooledObjectFactory#validateObject}.
|
||||
* </p>
|
||||
* <p>
|
||||
* By contract, clients <strong>must</strong> return the borrowed instance
|
||||
* using {@link #returnObject}, {@link #invalidateObject}, or a related
|
||||
* method as defined in an implementation or sub-interface.
|
||||
* </p>
|
||||
* <p>
|
||||
* The behaviour of this method when the pool has been exhausted
|
||||
* is not strictly specified (although it may be specified by
|
||||
* implementations).
|
||||
* </p>
|
||||
*
|
||||
* @return an instance from this pool.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* after {@link #close close} has been called on this pool.
|
||||
* @throws Exception
|
||||
* when {@link PooledObjectFactory#makeObject} throws an
|
||||
* exception.
|
||||
* @throws NoSuchElementException
|
||||
* when the pool is exhausted and cannot or will not return
|
||||
* another instance.
|
||||
*/
|
||||
T borrowObject() throws Exception, NoSuchElementException,
|
||||
IllegalStateException;
|
||||
|
||||
/**
|
||||
* Clears any objects sitting idle in the pool, releasing any associated
|
||||
* resources (optional operation). Idle objects cleared must be
|
||||
* {@link PooledObjectFactory#destroyObject(PooledObject)}.
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* if this implementation does not support the operation
|
||||
*
|
||||
* @throws Exception if the pool cannot be cleared
|
||||
*/
|
||||
void clear() throws Exception, UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* Closes this pool, and free any resources associated with it.
|
||||
* <p>
|
||||
* Calling {@link #addObject} or {@link #borrowObject} after invoking this
|
||||
* method on a pool will cause them to throw an {@link IllegalStateException}.
|
||||
* </p>
|
||||
* <p>
|
||||
* Implementations should silently fail if not all resources can be freed.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Returns the number of instances currently borrowed from this pool. Returns
|
||||
* a negative value if this information is not available.
|
||||
* @return the number of instances currently borrowed from this pool.
|
||||
*/
|
||||
int getNumActive();
|
||||
|
||||
/**
|
||||
* Returns the number of instances currently idle in this pool. This may be
|
||||
* considered an approximation of the number of objects that can be
|
||||
* {@link #borrowObject borrowed} without creating any new instances.
|
||||
* Returns a negative value if this information is not available.
|
||||
* @return the number of instances currently idle in this pool.
|
||||
*/
|
||||
int getNumIdle();
|
||||
|
||||
/**
|
||||
* Invalidates an object from the pool.
|
||||
* <p>
|
||||
* By contract, <code>obj</code> <strong>must</strong> have been obtained
|
||||
* using {@link #borrowObject} or a related method as defined in an
|
||||
* implementation or sub-interface.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method should be used when an object that has been borrowed is
|
||||
* determined (due to an exception or other problem) to be invalid.
|
||||
* </p>
|
||||
*
|
||||
* @param obj a {@link #borrowObject borrowed} instance to be disposed.
|
||||
*
|
||||
* @throws Exception if the instance cannot be invalidated
|
||||
*/
|
||||
void invalidateObject(T obj) throws Exception;
|
||||
|
||||
/**
|
||||
* Returns an instance to the pool. By contract, <code>obj</code>
|
||||
* <strong>must</strong> have been obtained using {@link #borrowObject()} or
|
||||
* a related method as defined in an implementation or sub-interface.
|
||||
*
|
||||
* @param obj a {@link #borrowObject borrowed} instance to be returned.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if an attempt is made to return an object to the pool that
|
||||
* is in any state other than allocated (i.e. borrowed).
|
||||
* Attempting to return an object more than once or attempting
|
||||
* to return an object that was never borrowed from the pool
|
||||
* will trigger this exception.
|
||||
*
|
||||
* @throws Exception if an instance cannot be returned to the pool
|
||||
*/
|
||||
void returnObject(T obj) throws Exception;
|
||||
}
|
||||
717
java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
Normal file
717
java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
Normal file
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
|
||||
/**
|
||||
* This class consists exclusively of static methods that operate on or return
|
||||
* ObjectPool or KeyedObjectPool related interfaces.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public final class PoolUtils {
|
||||
|
||||
private static final String MSG_MIN_IDLE = "minIdle must be non-negative.";
|
||||
public static final String MSG_NULL_KEY = "key must not be null.";
|
||||
private static final String MSG_NULL_KEYED_POOL = "keyedPool must not be null.";
|
||||
public static final String MSG_NULL_KEYS = "keys must not be null.";
|
||||
private static final String MSG_NULL_POOL = "pool must not be null.";
|
||||
|
||||
/**
|
||||
* Timer used to periodically check pools idle object count. Because a
|
||||
* {@link Timer} creates a {@link Thread}, an IODH is used.
|
||||
*/
|
||||
static class TimerHolder {
|
||||
static final Timer MIN_IDLE_TIMER = new Timer(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* PoolUtils instances should NOT be constructed in standard programming.
|
||||
* Instead, the class should be used procedurally: PoolUtils.adapt(aPool);.
|
||||
* This constructor is public to permit tools that require a JavaBean
|
||||
* instance to operate.
|
||||
*/
|
||||
public PoolUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the supplied Throwable be re-thrown (eg if it is an instance of
|
||||
* one of the Throwables that should never be swallowed). Used by the pool
|
||||
* error handling for operations that throw exceptions that normally need to
|
||||
* be ignored.
|
||||
*
|
||||
* @param t
|
||||
* The Throwable to check
|
||||
* @throws ThreadDeath
|
||||
* if that is passed in
|
||||
* @throws VirtualMachineError
|
||||
* if that is passed in
|
||||
*/
|
||||
public static void checkRethrow(final Throwable t) {
|
||||
if (t instanceof ThreadDeath) {
|
||||
throw (ThreadDeath) t;
|
||||
}
|
||||
if (t instanceof VirtualMachineError) {
|
||||
throw (VirtualMachineError) t;
|
||||
}
|
||||
// All other instances of Throwable will be silently swallowed
|
||||
}
|
||||
|
||||
/**
|
||||
* Periodically check the idle object count for the pool. At most one idle
|
||||
* object will be added per period. If there is an exception when calling
|
||||
* {@link ObjectPool#addObject()} then no more checks will be performed.
|
||||
*
|
||||
* @param pool
|
||||
* the pool to check periodically.
|
||||
* @param minIdle
|
||||
* if the {@link ObjectPool#getNumIdle()} is less than this then
|
||||
* add an idle object.
|
||||
* @param period
|
||||
* the frequency to check the number of idle objects in a pool,
|
||||
* see {@link Timer#schedule(TimerTask, long, long)}.
|
||||
* @param <T> the type of objects in the pool
|
||||
* @return the {@link TimerTask} that will periodically check the pools idle
|
||||
* object count.
|
||||
* @throws IllegalArgumentException
|
||||
* when <code>pool</code> is <code>null</code> or when
|
||||
* <code>minIdle</code> is negative or when <code>period</code>
|
||||
* isn't valid for {@link Timer#schedule(TimerTask, long, long)}
|
||||
*/
|
||||
public static <T> TimerTask checkMinIdle(final ObjectPool<T> pool,
|
||||
final int minIdle, final long period)
|
||||
throws IllegalArgumentException {
|
||||
if (pool == null) {
|
||||
throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
|
||||
}
|
||||
if (minIdle < 0) {
|
||||
throw new IllegalArgumentException(MSG_MIN_IDLE);
|
||||
}
|
||||
final TimerTask task = new ObjectPoolMinIdleTimerTask<>(pool, minIdle);
|
||||
getMinIdleTimer().schedule(task, 0L, period);
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Periodically check the idle object count for the key in the keyedPool. At
|
||||
* most one idle object will be added per period. If there is an exception
|
||||
* when calling {@link KeyedObjectPool#addObject(Object)} then no more
|
||||
* checks for that key will be performed.
|
||||
*
|
||||
* @param keyedPool
|
||||
* the keyedPool to check periodically.
|
||||
* @param key
|
||||
* the key to check the idle count of.
|
||||
* @param minIdle
|
||||
* if the {@link KeyedObjectPool#getNumIdle(Object)} is less than
|
||||
* this then add an idle object.
|
||||
* @param period
|
||||
* the frequency to check the number of idle objects in a
|
||||
* keyedPool, see {@link Timer#schedule(TimerTask, long, long)}.
|
||||
* @param <K> the type of the pool key
|
||||
* @param <V> the type of pool entries
|
||||
* @return the {@link TimerTask} that will periodically check the pools idle
|
||||
* object count.
|
||||
* @throws IllegalArgumentException
|
||||
* when <code>keyedPool</code>, <code>key</code> is
|
||||
* <code>null</code> or when <code>minIdle</code> is negative or
|
||||
* when <code>period</code> isn't valid for
|
||||
* {@link Timer#schedule(TimerTask, long, long)}.
|
||||
*/
|
||||
public static <K, V> TimerTask checkMinIdle(
|
||||
final KeyedObjectPool<K, V> keyedPool, final K key,
|
||||
final int minIdle, final long period)
|
||||
throws IllegalArgumentException {
|
||||
if (keyedPool == null) {
|
||||
throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException(MSG_NULL_KEY);
|
||||
}
|
||||
if (minIdle < 0) {
|
||||
throw new IllegalArgumentException(MSG_MIN_IDLE);
|
||||
}
|
||||
final TimerTask task = new KeyedObjectPoolMinIdleTimerTask<>(
|
||||
keyedPool, key, minIdle);
|
||||
getMinIdleTimer().schedule(task, 0L, period);
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Periodically check the idle object count for each key in the
|
||||
* <code>Collection</code> <code>keys</code> in the keyedPool. At most one
|
||||
* idle object will be added per period.
|
||||
*
|
||||
* @param keyedPool
|
||||
* the keyedPool to check periodically.
|
||||
* @param keys
|
||||
* a collection of keys to check the idle object count.
|
||||
* @param minIdle
|
||||
* if the {@link KeyedObjectPool#getNumIdle(Object)} is less than
|
||||
* this then add an idle object.
|
||||
* @param period
|
||||
* the frequency to check the number of idle objects in a
|
||||
* keyedPool, see {@link Timer#schedule(TimerTask, long, long)}.
|
||||
* @param <K> the type of the pool key
|
||||
* @param <V> the type of pool entries
|
||||
* @return a {@link Map} of key and {@link TimerTask} pairs that will
|
||||
* periodically check the pools idle object count.
|
||||
* @throws IllegalArgumentException
|
||||
* when <code>keyedPool</code>, <code>keys</code>, or any of the
|
||||
* values in the collection is <code>null</code> or when
|
||||
* <code>minIdle</code> is negative or when <code>period</code>
|
||||
* isn't valid for {@link Timer#schedule(TimerTask, long, long)}
|
||||
* .
|
||||
* @see #checkMinIdle(KeyedObjectPool, Object, int, long)
|
||||
*/
|
||||
public static <K, V> Map<K, TimerTask> checkMinIdle(
|
||||
final KeyedObjectPool<K, V> keyedPool, final Collection<K> keys,
|
||||
final int minIdle, final long period)
|
||||
throws IllegalArgumentException {
|
||||
if (keys == null) {
|
||||
throw new IllegalArgumentException(MSG_NULL_KEYS);
|
||||
}
|
||||
final Map<K, TimerTask> tasks = new HashMap<>(keys.size());
|
||||
final Iterator<K> iter = keys.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final K key = iter.next();
|
||||
final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period);
|
||||
tasks.put(key, task);
|
||||
}
|
||||
return tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link ObjectPool#addObject()} on <code>pool</code> <code>count</code>
|
||||
* number of times.
|
||||
*
|
||||
* @param pool
|
||||
* the pool to prefill.
|
||||
* @param count
|
||||
* the number of idle objects to add.
|
||||
* @param <T> the type of objects in the pool
|
||||
* @throws Exception
|
||||
* when {@link ObjectPool#addObject()} fails.
|
||||
* @throws IllegalArgumentException
|
||||
* when <code>pool</code> is <code>null</code>.
|
||||
* @deprecated Use {@link ObjectPool#addObjects(int)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <T> void prefill(final ObjectPool<T> pool, final int count)
|
||||
throws Exception, IllegalArgumentException {
|
||||
if (pool == null) {
|
||||
throw new IllegalArgumentException(MSG_NULL_POOL);
|
||||
}
|
||||
pool.addObjects(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link KeyedObjectPool#addObject(Object)} on <code>keyedPool</code> with
|
||||
* <code>key</code> <code>count</code> number of times.
|
||||
*
|
||||
* @param keyedPool
|
||||
* the keyedPool to prefill.
|
||||
* @param key
|
||||
* the key to add objects for.
|
||||
* @param count
|
||||
* the number of idle objects to add for <code>key</code>.
|
||||
* @param <K> the type of the pool key
|
||||
* @param <V> the type of pool entries
|
||||
* @throws Exception
|
||||
* when {@link KeyedObjectPool#addObject(Object)} fails.
|
||||
* @throws IllegalArgumentException
|
||||
* when <code>keyedPool</code> or <code>key</code> is
|
||||
* <code>null</code>.
|
||||
* @deprecated Use {@link KeyedObjectPool#addObjects(Object, int)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
|
||||
final K key, final int count) throws Exception,
|
||||
IllegalArgumentException {
|
||||
if (keyedPool == null) {
|
||||
throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
|
||||
}
|
||||
keyedPool.addObjects(key, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link KeyedObjectPool#addObject(Object)} on <code>keyedPool</code> with each
|
||||
* key in <code>keys</code> for <code>count</code> number of times. This has
|
||||
* the same effect as calling {@link #prefill(KeyedObjectPool, Object, int)}
|
||||
* for each key in the <code>keys</code> collection.
|
||||
*
|
||||
* @param keyedPool
|
||||
* the keyedPool to prefill.
|
||||
* @param keys
|
||||
* {@link Collection} of keys to add objects for.
|
||||
* @param count
|
||||
* the number of idle objects to add for each <code>key</code>.
|
||||
* @param <K> the type of the pool key
|
||||
* @param <V> the type of pool entries
|
||||
* @throws Exception
|
||||
* when {@link KeyedObjectPool#addObject(Object)} fails.
|
||||
* @throws IllegalArgumentException
|
||||
* when <code>keyedPool</code>, <code>keys</code>, or any value
|
||||
* in <code>keys</code> is <code>null</code>.
|
||||
* @see #prefill(KeyedObjectPool, Object, int)
|
||||
* @deprecated Use {@link KeyedObjectPool#addObjects(Collection, int)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
|
||||
final Collection<K> keys, final int count) throws Exception,
|
||||
IllegalArgumentException {
|
||||
if (keys == null) {
|
||||
throw new IllegalArgumentException(MSG_NULL_KEYS);
|
||||
}
|
||||
keyedPool.addObjects(keys, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a synchronized (thread-safe) PooledObjectFactory backed by the
|
||||
* specified PooledObjectFactory.
|
||||
*
|
||||
* @param factory
|
||||
* the PooledObjectFactory to be "wrapped" in a synchronized
|
||||
* PooledObjectFactory.
|
||||
* @param <T> the type of objects in the pool
|
||||
* @return a synchronized view of the specified PooledObjectFactory.
|
||||
*/
|
||||
public static <T> PooledObjectFactory<T> synchronizedPooledFactory(
|
||||
final PooledObjectFactory<T> factory) {
|
||||
return new SynchronizedPooledObjectFactory<>(factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a synchronized (thread-safe) KeyedPooledObjectFactory backed by
|
||||
* the specified KeyedPoolableObjectFactory.
|
||||
*
|
||||
* @param keyedFactory
|
||||
* the KeyedPooledObjectFactory to be "wrapped" in a
|
||||
* synchronized KeyedPooledObjectFactory.
|
||||
* @param <K> the type of the pool key
|
||||
* @param <V> the type of pool entries
|
||||
* @return a synchronized view of the specified KeyedPooledObjectFactory.
|
||||
*/
|
||||
public static <K, V> KeyedPooledObjectFactory<K, V> synchronizedKeyedPooledFactory(
|
||||
final KeyedPooledObjectFactory<K, V> keyedFactory) {
|
||||
return new SynchronizedKeyedPooledObjectFactory<>(keyedFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>Timer</code> for checking keyedPool's idle count.
|
||||
*
|
||||
* @return the {@link Timer} for checking keyedPool's idle count.
|
||||
*/
|
||||
private static Timer getMinIdleTimer() {
|
||||
return TimerHolder.MIN_IDLE_TIMER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer task that adds objects to the pool until the number of idle
|
||||
* instances reaches the configured minIdle. Note that this is not the same
|
||||
* as the pool's minIdle setting.
|
||||
*
|
||||
* @param <T> type of objects in the pool
|
||||
*/
|
||||
private static final class ObjectPoolMinIdleTimerTask<T> extends TimerTask {
|
||||
|
||||
/** Minimum number of idle instances. Not the same as pool.getMinIdle(). */
|
||||
private final int minIdle;
|
||||
|
||||
/** Object pool */
|
||||
private final ObjectPool<T> pool;
|
||||
|
||||
/**
|
||||
* Create a new ObjectPoolMinIdleTimerTask for the given pool with the
|
||||
* given minIdle setting.
|
||||
*
|
||||
* @param pool
|
||||
* object pool
|
||||
* @param minIdle
|
||||
* number of idle instances to maintain
|
||||
* @throws IllegalArgumentException
|
||||
* if the pool is null
|
||||
*/
|
||||
ObjectPoolMinIdleTimerTask(final ObjectPool<T> pool, final int minIdle)
|
||||
throws IllegalArgumentException {
|
||||
if (pool == null) {
|
||||
throw new IllegalArgumentException(MSG_NULL_POOL);
|
||||
}
|
||||
this.pool = pool;
|
||||
this.minIdle = minIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
boolean success = false;
|
||||
try {
|
||||
if (pool.getNumIdle() < minIdle) {
|
||||
pool.addObject();
|
||||
}
|
||||
success = true;
|
||||
|
||||
} catch (final Exception e) {
|
||||
cancel();
|
||||
} finally {
|
||||
// detect other types of Throwable and cancel this Timer
|
||||
if (!success) {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("ObjectPoolMinIdleTimerTask");
|
||||
sb.append("{minIdle=").append(minIdle);
|
||||
sb.append(", pool=").append(pool);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer task that adds objects to the pool until the number of idle
|
||||
* instances for the given key reaches the configured minIdle. Note that
|
||||
* this is not the same as the pool's minIdle setting.
|
||||
*
|
||||
* @param <K> object pool key type
|
||||
* @param <V> object pool value type
|
||||
*/
|
||||
private static final class KeyedObjectPoolMinIdleTimerTask<K, V> extends
|
||||
TimerTask {
|
||||
|
||||
/** Minimum number of idle instances. Not the same as pool.getMinIdle(). */
|
||||
private final int minIdle;
|
||||
|
||||
/** Key to ensure minIdle for */
|
||||
private final K key;
|
||||
|
||||
/** Keyed object pool */
|
||||
private final KeyedObjectPool<K, V> keyedPool;
|
||||
|
||||
/**
|
||||
* Creates a new KeyedObjecPoolMinIdleTimerTask.
|
||||
*
|
||||
* @param keyedPool
|
||||
* keyed object pool
|
||||
* @param key
|
||||
* key to ensure minimum number of idle instances
|
||||
* @param minIdle
|
||||
* minimum number of idle instances
|
||||
* @throws IllegalArgumentException
|
||||
* if the key is null
|
||||
*/
|
||||
KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool<K, V> keyedPool,
|
||||
final K key, final int minIdle) throws IllegalArgumentException {
|
||||
if (keyedPool == null) {
|
||||
throw new IllegalArgumentException(
|
||||
MSG_NULL_KEYED_POOL);
|
||||
}
|
||||
this.keyedPool = keyedPool;
|
||||
this.key = key;
|
||||
this.minIdle = minIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
boolean success = false;
|
||||
try {
|
||||
if (keyedPool.getNumIdle(key) < minIdle) {
|
||||
keyedPool.addObject(key);
|
||||
}
|
||||
success = true;
|
||||
|
||||
} catch (final Exception e) {
|
||||
cancel();
|
||||
|
||||
} finally {
|
||||
// detect other types of Throwable and cancel this Timer
|
||||
if (!success) {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("KeyedObjectPoolMinIdleTimerTask");
|
||||
sb.append("{minIdle=").append(minIdle);
|
||||
sb.append(", key=").append(key);
|
||||
sb.append(", keyedPool=").append(keyedPool);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A fully synchronized PooledObjectFactory that wraps a
|
||||
* PooledObjectFactory and synchronizes access to the wrapped factory
|
||||
* methods.
|
||||
* <p>
|
||||
* <b>Note:</b> This should not be used on pool implementations that already
|
||||
* provide proper synchronization such as the pools provided in the Commons
|
||||
* Pool library.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> pooled object factory type
|
||||
*/
|
||||
private static final class SynchronizedPooledObjectFactory<T> implements
|
||||
PooledObjectFactory<T> {
|
||||
|
||||
/** Synchronization lock */
|
||||
private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
|
||||
|
||||
/** Wrapped factory */
|
||||
private final PooledObjectFactory<T> factory;
|
||||
|
||||
/**
|
||||
* Creates a SynchronizedPoolableObjectFactory wrapping the given
|
||||
* factory.
|
||||
*
|
||||
* @param factory
|
||||
* underlying factory to wrap
|
||||
* @throws IllegalArgumentException
|
||||
* if the factory is null
|
||||
*/
|
||||
SynchronizedPooledObjectFactory(final PooledObjectFactory<T> factory)
|
||||
throws IllegalArgumentException {
|
||||
if (factory == null) {
|
||||
throw new IllegalArgumentException("factory must not be null.");
|
||||
}
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public PooledObject<T> makeObject() throws Exception {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return factory.makeObject();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void destroyObject(final PooledObject<T> p) throws Exception {
|
||||
writeLock.lock();
|
||||
try {
|
||||
factory.destroyObject(p);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean validateObject(final PooledObject<T> p) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return factory.validateObject(p);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void activateObject(final PooledObject<T> p) throws Exception {
|
||||
writeLock.lock();
|
||||
try {
|
||||
factory.activateObject(p);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void passivateObject(final PooledObject<T> p) throws Exception {
|
||||
writeLock.lock();
|
||||
try {
|
||||
factory.passivateObject(p);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("SynchronizedPoolableObjectFactory");
|
||||
sb.append("{factory=").append(factory);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A fully synchronized KeyedPooledObjectFactory that wraps a
|
||||
* KeyedPooledObjectFactory and synchronizes access to the wrapped factory
|
||||
* methods.
|
||||
* <p>
|
||||
* <b>Note:</b> This should not be used on pool implementations that already
|
||||
* provide proper synchronization such as the pools provided in the Commons
|
||||
* Pool library.
|
||||
* </p>
|
||||
*
|
||||
* @param <K> pooled object factory key type
|
||||
* @param <V> pooled object factory key value
|
||||
*/
|
||||
private static final class SynchronizedKeyedPooledObjectFactory<K, V>
|
||||
implements KeyedPooledObjectFactory<K, V> {
|
||||
|
||||
/** Synchronization lock */
|
||||
private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
|
||||
|
||||
/** Wrapped factory */
|
||||
private final KeyedPooledObjectFactory<K, V> keyedFactory;
|
||||
|
||||
/**
|
||||
* Creates a SynchronizedKeyedPoolableObjectFactory wrapping the given
|
||||
* factory.
|
||||
*
|
||||
* @param keyedFactory
|
||||
* underlying factory to wrap
|
||||
* @throws IllegalArgumentException
|
||||
* if the factory is null
|
||||
*/
|
||||
SynchronizedKeyedPooledObjectFactory(
|
||||
final KeyedPooledObjectFactory<K, V> keyedFactory)
|
||||
throws IllegalArgumentException {
|
||||
if (keyedFactory == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"keyedFactory must not be null.");
|
||||
}
|
||||
this.keyedFactory = keyedFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public PooledObject<V> makeObject(final K key) throws Exception {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return keyedFactory.makeObject(key);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void destroyObject(final K key, final PooledObject<V> p) throws Exception {
|
||||
writeLock.lock();
|
||||
try {
|
||||
keyedFactory.destroyObject(key, p);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean validateObject(final K key, final PooledObject<V> p) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
return keyedFactory.validateObject(key, p);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void activateObject(final K key, final PooledObject<V> p) throws Exception {
|
||||
writeLock.lock();
|
||||
try {
|
||||
keyedFactory.activateObject(key, p);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void passivateObject(final K key, final PooledObject<V> p) throws Exception {
|
||||
writeLock.lock();
|
||||
try {
|
||||
keyedFactory.passivateObject(key, p);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("SynchronizedKeyedPoolableObjectFactory");
|
||||
sb.append("{keyedFactory=").append(keyedFactory);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
220
java/org/apache/tomcat/dbcp/pool2/PooledObject.java
Normal file
220
java/org/apache/tomcat/dbcp/pool2/PooledObject.java
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Deque;
|
||||
|
||||
/**
|
||||
* Defines the wrapper that is used to track the additional information, such as
|
||||
* state, for the pooled objects.
|
||||
* <p>
|
||||
* Implementations of this class are required to be thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of object in the pool
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface PooledObject<T> extends Comparable<PooledObject<T>> {
|
||||
|
||||
/**
|
||||
* Obtains the underlying object that is wrapped by this instance of
|
||||
* {@link PooledObject}.
|
||||
*
|
||||
* @return The wrapped object
|
||||
*/
|
||||
T getObject();
|
||||
|
||||
/**
|
||||
* Obtains the time (using the same basis as
|
||||
* {@link System#currentTimeMillis()}) that this object was created.
|
||||
*
|
||||
* @return The creation time for the wrapped object
|
||||
*/
|
||||
long getCreateTime();
|
||||
|
||||
/**
|
||||
* Obtains the time in milliseconds that this object last spent in the
|
||||
* active state (it may still be active in which case subsequent calls will
|
||||
* return an increased value).
|
||||
*
|
||||
* @return The time in milliseconds last spent in the active state
|
||||
*/
|
||||
long getActiveTimeMillis();
|
||||
|
||||
/**
|
||||
* Gets the number of times this object has been borrowed.
|
||||
*
|
||||
* @return The number of times this object has been borrowed.
|
||||
* @since 2.7.0
|
||||
*/
|
||||
long getBorrowedCount();
|
||||
|
||||
/**
|
||||
* Obtains the time in milliseconds that this object last spend in the
|
||||
* idle state (it may still be idle in which case subsequent calls will
|
||||
* return an increased value).
|
||||
*
|
||||
* @return The time in milliseconds last spent in the idle state
|
||||
*/
|
||||
long getIdleTimeMillis();
|
||||
|
||||
/**
|
||||
* Obtains the time the wrapped object was last borrowed.
|
||||
*
|
||||
* @return The time the object was last borrowed
|
||||
*/
|
||||
long getLastBorrowTime();
|
||||
|
||||
/**
|
||||
* Obtains the time the wrapped object was last returned.
|
||||
*
|
||||
* @return The time the object was last returned
|
||||
*/
|
||||
long getLastReturnTime();
|
||||
|
||||
/**
|
||||
* Returns an estimate of the last time this object was used. If the class
|
||||
* of the pooled object implements {@link TrackedUse}, what is returned is
|
||||
* the maximum of {@link TrackedUse#getLastUsed()} and
|
||||
* {@link #getLastBorrowTime()}; otherwise this method gives the same
|
||||
* value as {@link #getLastBorrowTime()}.
|
||||
*
|
||||
* @return the last time this object was used
|
||||
*/
|
||||
long getLastUsedTime();
|
||||
|
||||
/**
|
||||
* Orders instances based on idle time - i.e. the length of time since the
|
||||
* instance was returned to the pool. Used by the GKOP idle object evictor.
|
||||
*<p>
|
||||
* Note: This class has a natural ordering that is inconsistent with
|
||||
* equals if distinct objects have the same identity hash code.
|
||||
* </p>
|
||||
* <p>
|
||||
* {@inheritDoc}
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
int compareTo(PooledObject<T> other);
|
||||
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
/**
|
||||
* Provides a String form of the wrapper for debug purposes. The format is
|
||||
* not fixed and may change at any time.
|
||||
* <p>
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* Attempts to place the pooled object in the
|
||||
* {@link PooledObjectState#EVICTION} state.
|
||||
*
|
||||
* @return <code>true</code> if the object was placed in the
|
||||
* {@link PooledObjectState#EVICTION} state otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
boolean startEvictionTest();
|
||||
|
||||
/**
|
||||
* Called to inform the object that the eviction test has ended.
|
||||
*
|
||||
* @param idleQueue The queue of idle objects to which the object should be
|
||||
* returned
|
||||
*
|
||||
* @return Currently not used
|
||||
*/
|
||||
boolean endEvictionTest(Deque<PooledObject<T>> idleQueue);
|
||||
|
||||
/**
|
||||
* Allocates the object.
|
||||
*
|
||||
* @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
|
||||
*/
|
||||
boolean allocate();
|
||||
|
||||
/**
|
||||
* Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE}
|
||||
* if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}.
|
||||
*
|
||||
* @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED}
|
||||
*/
|
||||
boolean deallocate();
|
||||
|
||||
/**
|
||||
* Sets the state to {@link PooledObjectState#INVALID INVALID}
|
||||
*/
|
||||
void invalidate();
|
||||
|
||||
/**
|
||||
* Is abandoned object tracking being used? If this is true the
|
||||
* implementation will need to record the stack trace of the last caller to
|
||||
* borrow this object.
|
||||
*
|
||||
* @param logAbandoned The new configuration setting for abandoned
|
||||
* object tracking
|
||||
*/
|
||||
void setLogAbandoned(boolean logAbandoned);
|
||||
|
||||
/**
|
||||
* Configures the stack trace generation strategy based on whether or not fully detailed stack traces are required.
|
||||
* When set to false, abandoned logs may only include caller class information rather than method names, line
|
||||
* numbers, and other normal metadata available in a full stack trace.
|
||||
*
|
||||
* @param requireFullStackTrace the new configuration setting for abandoned object logging
|
||||
* @since 2.7.0
|
||||
*/
|
||||
void setRequireFullStackTrace(final boolean requireFullStackTrace);
|
||||
|
||||
/**
|
||||
* Record the current stack trace as the last time the object was used.
|
||||
*/
|
||||
void use();
|
||||
|
||||
/**
|
||||
* Prints the stack trace of the code that borrowed this pooled object and
|
||||
* the stack trace of the last code to use this object (if available) to
|
||||
* the supplied writer.
|
||||
*
|
||||
* @param writer The destination for the debug output
|
||||
*/
|
||||
void printStackTrace(PrintWriter writer);
|
||||
|
||||
/**
|
||||
* Returns the state of this object.
|
||||
* @return state
|
||||
*/
|
||||
PooledObjectState getState();
|
||||
|
||||
/**
|
||||
* Marks the pooled object as abandoned.
|
||||
*/
|
||||
void markAbandoned();
|
||||
|
||||
/**
|
||||
* Marks the object as returning to the pool.
|
||||
*/
|
||||
void markReturning();
|
||||
}
|
||||
141
java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java
Normal file
141
java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
/**
|
||||
* An interface defining life-cycle methods for instances to be served by an
|
||||
* {@link ObjectPool}.
|
||||
* <p>
|
||||
* By contract, when an {@link ObjectPool} delegates to a
|
||||
* {@link PooledObjectFactory},
|
||||
* </p>
|
||||
* <ol>
|
||||
* <li>
|
||||
* {@link #makeObject} is called whenever a new instance is needed.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@link #activateObject} is invoked on every instance that has been
|
||||
* {@link #passivateObject passivated} before it is
|
||||
* {@link ObjectPool#borrowObject borrowed} from the pool.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@link #validateObject} may be invoked on {@link #activateObject activated}
|
||||
* instances to make sure they can be {@link ObjectPool#borrowObject borrowed}
|
||||
* from the pool. {@link #validateObject} may also be used to
|
||||
* test an instance being {@link ObjectPool#returnObject returned} to the pool
|
||||
* before it is {@link #passivateObject passivated}. It will only be invoked
|
||||
* on an activated instance.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@link #passivateObject} is invoked on every instance when it is returned
|
||||
* to the pool.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@link #destroyObject} is invoked on every instance when it is being
|
||||
* "dropped" from the pool (whether due to the response from
|
||||
* {@link #validateObject}, or for reasons specific to the pool
|
||||
* implementation.) There is no guarantee that the instance being destroyed
|
||||
* will be considered active, passive or in a generally consistent state.
|
||||
* </li>
|
||||
* </ol>
|
||||
* {@link PooledObjectFactory} must be thread-safe. The only promise
|
||||
* an {@link ObjectPool} makes is that the same instance of an object will not
|
||||
* be passed to more than one method of a <code>PoolableObjectFactory</code>
|
||||
* at a time.
|
||||
* <p>
|
||||
* While clients of a {@link KeyedObjectPool} borrow and return instances of
|
||||
* the underlying value type {@code V}, the factory methods act on instances of
|
||||
* {@link PooledObject PooledObject<V>}. These are the object wrappers that
|
||||
* pools use to track and maintain state information about the objects that
|
||||
* they manage.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> Type of element managed in this factory.
|
||||
*
|
||||
* @see ObjectPool
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface PooledObjectFactory<T> {
|
||||
|
||||
/**
|
||||
* Creates an instance that can be served by the pool and wrap it in a
|
||||
* {@link PooledObject} to be managed by the pool.
|
||||
*
|
||||
* @return a {@code PooledObject} wrapping an instance that can be served by the pool
|
||||
*
|
||||
* @throws Exception if there is a problem creating a new instance,
|
||||
* this will be propagated to the code requesting an object.
|
||||
*/
|
||||
PooledObject<T> makeObject() throws Exception;
|
||||
|
||||
/**
|
||||
* Destroys an instance no longer needed by the pool.
|
||||
* <p>
|
||||
* It is important for implementations of this method to be aware that there
|
||||
* is no guarantee about what state <code>obj</code> will be in and the
|
||||
* implementation should be prepared to handle unexpected errors.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also, an implementation must take in to consideration that instances lost
|
||||
* to the garbage collector may never be destroyed.
|
||||
* </p>
|
||||
*
|
||||
* @param p a {@code PooledObject} wrapping the instance to be destroyed
|
||||
*
|
||||
* @throws Exception should be avoided as it may be swallowed by
|
||||
* the pool implementation.
|
||||
*
|
||||
* @see #validateObject
|
||||
* @see ObjectPool#invalidateObject
|
||||
*/
|
||||
void destroyObject(PooledObject<T> p) throws Exception;
|
||||
|
||||
/**
|
||||
* Ensures that the instance is safe to be returned by the pool.
|
||||
*
|
||||
* @param p a {@code PooledObject} wrapping the instance to be validated
|
||||
*
|
||||
* @return <code>false</code> if <code>obj</code> is not valid and should
|
||||
* be dropped from the pool, <code>true</code> otherwise.
|
||||
*/
|
||||
boolean validateObject(PooledObject<T> p);
|
||||
|
||||
/**
|
||||
* Reinitializes an instance to be returned by the pool.
|
||||
*
|
||||
* @param p a {@code PooledObject} wrapping the instance to be activated
|
||||
*
|
||||
* @throws Exception if there is a problem activating <code>obj</code>,
|
||||
* this exception may be swallowed by the pool.
|
||||
*
|
||||
* @see #destroyObject
|
||||
*/
|
||||
void activateObject(PooledObject<T> p) throws Exception;
|
||||
|
||||
/**
|
||||
* Uninitializes an instance to be returned to the idle object pool.
|
||||
*
|
||||
* @param p a {@code PooledObject} wrapping the instance to be passivated
|
||||
*
|
||||
* @throws Exception if there is a problem passivating <code>obj</code>,
|
||||
* this exception may be swallowed by the pool.
|
||||
*
|
||||
* @see #destroyObject
|
||||
*/
|
||||
void passivateObject(PooledObject<T> p) throws Exception;
|
||||
}
|
||||
87
java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java
Normal file
87
java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java
Normal file
@@ -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.pool2;
|
||||
|
||||
/**
|
||||
* Provides the possible states that a {@link PooledObject} may be in.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public enum PooledObjectState {
|
||||
|
||||
/**
|
||||
* In the queue, not in use.
|
||||
*/
|
||||
IDLE,
|
||||
|
||||
/**
|
||||
* In use.
|
||||
*/
|
||||
ALLOCATED,
|
||||
|
||||
/**
|
||||
* In the queue, currently being tested for possible eviction.
|
||||
*/
|
||||
EVICTION,
|
||||
|
||||
/**
|
||||
* Not in the queue, currently being tested for possible eviction. An
|
||||
* attempt to borrow the object was made while being tested which removed it
|
||||
* from the queue. It should be returned to the head of the queue once
|
||||
* eviction testing completes.
|
||||
* TODO: Consider allocating object and ignoring the result of the eviction
|
||||
* test.
|
||||
*/
|
||||
EVICTION_RETURN_TO_HEAD,
|
||||
|
||||
/**
|
||||
* In the queue, currently being validated.
|
||||
*/
|
||||
VALIDATION,
|
||||
|
||||
/**
|
||||
* Not in queue, currently being validated. The object was borrowed while
|
||||
* being validated and since testOnBorrow was configured, it was removed
|
||||
* from the queue and pre-allocated. It should be allocated once validation
|
||||
* completes.
|
||||
*/
|
||||
VALIDATION_PREALLOCATED,
|
||||
|
||||
/**
|
||||
* Not in queue, currently being validated. An attempt to borrow the object
|
||||
* was made while previously being tested for eviction which removed it from
|
||||
* the queue. It should be returned to the head of the queue once validation
|
||||
* completes.
|
||||
*/
|
||||
VALIDATION_RETURN_TO_HEAD,
|
||||
|
||||
/**
|
||||
* Failed maintenance (e.g. eviction test or validation) and will be / has
|
||||
* been destroyed
|
||||
*/
|
||||
INVALID,
|
||||
|
||||
/**
|
||||
* Deemed abandoned, to be invalidated.
|
||||
*/
|
||||
ABANDONED,
|
||||
|
||||
/**
|
||||
* Returning to the pool.
|
||||
*/
|
||||
RETURNING
|
||||
}
|
||||
@@ -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.pool2;
|
||||
|
||||
/**
|
||||
* Pools that unavoidably swallow exceptions may be configured with an instance
|
||||
* of this listener so the user may receive notification of when this happens.
|
||||
* The listener should not throw an exception when called but pools calling
|
||||
* listeners should protect themselves against exceptions anyway.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface SwallowedExceptionListener {
|
||||
|
||||
/**
|
||||
* This method is called every time the implementation unavoidably swallows
|
||||
* an exception.
|
||||
*
|
||||
* @param e The exception that was swallowed
|
||||
*/
|
||||
void onSwallowException(Exception e);
|
||||
}
|
||||
36
java/org/apache/tomcat/dbcp/pool2/TrackedUse.java
Normal file
36
java/org/apache/tomcat/dbcp/pool2/TrackedUse.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.pool2;
|
||||
|
||||
/**
|
||||
* This interface allows pooled objects to make information available about when
|
||||
* and how they were used available to the object pool. The object pool may, but
|
||||
* is not required, to use this information to make more informed decisions when
|
||||
* determining the state of a pooled object - for instance whether or not the
|
||||
* object has been abandoned.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface TrackedUse {
|
||||
|
||||
/**
|
||||
* Get the last time this object was used in ms.
|
||||
*
|
||||
* @return long time in ms
|
||||
*/
|
||||
long getLastUsed();
|
||||
}
|
||||
39
java/org/apache/tomcat/dbcp/pool2/UsageTracking.java
Normal file
39
java/org/apache/tomcat/dbcp/pool2/UsageTracking.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.pool2;
|
||||
|
||||
/**
|
||||
* This interface may be implemented by an object pool to enable clients
|
||||
* (primarily those clients that wrap pools to provide pools with extended
|
||||
* features) to provide additional information to the pool relating to object
|
||||
* using allowing more informed decisions and reporting to be made regarding
|
||||
* abandoned objects.
|
||||
*
|
||||
* @param <T> The type of object provided by the pool.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface UsageTracking<T> {
|
||||
|
||||
/**
|
||||
* This method is called every time a pooled object is used to enable the pool to
|
||||
* better track borrowed objects.
|
||||
*
|
||||
* @param pooledObject The object that is being used
|
||||
*/
|
||||
void use(T pooledObject);
|
||||
}
|
||||
292
java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java
Normal file
292
java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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.pool2.impl;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Configuration settings for abandoned object removal.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class AbandonedConfig {
|
||||
|
||||
/**
|
||||
* Whether or not borrowObject performs abandoned object removal.
|
||||
*/
|
||||
private boolean removeAbandonedOnBorrow = false;
|
||||
|
||||
/**
|
||||
* <p>Flag to remove abandoned objects if they exceed the
|
||||
* removeAbandonedTimeout when borrowObject is invoked.</p>
|
||||
*
|
||||
* <p>The default value is false.</p>
|
||||
*
|
||||
* <p>If set to true, abandoned objects are removed by borrowObject if
|
||||
* there are fewer than 2 idle objects available in the pool and
|
||||
* <code>getNumActive() > getMaxTotal() - 3</code></p>
|
||||
*
|
||||
* @return true if abandoned objects are to be removed by borrowObject
|
||||
*/
|
||||
public boolean getRemoveAbandonedOnBorrow() {
|
||||
return this.removeAbandonedOnBorrow;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Flag to remove abandoned objects if they exceed the
|
||||
* removeAbandonedTimeout when borrowObject is invoked.</p>
|
||||
*
|
||||
* @param removeAbandonedOnBorrow true means abandoned objects will be
|
||||
* removed by borrowObject
|
||||
* @see #getRemoveAbandonedOnBorrow()
|
||||
*/
|
||||
public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
|
||||
this.removeAbandonedOnBorrow = removeAbandonedOnBorrow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not pool maintenance (evictor) performs abandoned object
|
||||
* removal.
|
||||
*/
|
||||
private boolean removeAbandonedOnMaintenance = false;
|
||||
|
||||
/**
|
||||
* <p>Flag to remove abandoned objects if they exceed the
|
||||
* removeAbandonedTimeout when pool maintenance (the "evictor")
|
||||
* runs.</p>
|
||||
*
|
||||
* <p>The default value is false.</p>
|
||||
*
|
||||
* <p>If set to true, abandoned objects are removed by the pool
|
||||
* maintenance thread when it runs. This setting has no effect
|
||||
* unless maintenance is enabled by setting
|
||||
*{@link GenericObjectPool#getTimeBetweenEvictionRunsMillis() timeBetweenEvictionRunsMillis}
|
||||
* to a positive number.</p>
|
||||
*
|
||||
* @return true if abandoned objects are to be removed by the evictor
|
||||
*/
|
||||
public boolean getRemoveAbandonedOnMaintenance() {
|
||||
return this.removeAbandonedOnMaintenance;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Flag to remove abandoned objects if they exceed the
|
||||
* removeAbandonedTimeout when pool maintenance runs.</p>
|
||||
*
|
||||
* @param removeAbandonedOnMaintenance true means abandoned objects will be
|
||||
* removed by pool maintenance
|
||||
* @see #getRemoveAbandonedOnMaintenance
|
||||
*/
|
||||
public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
|
||||
this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeout in seconds before an abandoned object can be removed.
|
||||
*/
|
||||
private int removeAbandonedTimeout = 300;
|
||||
|
||||
/**
|
||||
* <p>Timeout in seconds before an abandoned object can be removed.</p>
|
||||
*
|
||||
* <p>The time of most recent use of an object is the maximum (latest) of
|
||||
* {@link org.apache.tomcat.dbcp.pool2.TrackedUse#getLastUsed()}
|
||||
* (if this class of the object implements
|
||||
* TrackedUse) and the time when the object was borrowed from the pool.</p>
|
||||
*
|
||||
* <p>The default value is 300 seconds.</p>
|
||||
*
|
||||
* @return the abandoned object timeout in seconds
|
||||
*/
|
||||
public int getRemoveAbandonedTimeout() {
|
||||
return this.removeAbandonedTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the timeout in seconds before an abandoned object can be
|
||||
* removed</p>
|
||||
*
|
||||
* <p>Setting this property has no effect if
|
||||
* {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and
|
||||
* {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance}
|
||||
* are both false.</p>
|
||||
*
|
||||
* @param removeAbandonedTimeout new abandoned timeout in seconds
|
||||
* @see #getRemoveAbandonedTimeout()
|
||||
*/
|
||||
public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) {
|
||||
this.removeAbandonedTimeout = removeAbandonedTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not to log stack traces for application code
|
||||
* which abandoned an object.
|
||||
*/
|
||||
private boolean logAbandoned = false;
|
||||
|
||||
/**
|
||||
* Flag to log stack traces for application code which abandoned
|
||||
* an object.
|
||||
*
|
||||
* Defaults to false.
|
||||
* Logging of abandoned objects adds overhead for every object created
|
||||
* because a stack trace has to be generated.
|
||||
*
|
||||
* @return boolean true if stack trace logging is turned on for abandoned
|
||||
* objects
|
||||
*
|
||||
*/
|
||||
public boolean getLogAbandoned() {
|
||||
return this.logAbandoned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag to log stack traces for application code which abandoned
|
||||
* an object.
|
||||
*
|
||||
* @param logAbandoned true turns on abandoned stack trace logging
|
||||
* @see #getLogAbandoned()
|
||||
*
|
||||
*/
|
||||
public void setLogAbandoned(final boolean logAbandoned) {
|
||||
this.logAbandoned = logAbandoned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not to log full stack traces when logAbandoned is true.
|
||||
* If disabled, then a faster method for logging stack traces with only class data
|
||||
* may be used if possible.
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
private boolean requireFullStackTrace = true;
|
||||
|
||||
/**
|
||||
* Indicates if full stack traces are required when {@link #getLogAbandoned() logAbandoned}
|
||||
* is true. Defaults to true. Logging of abandoned objects requiring a full stack trace will
|
||||
* generate an entire stack trace to generate for every object created. If this is disabled,
|
||||
* a faster but less informative stack walking mechanism may be used if available.
|
||||
*
|
||||
* @return true if full stack traces are required for logging abandoned connections, or false
|
||||
* if abbreviated stack traces are acceptable
|
||||
* @see CallStack
|
||||
* @since 2.5
|
||||
*/
|
||||
public boolean getRequireFullStackTrace() {
|
||||
return requireFullStackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag to require full stack traces for logging abandoned connections when enabled.
|
||||
*
|
||||
* @param requireFullStackTrace indicates whether or not full stack traces are required in
|
||||
* abandoned connection logs
|
||||
* @see CallStack
|
||||
* @see #getRequireFullStackTrace()
|
||||
* @since 2.5
|
||||
*/
|
||||
public void setRequireFullStackTrace(final boolean requireFullStackTrace) {
|
||||
this.requireFullStackTrace = requireFullStackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* PrintWriter to use to log information on abandoned objects.
|
||||
* Use of default system encoding is deliberate.
|
||||
*/
|
||||
private PrintWriter logWriter = new PrintWriter(System.out);
|
||||
|
||||
/**
|
||||
* Returns the log writer being used by this configuration to log
|
||||
* information on abandoned objects. If not set, a PrintWriter based on
|
||||
* System.out with the system default encoding is used.
|
||||
*
|
||||
* @return log writer in use
|
||||
*/
|
||||
public PrintWriter getLogWriter() {
|
||||
return logWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the log writer to be used by this configuration to log
|
||||
* information on abandoned objects.
|
||||
*
|
||||
* @param logWriter The new log writer
|
||||
*/
|
||||
public void setLogWriter(final PrintWriter logWriter) {
|
||||
this.logWriter = logWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pool implements
|
||||
* {@link org.apache.tomcat.dbcp.pool2.UsageTracking}, should the pool
|
||||
* record a stack trace every time a method is called on a pooled object and
|
||||
* retain the most recent stack trace to aid debugging of abandoned objects?
|
||||
*/
|
||||
private boolean useUsageTracking = false;
|
||||
|
||||
/**
|
||||
* If the pool implements
|
||||
* {@link org.apache.tomcat.dbcp.pool2.UsageTracking}, should the pool
|
||||
* record a
|
||||
* stack trace every time a method is called on a pooled object and retain
|
||||
* the most recent stack trace to aid debugging of abandoned objects?
|
||||
*
|
||||
* @return <code>true</code> if usage tracking is enabled
|
||||
*/
|
||||
public boolean getUseUsageTracking() {
|
||||
return useUsageTracking;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pool implements
|
||||
* {@link org.apache.tomcat.dbcp.pool2.UsageTracking}, configure whether the
|
||||
* pool
|
||||
* should record a stack trace every time a method is called on a pooled
|
||||
* object and retain the most recent stack trace to aid debugging of
|
||||
* abandoned objects.
|
||||
*
|
||||
* @param useUsageTracking A value of <code>true</code> will enable
|
||||
* the recording of a stack trace on every use
|
||||
* of a pooled object
|
||||
*/
|
||||
public void setUseUsageTracking(final boolean useUsageTracking) {
|
||||
this.useUsageTracking = useUsageTracking;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.4.3
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("AbandonedConfig [removeAbandonedOnBorrow=");
|
||||
builder.append(removeAbandonedOnBorrow);
|
||||
builder.append(", removeAbandonedOnMaintenance=");
|
||||
builder.append(removeAbandonedOnMaintenance);
|
||||
builder.append(", removeAbandonedTimeout=");
|
||||
builder.append(removeAbandonedTimeout);
|
||||
builder.append(", logAbandoned=");
|
||||
builder.append(logAbandoned);
|
||||
builder.append(", logWriter=");
|
||||
builder.append(logWriter);
|
||||
builder.append(", useUsageTracking=");
|
||||
builder.append(useUsageTracking);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
1411
java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
Normal file
1411
java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
Normal file
File diff suppressed because it is too large
Load Diff
750
java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
Normal file
750
java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
Normal file
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
* 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.pool2.impl;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.BaseObject;
|
||||
|
||||
/**
|
||||
* Provides the implementation for the common attributes shared by the
|
||||
* sub-classes. New instances of this class will be created using the defaults
|
||||
* defined by the public constants.
|
||||
* <p>
|
||||
* This class is not thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> Type of element pooled.
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Cloneable {
|
||||
|
||||
/**
|
||||
* The default value for the {@code lifo} configuration attribute.
|
||||
* @see GenericObjectPool#getLifo()
|
||||
* @see GenericKeyedObjectPool#getLifo()
|
||||
*/
|
||||
public static final boolean DEFAULT_LIFO = true;
|
||||
|
||||
/**
|
||||
* The default value for the {@code fairness} configuration attribute.
|
||||
* @see GenericObjectPool#getFairness()
|
||||
* @see GenericKeyedObjectPool#getFairness()
|
||||
*/
|
||||
public static final boolean DEFAULT_FAIRNESS = false;
|
||||
|
||||
/**
|
||||
* The default value for the {@code maxWait} configuration attribute.
|
||||
* @see GenericObjectPool#getMaxWaitMillis()
|
||||
* @see GenericKeyedObjectPool#getMaxWaitMillis()
|
||||
*/
|
||||
public static final long DEFAULT_MAX_WAIT_MILLIS = -1L;
|
||||
|
||||
/**
|
||||
* The default value for the {@code minEvictableIdleTimeMillis}
|
||||
* configuration attribute.
|
||||
* @see GenericObjectPool#getMinEvictableIdleTimeMillis()
|
||||
* @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()
|
||||
*/
|
||||
public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS =
|
||||
1000L * 60L * 30L;
|
||||
|
||||
/**
|
||||
* The default value for the {@code softMinEvictableIdleTimeMillis}
|
||||
* configuration attribute.
|
||||
* @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis()
|
||||
* @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()
|
||||
*/
|
||||
public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1;
|
||||
|
||||
/**
|
||||
* The default value for {@code evictorShutdownTimeoutMillis} configuration
|
||||
* attribute.
|
||||
* @see GenericObjectPool#getEvictorShutdownTimeoutMillis()
|
||||
* @see GenericKeyedObjectPool#getEvictorShutdownTimeoutMillis()
|
||||
*/
|
||||
public static final long DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS =
|
||||
10L * 1000L;
|
||||
|
||||
/**
|
||||
* The default value for the {@code numTestsPerEvictionRun} configuration
|
||||
* attribute.
|
||||
* @see GenericObjectPool#getNumTestsPerEvictionRun()
|
||||
* @see GenericKeyedObjectPool#getNumTestsPerEvictionRun()
|
||||
*/
|
||||
public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
|
||||
|
||||
/**
|
||||
* The default value for the {@code testOnCreate} configuration attribute.
|
||||
* @see GenericObjectPool#getTestOnCreate()
|
||||
* @see GenericKeyedObjectPool#getTestOnCreate()
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public static final boolean DEFAULT_TEST_ON_CREATE = false;
|
||||
|
||||
/**
|
||||
* The default value for the {@code testOnBorrow} configuration attribute.
|
||||
* @see GenericObjectPool#getTestOnBorrow()
|
||||
* @see GenericKeyedObjectPool#getTestOnBorrow()
|
||||
*/
|
||||
public static final boolean DEFAULT_TEST_ON_BORROW = false;
|
||||
|
||||
/**
|
||||
* The default value for the {@code testOnReturn} configuration attribute.
|
||||
* @see GenericObjectPool#getTestOnReturn()
|
||||
* @see GenericKeyedObjectPool#getTestOnReturn()
|
||||
*/
|
||||
public static final boolean DEFAULT_TEST_ON_RETURN = false;
|
||||
|
||||
/**
|
||||
* The default value for the {@code testWhileIdle} configuration attribute.
|
||||
* @see GenericObjectPool#getTestWhileIdle()
|
||||
* @see GenericKeyedObjectPool#getTestWhileIdle()
|
||||
*/
|
||||
public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
|
||||
|
||||
/**
|
||||
* The default value for the {@code timeBetweenEvictionRunsMillis}
|
||||
* configuration attribute.
|
||||
* @see GenericObjectPool#getTimeBetweenEvictionRunsMillis()
|
||||
* @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()
|
||||
*/
|
||||
public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
|
||||
|
||||
/**
|
||||
* The default value for the {@code blockWhenExhausted} configuration
|
||||
* attribute.
|
||||
* @see GenericObjectPool#getBlockWhenExhausted()
|
||||
* @see GenericKeyedObjectPool#getBlockWhenExhausted()
|
||||
*/
|
||||
public static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true;
|
||||
|
||||
/**
|
||||
* The default value for enabling JMX for pools created with a configuration
|
||||
* instance.
|
||||
*/
|
||||
public static final boolean DEFAULT_JMX_ENABLE = true;
|
||||
|
||||
/**
|
||||
* The default value for the prefix used to name JMX enabled pools created
|
||||
* with a configuration instance.
|
||||
* @see GenericObjectPool#getJmxName()
|
||||
* @see GenericKeyedObjectPool#getJmxName()
|
||||
*/
|
||||
public static final String DEFAULT_JMX_NAME_PREFIX = "pool";
|
||||
|
||||
/**
|
||||
* The default value for the base name to use to name JMX enabled pools
|
||||
* created with a configuration instance. The default is <code>null</code>
|
||||
* which means the pool will provide the base name to use.
|
||||
* @see GenericObjectPool#getJmxName()
|
||||
* @see GenericKeyedObjectPool#getJmxName()
|
||||
*/
|
||||
public static final String DEFAULT_JMX_NAME_BASE = null;
|
||||
|
||||
/**
|
||||
* The default value for the {@code evictionPolicyClassName} configuration
|
||||
* attribute.
|
||||
* @see GenericObjectPool#getEvictionPolicyClassName()
|
||||
* @see GenericKeyedObjectPool#getEvictionPolicyClassName()
|
||||
*/
|
||||
public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = DefaultEvictionPolicy.class.getName();
|
||||
|
||||
private boolean lifo = DEFAULT_LIFO;
|
||||
|
||||
private boolean fairness = DEFAULT_FAIRNESS;
|
||||
|
||||
private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS;
|
||||
|
||||
private long minEvictableIdleTimeMillis =
|
||||
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
|
||||
|
||||
private long evictorShutdownTimeoutMillis =
|
||||
DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
|
||||
|
||||
private long softMinEvictableIdleTimeMillis =
|
||||
DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
|
||||
|
||||
private int numTestsPerEvictionRun =
|
||||
DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
|
||||
|
||||
private EvictionPolicy<T> evictionPolicy = null; // Only 2.6.0 applications set this
|
||||
|
||||
private String evictionPolicyClassName = DEFAULT_EVICTION_POLICY_CLASS_NAME;
|
||||
|
||||
private boolean testOnCreate = DEFAULT_TEST_ON_CREATE;
|
||||
|
||||
private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;
|
||||
|
||||
private boolean testOnReturn = DEFAULT_TEST_ON_RETURN;
|
||||
|
||||
private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE;
|
||||
|
||||
private long timeBetweenEvictionRunsMillis =
|
||||
DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
|
||||
|
||||
private boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED;
|
||||
|
||||
private boolean jmxEnabled = DEFAULT_JMX_ENABLE;
|
||||
|
||||
// TODO Consider changing this to a single property for 3.x
|
||||
private String jmxNamePrefix = DEFAULT_JMX_NAME_PREFIX;
|
||||
|
||||
private String jmxNameBase = DEFAULT_JMX_NAME_BASE;
|
||||
|
||||
|
||||
/**
|
||||
* Get the value for the {@code lifo} configuration attribute for pools
|
||||
* created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code lifo} for this configuration
|
||||
* instance
|
||||
*
|
||||
* @see GenericObjectPool#getLifo()
|
||||
* @see GenericKeyedObjectPool#getLifo()
|
||||
*/
|
||||
public boolean getLifo() {
|
||||
return lifo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code fairness} configuration attribute for pools
|
||||
* created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code fairness} for this configuration
|
||||
* instance
|
||||
*
|
||||
* @see GenericObjectPool#getFairness()
|
||||
* @see GenericKeyedObjectPool#getFairness()
|
||||
*/
|
||||
public boolean getFairness() {
|
||||
return fairness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code lifo} configuration attribute for pools
|
||||
* created with this configuration instance.
|
||||
*
|
||||
* @param lifo The new setting of {@code lifo}
|
||||
* for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getLifo()
|
||||
* @see GenericKeyedObjectPool#getLifo()
|
||||
*/
|
||||
public void setLifo(final boolean lifo) {
|
||||
this.lifo = lifo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code fairness} configuration attribute for pools
|
||||
* created with this configuration instance.
|
||||
*
|
||||
* @param fairness The new setting of {@code fairness}
|
||||
* for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getFairness()
|
||||
* @see GenericKeyedObjectPool#getFairness()
|
||||
*/
|
||||
public void setFairness(final boolean fairness) {
|
||||
this.fairness = fairness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code maxWait} configuration attribute for pools
|
||||
* created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code maxWait} for this
|
||||
* configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getMaxWaitMillis()
|
||||
* @see GenericKeyedObjectPool#getMaxWaitMillis()
|
||||
*/
|
||||
public long getMaxWaitMillis() {
|
||||
return maxWaitMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code maxWait} configuration attribute for pools
|
||||
* created with this configuration instance.
|
||||
*
|
||||
* @param maxWaitMillis The new setting of {@code maxWaitMillis}
|
||||
* for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getMaxWaitMillis()
|
||||
* @see GenericKeyedObjectPool#getMaxWaitMillis()
|
||||
*/
|
||||
public void setMaxWaitMillis(final long maxWaitMillis) {
|
||||
this.maxWaitMillis = maxWaitMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code minEvictableIdleTimeMillis} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code minEvictableIdleTimeMillis} for
|
||||
* this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getMinEvictableIdleTimeMillis()
|
||||
* @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()
|
||||
*/
|
||||
public long getMinEvictableIdleTimeMillis() {
|
||||
return minEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code minEvictableIdleTimeMillis} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @param minEvictableIdleTimeMillis The new setting of
|
||||
* {@code minEvictableIdleTimeMillis} for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getMinEvictableIdleTimeMillis()
|
||||
* @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()
|
||||
*/
|
||||
public void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
|
||||
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code softMinEvictableIdleTimeMillis}
|
||||
* configuration attribute for pools created with this configuration
|
||||
* instance.
|
||||
*
|
||||
* @return The current setting of {@code softMinEvictableIdleTimeMillis}
|
||||
* for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis()
|
||||
* @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()
|
||||
*/
|
||||
public long getSoftMinEvictableIdleTimeMillis() {
|
||||
return softMinEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code softMinEvictableIdleTimeMillis}
|
||||
* configuration attribute for pools created with this configuration
|
||||
* instance.
|
||||
*
|
||||
* @param softMinEvictableIdleTimeMillis The new setting of
|
||||
* {@code softMinEvictableIdleTimeMillis} for this configuration
|
||||
* instance
|
||||
*
|
||||
* @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis()
|
||||
* @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()
|
||||
*/
|
||||
public void setSoftMinEvictableIdleTimeMillis(
|
||||
final long softMinEvictableIdleTimeMillis) {
|
||||
this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code numTestsPerEvictionRun} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code numTestsPerEvictionRun} for this
|
||||
* configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getNumTestsPerEvictionRun()
|
||||
* @see GenericKeyedObjectPool#getNumTestsPerEvictionRun()
|
||||
*/
|
||||
public int getNumTestsPerEvictionRun() {
|
||||
return numTestsPerEvictionRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code numTestsPerEvictionRun} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @param numTestsPerEvictionRun The new setting of
|
||||
* {@code numTestsPerEvictionRun} for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getNumTestsPerEvictionRun()
|
||||
* @see GenericKeyedObjectPool#getNumTestsPerEvictionRun()
|
||||
*/
|
||||
public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
|
||||
this.numTestsPerEvictionRun = numTestsPerEvictionRun;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code evictorShutdownTimeoutMillis} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code evictorShutdownTimeoutMillis} for
|
||||
* this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getEvictorShutdownTimeoutMillis()
|
||||
* @see GenericKeyedObjectPool#getEvictorShutdownTimeoutMillis()
|
||||
*/
|
||||
public long getEvictorShutdownTimeoutMillis() {
|
||||
return evictorShutdownTimeoutMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code evictorShutdownTimeoutMillis} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @param evictorShutdownTimeoutMillis The new setting of
|
||||
* {@code evictorShutdownTimeoutMillis} for this configuration
|
||||
* instance
|
||||
*
|
||||
* @see GenericObjectPool#getEvictorShutdownTimeoutMillis()
|
||||
* @see GenericKeyedObjectPool#getEvictorShutdownTimeoutMillis()
|
||||
*/
|
||||
public void setEvictorShutdownTimeoutMillis(
|
||||
final long evictorShutdownTimeoutMillis) {
|
||||
this.evictorShutdownTimeoutMillis = evictorShutdownTimeoutMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code testOnCreate} configuration attribute for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code testOnCreate} for this
|
||||
* configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getTestOnCreate()
|
||||
* @see GenericKeyedObjectPool#getTestOnCreate()
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public boolean getTestOnCreate() {
|
||||
return testOnCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code testOnCreate} configuration attribute for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @param testOnCreate The new setting of {@code testOnCreate}
|
||||
* for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getTestOnCreate()
|
||||
* @see GenericKeyedObjectPool#getTestOnCreate()
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public void setTestOnCreate(final boolean testOnCreate) {
|
||||
this.testOnCreate = testOnCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code testOnBorrow} configuration attribute for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code testOnBorrow} for this
|
||||
* configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getTestOnBorrow()
|
||||
* @see GenericKeyedObjectPool#getTestOnBorrow()
|
||||
*/
|
||||
public boolean getTestOnBorrow() {
|
||||
return testOnBorrow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code testOnBorrow} configuration attribute for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @param testOnBorrow The new setting of {@code testOnBorrow}
|
||||
* for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getTestOnBorrow()
|
||||
* @see GenericKeyedObjectPool#getTestOnBorrow()
|
||||
*/
|
||||
public void setTestOnBorrow(final boolean testOnBorrow) {
|
||||
this.testOnBorrow = testOnBorrow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code testOnReturn} configuration attribute for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code testOnReturn} for this
|
||||
* configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getTestOnReturn()
|
||||
* @see GenericKeyedObjectPool#getTestOnReturn()
|
||||
*/
|
||||
public boolean getTestOnReturn() {
|
||||
return testOnReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code testOnReturn} configuration attribute for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @param testOnReturn The new setting of {@code testOnReturn}
|
||||
* for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getTestOnReturn()
|
||||
* @see GenericKeyedObjectPool#getTestOnReturn()
|
||||
*/
|
||||
public void setTestOnReturn(final boolean testOnReturn) {
|
||||
this.testOnReturn = testOnReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code testWhileIdle} configuration attribute for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code testWhileIdle} for this
|
||||
* configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getTestWhileIdle()
|
||||
* @see GenericKeyedObjectPool#getTestWhileIdle()
|
||||
*/
|
||||
public boolean getTestWhileIdle() {
|
||||
return testWhileIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code testWhileIdle} configuration attribute for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @param testWhileIdle The new setting of {@code testWhileIdle}
|
||||
* for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getTestWhileIdle()
|
||||
* @see GenericKeyedObjectPool#getTestWhileIdle()
|
||||
*/
|
||||
public void setTestWhileIdle(final boolean testWhileIdle) {
|
||||
this.testWhileIdle = testWhileIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code timeBetweenEvictionRunsMillis} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code timeBetweenEvictionRunsMillis} for
|
||||
* this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getTimeBetweenEvictionRunsMillis()
|
||||
* @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()
|
||||
*/
|
||||
public long getTimeBetweenEvictionRunsMillis() {
|
||||
return timeBetweenEvictionRunsMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code timeBetweenEvictionRunsMillis} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @param timeBetweenEvictionRunsMillis The new setting of
|
||||
* {@code timeBetweenEvictionRunsMillis} for this configuration
|
||||
* instance
|
||||
*
|
||||
* @see GenericObjectPool#getTimeBetweenEvictionRunsMillis()
|
||||
* @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()
|
||||
*/
|
||||
public void setTimeBetweenEvictionRunsMillis(
|
||||
final long timeBetweenEvictionRunsMillis) {
|
||||
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code evictionPolicyClass} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code evictionPolicyClass} for this
|
||||
* configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getEvictionPolicy()
|
||||
* @see GenericKeyedObjectPool#getEvictionPolicy()
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public EvictionPolicy<T> getEvictionPolicy() {
|
||||
return evictionPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code evictionPolicyClassName} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code evictionPolicyClassName} for this
|
||||
* configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getEvictionPolicyClassName()
|
||||
* @see GenericKeyedObjectPool#getEvictionPolicyClassName()
|
||||
*/
|
||||
public String getEvictionPolicyClassName() {
|
||||
return evictionPolicyClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code evictionPolicyClass} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @param evictionPolicy The new setting of
|
||||
* {@code evictionPolicyClass} for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getEvictionPolicy()
|
||||
* @see GenericKeyedObjectPool#getEvictionPolicy()
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public void setEvictionPolicy(final EvictionPolicy<T> evictionPolicy) {
|
||||
this.evictionPolicy = evictionPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code evictionPolicyClassName} configuration
|
||||
* attribute for pools created with this configuration instance.
|
||||
*
|
||||
* @param evictionPolicyClassName The new setting of
|
||||
* {@code evictionPolicyClassName} for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getEvictionPolicyClassName()
|
||||
* @see GenericKeyedObjectPool#getEvictionPolicyClassName()
|
||||
*/
|
||||
public void setEvictionPolicyClassName(final String evictionPolicyClassName) {
|
||||
this.evictionPolicyClassName = evictionPolicyClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the {@code blockWhenExhausted} configuration attribute
|
||||
* for pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code blockWhenExhausted} for this
|
||||
* configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getBlockWhenExhausted()
|
||||
* @see GenericKeyedObjectPool#getBlockWhenExhausted()
|
||||
*/
|
||||
public boolean getBlockWhenExhausted() {
|
||||
return blockWhenExhausted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the {@code blockWhenExhausted} configuration attribute
|
||||
* for pools created with this configuration instance.
|
||||
*
|
||||
* @param blockWhenExhausted The new setting of {@code blockWhenExhausted}
|
||||
* for this configuration instance
|
||||
*
|
||||
* @see GenericObjectPool#getBlockWhenExhausted()
|
||||
* @see GenericKeyedObjectPool#getBlockWhenExhausted()
|
||||
*/
|
||||
public void setBlockWhenExhausted(final boolean blockWhenExhausted) {
|
||||
this.blockWhenExhausted = blockWhenExhausted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the flag that determines if JMX will be enabled for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @return The current setting of {@code jmxEnabled} for this configuration
|
||||
* instance
|
||||
*/
|
||||
public boolean getJmxEnabled() {
|
||||
return jmxEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the flag that determines if JMX will be enabled for
|
||||
* pools created with this configuration instance.
|
||||
*
|
||||
* @param jmxEnabled The new setting of {@code jmxEnabled}
|
||||
* for this configuration instance
|
||||
*/
|
||||
public void setJmxEnabled(final boolean jmxEnabled) {
|
||||
this.jmxEnabled = jmxEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the JMX name base that will be used as part of the
|
||||
* name assigned to JMX enabled pools created with this configuration
|
||||
* instance. A value of <code>null</code> means that the pool will define
|
||||
* the JMX name base.
|
||||
*
|
||||
* @return The current setting of {@code jmxNameBase} for this
|
||||
* configuration instance
|
||||
*/
|
||||
public String getJmxNameBase() {
|
||||
return jmxNameBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the JMX name base that will be used as part of the
|
||||
* name assigned to JMX enabled pools created with this configuration
|
||||
* instance. A value of <code>null</code> means that the pool will define
|
||||
* the JMX name base.
|
||||
*
|
||||
* @param jmxNameBase The new setting of {@code jmxNameBase}
|
||||
* for this configuration instance
|
||||
*/
|
||||
public void setJmxNameBase(final String jmxNameBase) {
|
||||
this.jmxNameBase = jmxNameBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the JMX name prefix that will be used as part of the
|
||||
* name assigned to JMX enabled pools created with this configuration
|
||||
* instance.
|
||||
*
|
||||
* @return The current setting of {@code jmxNamePrefix} for this
|
||||
* configuration instance
|
||||
*/
|
||||
public String getJmxNamePrefix() {
|
||||
return jmxNamePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the JMX name prefix that will be used as part of the
|
||||
* name assigned to JMX enabled pools created with this configuration
|
||||
* instance.
|
||||
*
|
||||
* @param jmxNamePrefix The new setting of {@code jmxNamePrefix}
|
||||
* for this configuration instance
|
||||
*/
|
||||
public void setJmxNamePrefix(final String jmxNamePrefix) {
|
||||
this.jmxNamePrefix = jmxNamePrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toStringAppendFields(final StringBuilder builder) {
|
||||
builder.append("lifo=");
|
||||
builder.append(lifo);
|
||||
builder.append(", fairness=");
|
||||
builder.append(fairness);
|
||||
builder.append(", maxWaitMillis=");
|
||||
builder.append(maxWaitMillis);
|
||||
builder.append(", minEvictableIdleTimeMillis=");
|
||||
builder.append(minEvictableIdleTimeMillis);
|
||||
builder.append(", softMinEvictableIdleTimeMillis=");
|
||||
builder.append(softMinEvictableIdleTimeMillis);
|
||||
builder.append(", numTestsPerEvictionRun=");
|
||||
builder.append(numTestsPerEvictionRun);
|
||||
builder.append(", evictionPolicyClassName=");
|
||||
builder.append(evictionPolicyClassName);
|
||||
builder.append(", testOnCreate=");
|
||||
builder.append(testOnCreate);
|
||||
builder.append(", testOnBorrow=");
|
||||
builder.append(testOnBorrow);
|
||||
builder.append(", testOnReturn=");
|
||||
builder.append(testOnReturn);
|
||||
builder.append(", testWhileIdle=");
|
||||
builder.append(testWhileIdle);
|
||||
builder.append(", timeBetweenEvictionRunsMillis=");
|
||||
builder.append(timeBetweenEvictionRunsMillis);
|
||||
builder.append(", blockWhenExhausted=");
|
||||
builder.append(blockWhenExhausted);
|
||||
builder.append(", jmxEnabled=");
|
||||
builder.append(jmxEnabled);
|
||||
builder.append(", jmxNamePrefix=");
|
||||
builder.append(jmxNamePrefix);
|
||||
builder.append(", jmxNameBase=");
|
||||
builder.append(jmxNameBase);
|
||||
}
|
||||
}
|
||||
52
java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
Normal file
52
java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.pool2.impl;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Strategy for obtaining and printing the current call stack. This is primarily useful for
|
||||
* {@link org.apache.tomcat.dbcp.pool2.UsageTracking usage tracking} so
|
||||
* that different JVMs and configurations can use more efficient strategies
|
||||
* for obtaining the current call stack depending on metadata needs.
|
||||
*
|
||||
* @see CallStackUtils
|
||||
* @since 2.4.3
|
||||
*/
|
||||
public interface CallStack {
|
||||
|
||||
/**
|
||||
* Prints the current stack trace if available to a PrintWriter. The format is undefined and is primarily useful
|
||||
* for debugging issues with {@link org.apache.tomcat.dbcp.pool2.PooledObject} usage in user code.
|
||||
*
|
||||
* @param writer a PrintWriter to write the current stack trace to if available
|
||||
* @return true if a stack trace was available to print or false if nothing was printed
|
||||
*/
|
||||
boolean printStackTrace(final PrintWriter writer);
|
||||
|
||||
/**
|
||||
* Takes a snapshot of the current call stack. Subsequent calls to {@link #printStackTrace(PrintWriter)} will print
|
||||
* out that stack trace until it is {@linkplain #clear() cleared}.
|
||||
*/
|
||||
void fillInStackTrace();
|
||||
|
||||
/**
|
||||
* Clears the current stack trace snapshot. Subsequent calls to {@link #printStackTrace(PrintWriter)} will be
|
||||
* no-ops until another call to {@link #fillInStackTrace()}.
|
||||
*/
|
||||
void clear();
|
||||
}
|
||||
85
java/org/apache/tomcat/dbcp/pool2/impl/CallStackUtils.java
Normal file
85
java/org/apache/tomcat/dbcp/pool2/impl/CallStackUtils.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.pool2.impl;
|
||||
|
||||
import java.security.AccessControlException;
|
||||
|
||||
/**
|
||||
* Utility methods for {@link CallStack}.
|
||||
*
|
||||
* @since 2.4.3
|
||||
*/
|
||||
public final class CallStackUtils {
|
||||
|
||||
/**
|
||||
* Returns whether the caller can create a security manager in the current environment.
|
||||
*
|
||||
* @return {@code true} if it is able to create a security manager in the current environment, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
private static boolean canCreateSecurityManager() {
|
||||
final SecurityManager manager = System.getSecurityManager();
|
||||
if (manager == null) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
manager.checkPermission(new RuntimePermission("createSecurityManager"));
|
||||
return true;
|
||||
} catch (final AccessControlException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link CallStack} using the fastest allowed strategy.
|
||||
*
|
||||
* @param messageFormat message (or format) to print first in stack traces
|
||||
* @param useTimestamp if true, interpret message as a SimpleDateFormat and print the created timestamp; otherwise,
|
||||
* print message format literally
|
||||
* @return a new CallStack
|
||||
* @deprecated use {@link #newCallStack(String, boolean, boolean)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static CallStack newCallStack(final String messageFormat, final boolean useTimestamp) {
|
||||
return newCallStack(messageFormat, useTimestamp, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link CallStack} using the fasted allowed strategy.
|
||||
*
|
||||
* @param messageFormat message (or format) to print first in stack traces
|
||||
* @param useTimestamp if true, interpret message as a SimpleDateFormat and print the created timestamp;
|
||||
* otherwise, print message format literally
|
||||
* @param requireFullStackTrace if true, forces the use of a stack walking mechanism that includes full stack trace
|
||||
* information; otherwise, uses a faster implementation if possible
|
||||
* @return a new CallStack
|
||||
* @since 2.5
|
||||
*/
|
||||
public static CallStack newCallStack(final String messageFormat,
|
||||
final boolean useTimestamp,
|
||||
final boolean requireFullStackTrace) {
|
||||
return canCreateSecurityManager() && !requireFullStackTrace
|
||||
? new SecurityManagerCallStack(messageFormat, useTimestamp)
|
||||
: new ThrowableCallStack(messageFormat, useTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden constructor.
|
||||
*/
|
||||
private CallStackUtils() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.pool2.impl;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.PooledObject;
|
||||
|
||||
/**
|
||||
* Provides the default implementation of {@link EvictionPolicy} used by the
|
||||
* pools. Objects will be evicted if the following conditions are met:
|
||||
* <ul>
|
||||
* <li>the object has been idle longer than
|
||||
* {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} /
|
||||
* {@link GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()}</li>
|
||||
* <li>there are more than {@link GenericObjectPool#getMinIdle()} /
|
||||
* {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} idle objects in
|
||||
* the pool and the object has been idle for longer than
|
||||
* {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} /
|
||||
* {@link GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()}
|
||||
* </ul>
|
||||
* <p>
|
||||
* This class is immutable and thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of objects in the pool
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DefaultEvictionPolicy<T> implements EvictionPolicy<T> {
|
||||
|
||||
@Override
|
||||
public boolean evict(final EvictionConfig config, final PooledObject<T> underTest,
|
||||
final int idleCount) {
|
||||
|
||||
if ((config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() &&
|
||||
config.getMinIdle() < idleCount) ||
|
||||
config.getIdleEvictTime() < underTest.getIdleTimeMillis()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
298
java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
Normal file
298
java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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.pool2.impl;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Deque;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.PooledObject;
|
||||
import org.apache.tomcat.dbcp.pool2.PooledObjectState;
|
||||
import org.apache.tomcat.dbcp.pool2.TrackedUse;
|
||||
|
||||
/**
|
||||
* This wrapper is used to track the additional information, such as state, for
|
||||
* the pooled objects.
|
||||
* <p>
|
||||
* This class is intended to be thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @param <T> the type of object in the pool
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DefaultPooledObject<T> implements PooledObject<T> {
|
||||
|
||||
private final T object;
|
||||
private PooledObjectState state = PooledObjectState.IDLE; // @GuardedBy("this") to ensure transitions are valid
|
||||
private final long createTime = System.currentTimeMillis();
|
||||
private volatile long lastBorrowTime = createTime;
|
||||
private volatile long lastUseTime = createTime;
|
||||
private volatile long lastReturnTime = createTime;
|
||||
private volatile boolean logAbandoned = false;
|
||||
private volatile CallStack borrowedBy = NoOpCallStack.INSTANCE;
|
||||
private volatile CallStack usedBy = NoOpCallStack.INSTANCE;
|
||||
private volatile long borrowedCount = 0;
|
||||
|
||||
/**
|
||||
* Creates a new instance that wraps the provided object so that the pool can
|
||||
* track the state of the pooled object.
|
||||
*
|
||||
* @param object The object to wrap
|
||||
*/
|
||||
public DefaultPooledObject(final T object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getActiveTimeMillis() {
|
||||
// Take copies to avoid threading issues
|
||||
final long rTime = lastReturnTime;
|
||||
final long bTime = lastBorrowTime;
|
||||
|
||||
if (rTime > bTime) {
|
||||
return rTime - bTime;
|
||||
}
|
||||
return System.currentTimeMillis() - bTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIdleTimeMillis() {
|
||||
final long elapsed = System.currentTimeMillis() - lastReturnTime;
|
||||
// elapsed may be negative if:
|
||||
// - another thread updates lastReturnTime during the calculation window
|
||||
// - System.currentTimeMillis() is not monotonic (e.g. system time is set back)
|
||||
return elapsed >= 0 ? elapsed : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastBorrowTime() {
|
||||
return lastBorrowTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastReturnTime() {
|
||||
return lastReturnTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times this object has been borrowed.
|
||||
* @return The number of times this object has been borrowed.
|
||||
* @since 2.1
|
||||
*/
|
||||
@Override
|
||||
public long getBorrowedCount() {
|
||||
return borrowedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an estimate of the last time this object was used. If the class
|
||||
* of the pooled object implements {@link TrackedUse}, what is returned is
|
||||
* the maximum of {@link TrackedUse#getLastUsed()} and
|
||||
* {@link #getLastBorrowTime()}; otherwise this method gives the same
|
||||
* value as {@link #getLastBorrowTime()}.
|
||||
*
|
||||
* @return the last time this object was used
|
||||
*/
|
||||
@Override
|
||||
public long getLastUsedTime() {
|
||||
if (object instanceof TrackedUse) {
|
||||
return Math.max(((TrackedUse) object).getLastUsed(), lastUseTime);
|
||||
}
|
||||
return lastUseTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final PooledObject<T> other) {
|
||||
final long lastActiveDiff = this.getLastReturnTime() - other.getLastReturnTime();
|
||||
if (lastActiveDiff == 0) {
|
||||
// Make sure the natural ordering is broadly consistent with equals
|
||||
// although this will break down if distinct objects have the same
|
||||
// identity hash code.
|
||||
// see java.lang.Comparable Javadocs
|
||||
return System.identityHashCode(this) - System.identityHashCode(other);
|
||||
}
|
||||
// handle int overflow
|
||||
return (int)Math.min(Math.max(lastActiveDiff, Integer.MIN_VALUE), Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
result.append("Object: ");
|
||||
result.append(object.toString());
|
||||
result.append(", State: ");
|
||||
synchronized (this) {
|
||||
result.append(state.toString());
|
||||
}
|
||||
return result.toString();
|
||||
// TODO add other attributes
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean startEvictionTest() {
|
||||
if (state == PooledObjectState.IDLE) {
|
||||
state = PooledObjectState.EVICTION;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean endEvictionTest(
|
||||
final Deque<PooledObject<T>> idleQueue) {
|
||||
if (state == PooledObjectState.EVICTION) {
|
||||
state = PooledObjectState.IDLE;
|
||||
return true;
|
||||
} else if (state == PooledObjectState.EVICTION_RETURN_TO_HEAD) {
|
||||
state = PooledObjectState.IDLE;
|
||||
if (!idleQueue.offerFirst(this)) {
|
||||
// TODO - Should never happen
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates the object.
|
||||
*
|
||||
* @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
|
||||
*/
|
||||
@Override
|
||||
public synchronized boolean allocate() {
|
||||
if (state == PooledObjectState.IDLE) {
|
||||
state = PooledObjectState.ALLOCATED;
|
||||
lastBorrowTime = System.currentTimeMillis();
|
||||
lastUseTime = lastBorrowTime;
|
||||
borrowedCount++;
|
||||
if (logAbandoned) {
|
||||
borrowedBy.fillInStackTrace();
|
||||
}
|
||||
return true;
|
||||
} else if (state == PooledObjectState.EVICTION) {
|
||||
// TODO Allocate anyway and ignore eviction test
|
||||
state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
|
||||
return false;
|
||||
}
|
||||
// TODO if validating and testOnBorrow == true then pre-allocate for
|
||||
// performance
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE}
|
||||
* if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}.
|
||||
*
|
||||
* @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED}
|
||||
*/
|
||||
@Override
|
||||
public synchronized boolean deallocate() {
|
||||
if (state == PooledObjectState.ALLOCATED ||
|
||||
state == PooledObjectState.RETURNING) {
|
||||
state = PooledObjectState.IDLE;
|
||||
lastReturnTime = System.currentTimeMillis();
|
||||
borrowedBy.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state to {@link PooledObjectState#INVALID INVALID}
|
||||
*/
|
||||
@Override
|
||||
public synchronized void invalidate() {
|
||||
state = PooledObjectState.INVALID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void use() {
|
||||
lastUseTime = System.currentTimeMillis();
|
||||
usedBy.fillInStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printStackTrace(final PrintWriter writer) {
|
||||
boolean written = borrowedBy.printStackTrace(writer);
|
||||
written |= usedBy.printStackTrace(writer);
|
||||
if (written) {
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the state of this object.
|
||||
* @return state
|
||||
*/
|
||||
@Override
|
||||
public synchronized PooledObjectState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the pooled object as abandoned.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void markAbandoned() {
|
||||
state = PooledObjectState.ABANDONED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the object as returning to the pool.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void markReturning() {
|
||||
state = PooledObjectState.RETURNING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogAbandoned(final boolean logAbandoned) {
|
||||
this.logAbandoned = logAbandoned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the stack trace generation strategy based on whether or not fully
|
||||
* detailed stack traces are required. When set to false, abandoned logs may
|
||||
* only include caller class information rather than method names, line numbers,
|
||||
* and other normal metadata available in a full stack trace.
|
||||
*
|
||||
* @param requireFullStackTrace the new configuration setting for abandoned object
|
||||
* logging
|
||||
* @since 2.5
|
||||
*/
|
||||
@Override
|
||||
public void setRequireFullStackTrace(final boolean requireFullStackTrace) {
|
||||
borrowedBy = CallStackUtils.newCallStack("'Pooled object created' " +
|
||||
"yyyy-MM-dd HH:mm:ss Z 'by the following code has not been returned to the pool:'",
|
||||
true, requireFullStackTrace);
|
||||
usedBy = CallStackUtils.newCallStack("The last code to use this object was:",
|
||||
false, requireFullStackTrace);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.pool2.impl;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import org.apache.tomcat.dbcp.pool2.PooledObject;
|
||||
|
||||
/**
|
||||
* Implementation of object that is used to provide information on pooled
|
||||
* objects via JMX.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DefaultPooledObjectInfo implements DefaultPooledObjectInfoMBean {
|
||||
|
||||
private final PooledObject<?> pooledObject;
|
||||
|
||||
/**
|
||||
* Create a new instance for the given pooled object.
|
||||
*
|
||||
* @param pooledObject The pooled object that this instance will represent
|
||||
*/
|
||||
public DefaultPooledObjectInfo(final PooledObject<?> pooledObject) {
|
||||
this.pooledObject = pooledObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCreateTime() {
|
||||
return pooledObject.getCreateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCreateTimeFormatted() {
|
||||
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
return sdf.format(Long.valueOf(pooledObject.getCreateTime()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastBorrowTime() {
|
||||
return pooledObject.getLastBorrowTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLastBorrowTimeFormatted() {
|
||||
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
return sdf.format(Long.valueOf(pooledObject.getLastBorrowTime()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLastBorrowTrace() {
|
||||
final StringWriter sw = new StringWriter();
|
||||
pooledObject.printStackTrace(new PrintWriter(sw));
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastReturnTime() {
|
||||
return pooledObject.getLastReturnTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLastReturnTimeFormatted() {
|
||||
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
return sdf.format(Long.valueOf(pooledObject.getLastReturnTime()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPooledObjectType() {
|
||||
return pooledObject.getObject().getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPooledObjectToString() {
|
||||
return pooledObject.getObject().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBorrowedCount() {
|
||||
return pooledObject.getBorrowedCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.4.3
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("DefaultPooledObjectInfo [pooledObject=");
|
||||
builder.append(pooledObject);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user