Author: fhanik Date: Thu Aug 7 20:15:19 2014 New Revision: 1616584 URL: http://svn.apache.org/r1616584 Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=53853 Dynamic class loading of driver, validator and interceptors can be done from libraries on the context class loader. Behavior is partly backwards compatible, always try the current loader first, but then attempts the current thread's context class loader
Added: tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ClassLoaderUtil.java (with props) Modified: tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java Modified: tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml?rev=1616584&r1=1616583&r2=1616584&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml (original) +++ tomcat/trunk/modules/jdbc-pool/doc/jdbc-pool.xml Thu Aug 7 20:15:19 2014 @@ -170,6 +170,22 @@ </attribute> </attributes> </subsection> + + <subsection name="System Properties"> + <p>System properties are JVM wide, affect all pools created in the JVM</p> + <attributes> + <attribute name="org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader" required="false"> + <p>(boolean) Controls classloading of dynamic classes, such as + jdbc drivers, interceptors and validators. If set to false, default value, + the pool will first attempt to load using the current loader and if class loading fails + attempt to load using the thread context loader. + Set this value to try, if you wish to remain backwards compatible, + Apache Tomcat 8.0.8 and earlier, and only attempt the current loader. + If not set then the default value is <code>false</code>.) + </p> + </attribute> + </attributes> + </subsection> <subsection name="Common Attributes"> <p>These attributes are shared between commons-dbcp and tomcat-jdbc-pool, in some cases default values are different.</p> Modified: tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java?rev=1616584&r1=1616583&r2=1616584&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java (original) +++ tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/naming/GenericNamingResourcesFactory.java Thu Aug 7 20:15:19 2014 @@ -31,6 +31,8 @@ import javax.naming.spi.ObjectFactory; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.jdbc.pool.ClassLoaderUtil; + /** * Simple way of configuring generic resources by using reflection. * Example usage: @@ -57,7 +59,12 @@ public class GenericNamingResourcesFacto Enumeration<RefAddr> refs = ref.getAll(); String type = ref.getClassName(); - Object o = Class.forName(type).newInstance(); + Object o = + ClassLoaderUtil.loadClass( + type, + GenericNamingResourcesFactory.class.getClassLoader(), + Thread.currentThread().getContextClassLoader()) + .newInstance(); while (refs.hasMoreElements()) { RefAddr addr = refs.nextElement(); Added: tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ClassLoaderUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ClassLoaderUtil.java?rev=1616584&view=auto ============================================================================== --- tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ClassLoaderUtil.java (added) +++ tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ClassLoaderUtil.java Thu Aug 7 20:15:19 2014 @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.jdbc.pool; + + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +public class ClassLoaderUtil { + private static final Log log = LogFactory.getLog(ClassLoaderUtil.class); + + private static final boolean onlyAttemptFirstLoader = + Boolean.getBoolean(System.getProperty("org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader", "false")); + + public static Class loadClass(String className, ClassLoader... classLoaders) throws ClassNotFoundException { + ClassNotFoundException last = null; + StringBuffer errorMsg = null; + for (ClassLoader cl : classLoaders) { + try { + if (cl!=null) { + if (log.isDebugEnabled()) { + log.debug("Attempting to load class["+className+"] from "+cl); + } + return Class.forName(className, true, cl); + } else { + throw new ClassNotFoundException("Classloader is null"); + } + } catch (ClassNotFoundException x) { + last = x; + if (errorMsg==null) { + errorMsg = new StringBuffer(); + } else { + errorMsg.append(";"); + } + errorMsg.append("ClassLoader:"); + errorMsg.append(cl.toString()); + } + if (onlyAttemptFirstLoader) { + break; + } + } + throw new ClassNotFoundException("Unable to load class:"+className+" from "+errorMsg, last); + } + + + +} Propchange: tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/ClassLoaderUtil.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java?rev=1616584&r1=1616583&r2=1616584&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java (original) +++ tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java Thu Aug 7 20:15:19 2014 @@ -767,7 +767,11 @@ public class PoolProperties implements P try { @SuppressWarnings("unchecked") - Class<Validator> validatorClass = (Class<Validator>)Class.forName(className); + Class<Validator> validatorClass = (Class<Validator>)ClassLoaderUtil.loadClass( + className, + PoolProperties.class.getClassLoader(), + Thread.currentThread().getContextClassLoader() + ); validator = validatorClass.newInstance(); } catch (ClassNotFoundException e) { log.warn("The class "+className+" cannot be found.", e); @@ -957,12 +961,20 @@ public class PoolProperties implements P if (log.isDebugEnabled()) { log.debug("Loading interceptor class:"+PoolConfiguration.PKG_PREFIX+getClassName()); } - clazz = Class.forName(PoolConfiguration.PKG_PREFIX+getClassName(), true, this.getClass().getClassLoader()); + clazz = ClassLoaderUtil.loadClass( + PoolConfiguration.PKG_PREFIX+getClassName(), + this.getClass().getClassLoader(), + Thread.currentThread().getContextClassLoader() + ); } else { if (log.isDebugEnabled()) { log.debug("Loading interceptor class:"+getClassName()); } - clazz = Class.forName(getClassName(), true, this.getClass().getClassLoader()); + clazz = ClassLoaderUtil.loadClass( + getClassName(), + this.getClass().getClassLoader(), + Thread.currentThread().getContextClassLoader() + ); } } return (Class<? extends JdbcInterceptor>)clazz; Modified: tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java?rev=1616584&r1=1616583&r2=1616584&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java (original) +++ tomcat/trunk/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java Thu Aug 7 20:15:19 2014 @@ -247,8 +247,12 @@ public class PooledConnection { //rely on DriverManager log.warn("Not loading a JDBC driver as driverClassName property is null."); } else { - driver = (java.sql.Driver) Class.forName(poolProperties.getDriverClassName(), - true, PooledConnection.class.getClassLoader()).newInstance(); + driver = (java.sql.Driver) + ClassLoaderUtil.loadClass( + poolProperties.getDriverClassName(), + PooledConnection.class.getClassLoader(), + Thread.currentThread().getContextClassLoader() + ).newInstance(); } } } catch (java.lang.Exception cn) { --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org