Author: rmannibucau Date: Thu Apr 3 20:12:57 2014 New Revision: 1584372 URL: http://svn.apache.org/r1584372 Log: TOMEE-1164 forcing a parent classloader in tomcat webapp classloader
Added: tomee/tomee/trunk/tomee/tomee-jaxrs/src/test/java/org/ tomee/tomee/trunk/tomee/tomee-jaxrs/src/test/java/org/apache/ tomee/tomee/trunk/tomee/tomee-jaxrs/src/test/java/org/apache/tomee/ tomee/tomee/trunk/tomee/tomee-jaxrs/src/test/java/org/apache/tomee/jaxrs/ tomee/tomee/trunk/tomee/tomee-jaxrs/src/test/java/org/apache/tomee/jaxrs/ReloadingLoaderTest.java Modified: tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java tomee/tomee/trunk/tomee/tomee-jaxrs/pom.xml Modified: tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java?rev=1584372&r1=1584371&r2=1584372&view=diff ============================================================================== --- tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java (original) +++ tomee/tomee/trunk/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java Thu Apr 3 20:12:57 2014 @@ -16,47 +16,6 @@ */ package org.apache.tomee.catalina; -import static org.apache.tomee.catalina.BackportUtil.getNamingContextListener; -import static org.apache.tomee.catalina.Contexts.warPath; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -import javax.ejb.spi.HandleDelegate; -import javax.el.ELResolver; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NameNotFoundException; -import javax.naming.NamingException; -import javax.naming.Reference; -import javax.naming.StringRefAddr; -import javax.servlet.ServletContext; -import javax.servlet.SessionTrackingMode; -import javax.servlet.jsp.JspApplicationContext; -import javax.servlet.jsp.JspFactory; -import javax.sql.DataSource; -import javax.transaction.TransactionManager; -import javax.transaction.TransactionSynchronizationRegistry; - import org.apache.catalina.Cluster; import org.apache.catalina.Container; import org.apache.catalina.Engine; @@ -168,6 +127,46 @@ import org.apache.webbeans.config.WebBea import org.apache.webbeans.spi.adaptor.ELAdaptor; import org.omg.CORBA.ORB; +import javax.ejb.spi.HandleDelegate; +import javax.el.ELResolver; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.StringRefAddr; +import javax.servlet.ServletContext; +import javax.servlet.SessionTrackingMode; +import javax.servlet.jsp.JspApplicationContext; +import javax.servlet.jsp.JspFactory; +import javax.sql.DataSource; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import static org.apache.tomee.catalina.BackportUtil.getNamingContextListener; +import static org.apache.tomee.catalina.Contexts.warPath; + /** * Web application builder. * @@ -1084,6 +1083,8 @@ public class TomcatWebAppBuilder impleme private void startInternal(final StandardContext standardContext) { if (isIgnored(standardContext)) return; + forceWebAppLoaderToGetAParent(standardContext.getLoader().getClassLoader(), standardContext.getParentClassLoader()); + final CoreContainerSystem cs = getContainerSystem(); final Assembler a = getAssembler(); @@ -1372,6 +1373,18 @@ public class TomcatWebAppBuilder impleme } } + private void forceWebAppLoaderToGetAParent(final ClassLoader classLoader, final ClassLoader parent) { + if (!LazyStopWebappClassLoader.class.isInstance(classLoader)) { + return; + } + + // workaround since tomcat doesn't support reload anymore + if (Reflections.get(classLoader, "parent") == null) { // then the current loader was reloaded and is now broken if we need parent + // this algorithm is broken for ears but ears will not be reloaded this way normally + Reflections.set(classLoader, "parent", parent); + } + } + private static File rootPath(final File file) { if (file.isDirectory() && file.getName().equals("classes") && file.getParentFile() != null && file.getParentFile().getName().equals("WEB-INF")) { return file.getParentFile().getParentFile(); Modified: tomee/tomee/trunk/tomee/tomee-jaxrs/pom.xml URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/tomee/tomee-jaxrs/pom.xml?rev=1584372&r1=1584371&r2=1584372&view=diff ============================================================================== --- tomee/tomee/trunk/tomee/tomee-jaxrs/pom.xml (original) +++ tomee/tomee/trunk/tomee/tomee-jaxrs/pom.xml Thu Apr 3 20:12:57 2014 @@ -82,5 +82,12 @@ <version>${tomcat.version}</version> <scope>provided</scope> </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-coyote</artifactId> + <version>${tomcat.version}</version> + <scope>test</scope> + </dependency> </dependencies> </project> Added: tomee/tomee/trunk/tomee/tomee-jaxrs/src/test/java/org/apache/tomee/jaxrs/ReloadingLoaderTest.java URL: http://svn.apache.org/viewvc/tomee/tomee/trunk/tomee/tomee-jaxrs/src/test/java/org/apache/tomee/jaxrs/ReloadingLoaderTest.java?rev=1584372&view=auto ============================================================================== --- tomee/tomee/trunk/tomee/tomee-jaxrs/src/test/java/org/apache/tomee/jaxrs/ReloadingLoaderTest.java (added) +++ tomee/tomee/trunk/tomee/tomee-jaxrs/src/test/java/org/apache/tomee/jaxrs/ReloadingLoaderTest.java Thu Apr 3 20:12:57 2014 @@ -0,0 +1,143 @@ +/* + * 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.tomee.jaxrs; + +import org.apache.catalina.LifecycleException; +import org.apache.openejb.AppContext; +import org.apache.openejb.BeanContext; +import org.apache.openejb.assembler.classic.AppInfo; +import org.apache.openejb.assembler.classic.FacilitiesInfo; +import org.apache.openejb.assembler.classic.OpenEjbConfiguration; +import org.apache.openejb.assembler.classic.event.AssemblerAfterApplicationCreated; +import org.apache.openejb.assembler.classic.event.AssemblerBeforeApplicationDestroyed; +import org.apache.openejb.classloader.WebAppEnricher; +import org.apache.openejb.core.CoreContainerSystem; +import org.apache.openejb.core.ParentClassLoaderFinder; +import org.apache.openejb.core.WebContext; +import org.apache.openejb.core.ivm.naming.IvmContext; +import org.apache.openejb.core.ivm.naming.IvmJndiFactory; +import org.apache.openejb.loader.SystemInstance; +import org.apache.openejb.server.cxf.rs.CxfRSService; +import org.apache.openejb.spi.ContainerSystem; +import org.apache.openejb.util.reflection.Reflections; +import org.apache.tomee.catalina.LazyStopWebappClassLoader; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.net.URL; +import java.util.Collections; +import java.util.Properties; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + +public class ReloadingLoaderTest { + private AppInfo info; + private AppContext context; + private LazyStopWebappClassLoader loader; + + @BeforeClass + @AfterClass + public static void resetSystemInstance() { + SystemInstance.reset(); + } + + @Before + public void initContext() throws LifecycleException { + final OpenEjbConfiguration configuration = new OpenEjbConfiguration(); + configuration.facilities = new FacilitiesInfo(); + + final CoreContainerSystem containerSystem = new CoreContainerSystem(new IvmJndiFactory()); + + SystemInstance.get().setComponent(OpenEjbConfiguration.class, configuration); + SystemInstance.get().setComponent(ContainerSystem.class, containerSystem); + SystemInstance.get().setComponent(WebAppEnricher.class, new WebAppEnricher() { + @Override + public URL[] enrichment(final ClassLoader webappClassLaoder) { + return new URL[0]; + } + }); + + loader = new LazyStopWebappClassLoader(ParentClassLoaderFinder.Helper.get()); + loader.init(); + loader.start(); + + info = new AppInfo(); + info.appId = "test"; + context = new AppContext(info.appId, SystemInstance.get(), loader, new IvmContext(), new IvmContext(), true); + containerSystem.addAppContext(context); + + final WebContext webDeployment = new WebContext(context); + webDeployment.setId(context.getId()); + webDeployment.setClassLoader(loader); + containerSystem.addWebContext(webDeployment); + } + + @After + public void cleanUp() throws LifecycleException { + loader.stop(); + } + @Test + public void tomcatClassLoaderParentShouldntBeNulAfterAStopStartOtherwiseReloadIsBroken() throws Exception { + final CxfRSService server = new CxfRSService(); + try { + server.init(new Properties()); + server.start(); + + server.afterApplicationCreated(new AssemblerAfterApplicationCreated(info, context, Collections.<BeanContext>emptyList())); + + { + final ClassLoader beforeLoader = SystemInstance.get().getComponent(ContainerSystem.class).getWebContext("test").getClassLoader(); + assertSame(loader, beforeLoader); + assertNotNull(beforeLoader); + assertNotNull(Reflections.get(beforeLoader, "parent")); // getParent != parent from WebAppClassLoader + } + + loader.internalStop(); + + server.undeploy(new AssemblerBeforeApplicationDestroyed(info, context)); + + { + final ClassLoader afterLoader = SystemInstance.get().getComponent(ContainerSystem.class).getWebContext("test").getClassLoader(); + assertSame(loader, afterLoader); + assertNotNull(afterLoader); + assertNull(Reflections.get(afterLoader, "parent")); + } + + loader.start(); + // TomcatWebAppBuilder ill catch start event from StandardContext and force a classloader + Reflections.set(loader, "parent", ParentClassLoaderFinder.Helper.get()); + + server.afterApplicationCreated(new AssemblerAfterApplicationCreated(info, context, Collections.<BeanContext>emptyList())); + + { + final ClassLoader afterLoader = SystemInstance.get().getComponent(ContainerSystem.class).getWebContext("test").getClassLoader(); + assertSame(loader, afterLoader); + assertNotNull(afterLoader); + assertNotNull(Reflections.get(afterLoader, "parent")); + } + + server.undeploy(new AssemblerBeforeApplicationDestroyed(info, context)); + } finally { + server.stop(); + } + } +}