This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View 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);
}

View 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;
}

View 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);
}
}

View 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();
}

View 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;
}

View 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);
}

View 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
}

View 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);
}

View 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;
}

View 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();
}

View 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;
}
}

View 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;
}
}
}
}

View 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);
}
}
}
}
}
}

View 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( "&amp;" );
break;
case '<':
result.append( "&lt;" );
break;
default:
result.append( c );
}
}
out.print( result.toString() + LINE_SEPARATOR );
}
// Output footer:
out.print( "</pre></body></html>" );
}
}
}
}

View 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;
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View 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.";
}

View 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);
}
}
}
}

View 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();
}
}
}

View 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;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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();
}

View 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;
}

View File

@@ -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);
}
}

View 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";
}

View File

@@ -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;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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.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) + "]";
}
}

View 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;
}
}

View 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.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;
}
}

View 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()");
}
}
}

View File

@@ -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);
}
}

View 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;
}
}

View 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.

View 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

View 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

View 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=内部オブジェクトプールが例外を飲み込みました。

View 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=내부 객체 풀이 예외 발생을 무시했습니다.

View File

@@ -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=一个内部对象池吞并了一个异常。

View 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;
}
}

File diff suppressed because it is too large Load Diff

View 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();
}
}

View 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;
}
}

Some files were not shown because too many files have changed in this diff Show More