Author: markt
Date: Tue Sep  8 13:46:34 2015
New Revision: 1701805

URL: http://svn.apache.org/r1701805
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=57681
Add a web application class loader implementation that supports the parallel 
loading of web application classes.
Use of this feature requires a Java 7 or later JRE.
Based on a patch by Huxing Zhang.

Added:
    
tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/ParallelWebappClassLoader.java
   (with props)
    
tomcat/tc7.0.x/trunk/test/org/apache/catalina/loader/TestParallelWebappClassLoader.java
   (with props)
Modified:
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/LocalStrings.properties
    tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/mbeans-descriptors.xml
    tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
    tomcat/tc7.0.x/trunk/webapps/docs/config/loader.xml

Modified: 
tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/LocalStrings.properties?rev=1701805&r1=1701804&r2=1701805&view=diff
==============================================================================
--- 
tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/LocalStrings.properties 
(original)
+++ 
tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/LocalStrings.properties 
Tue Sep  8 13:46:34 2015
@@ -66,6 +66,7 @@ webappClassLoader.addTransformer.duplica
 webappClassLoader.addTransformer=Added class file transformer [{0}] to web 
application [{1}].
 webappClassLoader.removeTransformer=Removed class file transformer [{0}] from 
web application [{1}].
 webappClassLoader.transformError=Instrumentation error: could not transform 
class [{0}] because its class file format is not legal.
+webappClassLoaderParallel.registrationFailed=Registration of 
org.apache.catalina.loader.ParallelWebappClassLoader as capable of loading 
classes in parallel failed
 webappLoader.addRepository=Adding repository {0}
 webappLoader.deploy=Deploying class repositories to work directory {0}
 webappLoader.jarDeploy=Deploy JAR {0} to {1}

Added: 
tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/ParallelWebappClassLoader.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/ParallelWebappClassLoader.java?rev=1701805&view=auto
==============================================================================
--- 
tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/ParallelWebappClassLoader.java
 (added)
+++ 
tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/ParallelWebappClassLoader.java
 Tue Sep  8 13:46:34 2015
@@ -0,0 +1,100 @@
+/*
+ * 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.catalina.loader;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.apache.catalina.LifecycleException;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.compat.JreCompat;
+
+/**
+ * Parallel class loading implementation of WebappClassLoaderBase. Parallel
+ * class loading is only available when using a Java 7+ JRE.
+ */
+public class ParallelWebappClassLoader extends WebappClassLoaderBase {
+
+    private static final Log log = 
LogFactory.getLog(ParallelWebappClassLoader.class);
+
+    static {
+        try {
+            if (JreCompat.isJre7Available()) {
+                // parallel class loading capable
+                final Method registerParallel =
+                        
ClassLoader.class.getDeclaredMethod("registerAsParallelCapable");
+                AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                    @Override
+                    public Object run() {
+                        registerParallel.setAccessible(true);
+                        return null;
+                    }
+                });
+                Boolean result = (Boolean)registerParallel.invoke(null);
+                if (!result.booleanValue()) {
+                    
log.warn(sm.getString("webappClassLoaderParallel.registrationFailed"));
+                }
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+    }
+
+    
+    public ParallelWebappClassLoader() {
+        super();
+    }
+
+    
+    public ParallelWebappClassLoader(ClassLoader parent) {
+        super(parent);
+    }
+
+
+    /**
+     * 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 java.lang.instrument.ClassFileTransformer}'s
+     * {@link java.lang.instrument.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.
+     */
+    @Override
+    public ParallelWebappClassLoader copyWithoutTransformers() {
+
+        ParallelWebappClassLoader result = new 
ParallelWebappClassLoader(getParent());
+
+        super.copyStateWithoutTransformers(result);
+
+        try {
+            result.start();
+        } catch (LifecycleException e) {
+            throw new IllegalStateException(e);
+        }
+
+        return result;
+    }
+}
\ No newline at end of file

Propchange: 
tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/ParallelWebappClassLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/mbeans-descriptors.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/mbeans-descriptors.xml?rev=1701805&r1=1701804&r2=1701805&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/mbeans-descriptors.xml 
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/loader/mbeans-descriptors.xml 
Tue Sep  8 13:46:34 2015
@@ -171,4 +171,48 @@
 
   </mbean>
 
+  <mbean         name="ParallelWebappClassLoader"
+          description="Classloader implementation which is specialized for 
handling web applications"
+               domain="Catalina"
+                group="Loader"
+                 type="org.apache.catalina.loader.ParallelWebappClassLoader">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="contextName"
+          description="Name of the webapp context"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="delegate"
+          description="The 'follow standard delegation model' flag that will 
be used to configure our ClassLoader"
+                 type="boolean"/>
+
+    <attribute   name="antiJARLocking"
+          description="The antiJARLocking flag for this Loader"
+                 type="boolean"/>
+
+    <attribute   name="searchExternalFirst"
+          description="The searchExternalFirst flag for this Loader"
+                 type="boolean"/>
+
+    <attribute   name="stateName"
+          description="The name of the LifecycleState that this component is 
currently in"
+                 type="java.lang.String"
+                 writeable="false"/>
+
+    <attribute   name="URLs"
+          description="The URLs of this loader"
+                 type="[Ljava.net.URL;"/>
+
+    <attribute   name="jarPath"
+          description="The jarPath of this loader"
+             writeable="false" 
+                 type="java.lang.String"/>
+
+  </mbean>
+
 </mbeans-descriptors>

Added: 
tomcat/tc7.0.x/trunk/test/org/apache/catalina/loader/TestParallelWebappClassLoader.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/loader/TestParallelWebappClassLoader.java?rev=1701805&view=auto
==============================================================================
--- 
tomcat/tc7.0.x/trunk/test/org/apache/catalina/loader/TestParallelWebappClassLoader.java
 (added)
+++ 
tomcat/tc7.0.x/trunk/test/org/apache/catalina/loader/TestParallelWebappClassLoader.java
 Tue Sep  8 13:46:34 2015
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.catalina.loader;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.tomcat.util.compat.JreCompat;
+
+public class TestParallelWebappClassLoader extends TomcatBaseTest {
+
+    private static final String PARALLEL_CLASSLOADER =
+            "org.apache.catalina.loader.ParallelWebappClassLoader";
+    private static final String DUMMY_SERVLET =
+            "org.apache.catalina.loader.DummyServlet";
+
+    @Test
+    public void testParallelCapableOnJre7() {
+        if (!JreCompat.isJre7Available()) {
+            // ignore on Jre6 or lower
+            return;
+        }
+        try {
+            Tomcat tomcat = getTomcatInstance();
+            Context ctx = tomcat.addContext("", null);
+
+            WebappLoader webappLoader = new WebappLoader();
+            webappLoader.setLoaderClass(PARALLEL_CLASSLOADER);
+            ctx.setLoader(webappLoader);
+
+            tomcat.start();
+
+            ClassLoader classloader = ctx.getLoader().getClassLoader();
+
+            Assert.assertTrue(classloader instanceof 
ParallelWebappClassLoader);
+
+            // parallel class loading capable
+            Method getClassLoadingLock =
+                    getDeclaredMethod(classloader.getClass(), 
"getClassLoadingLock", String.class);
+            // make sure we have getClassLoadingLock on JRE7.
+            Assert.assertNotNull(getClassLoadingLock);
+            // give us permission to access protected method
+            getClassLoadingLock.setAccessible(true);
+
+            Object lock = getClassLoadingLock.invoke(classloader, 
DUMMY_SERVLET);
+            // make sure it is not a ParallelWebappClassLoader object lock
+            Assert.assertNotEquals(lock, classloader);
+        } catch (Exception e) {
+            e.printStackTrace();
+            Assert.fail("testParallelCapableOnJre7 fails.");
+        }
+    }
+
+    @Test
+    public void testParallelIncapableOnJre6() {
+        if (JreCompat.isJre7Available()) {
+            // ignore on Jre7 or above
+            return;
+        }
+        try {
+            Tomcat tomcat = getTomcatInstance();
+            // Must have a real docBase - just use temp
+            Context ctx = tomcat.addContext("",
+                    System.getProperty("java.io.tmpdir"));
+
+            WebappLoader webappLoader = new WebappLoader();
+            webappLoader.setLoaderClass(PARALLEL_CLASSLOADER);
+            ctx.setLoader(webappLoader);
+
+            tomcat.start();
+
+            ClassLoader classloader = ctx.getLoader().getClassLoader();
+
+            Assert.assertTrue(classloader instanceof 
ParallelWebappClassLoader);
+
+            // parallel class loading capable
+            Method getClassLoadingLock =
+                    getDeclaredMethod(classloader.getClass(), 
"getClassLoadingLock", String.class);
+            // make sure we don't have getClassLoadingLock on JRE6.
+            Assert.assertNull(getClassLoadingLock);
+        } catch (Exception e) {
+            e.printStackTrace();
+            Assert.fail("testParallelIncapableOnJre6 fails.");
+        }
+    }
+
+    private Method getDeclaredMethod(Class<?> clazz, String name, Class<?>... 
parameterTypes) {
+        if (clazz == null) return null;
+        for (Method method: clazz.getDeclaredMethods()) {
+            if (method.getName().equals(name)) {
+                return method;
+            }
+        }
+        // find from super class
+        return getDeclaredMethod(clazz.getSuperclass(), name, parameterTypes);
+    }
+
+    @SuppressWarnings("unused")
+    private static final class DummyServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            // do nothing
+        }
+    }
+}
\ No newline at end of file

Propchange: 
tomcat/tc7.0.x/trunk/test/org/apache/catalina/loader/TestParallelWebappClassLoader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1701805&r1=1701804&r2=1701805&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Tue Sep  8 13:46:34 2015
@@ -60,6 +60,12 @@
 <section name="Tomcat 7.0.65 (violetagg)">
   <subsection name="Catalina">
     <changelog>
+      <add>
+        <bug>57681</bug>: Add a web application class loader implementation 
that
+        supports the parallel loading of web application classes. Use of this
+        feature requires a Java 7 or later JRE. Based on a patch by Huxing
+        Zhang. (markt)
+      </add>
       <fix>
         <bug>58187</bug>: Correct a regression in the fix for <bug>57765</bug>
         that meant that deployment of web applications deployed via the Manager

Modified: tomcat/tc7.0.x/trunk/webapps/docs/config/loader.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/config/loader.xml?rev=1701805&r1=1701804&r2=1701805&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/config/loader.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/config/loader.xml Tue Sep  8 13:46:34 2015
@@ -125,7 +125,11 @@
         implementation class to use.  If not specified, the default value is
         <code>org.apache.catalina.loader.WebappClassLoader</code>. Custom
         <strong>loaderClass</strong> implementations must extend
-        <code>org.apache.catalina.loader.WebappClassLoaderBase</code>.</p>
+        <code>org.apache.catalina.loader.WebappClassLoaderBase</code>.The
+        default <strong>loaderClass</strong> is not parallel capable. A 
parallel
+        capable <strong>loaderClass</strong> is available when running on a 
Java
+        7 or higher JRE and can be used by specifying
+        <code>org.apache.catalina.loader.ParallelWebappClassLoader</code>.</p>
       </attribute>
 
       <attribute name="searchExternalFirst" required="false">



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to