Repository: tomee Updated Branches: refs/heads/master fc28436fb -> c0e6d70f1
TOMEE-1851 ear webapp first strategy Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/475b1e0f Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/475b1e0f Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/475b1e0f Branch: refs/heads/master Commit: 475b1e0f6e51d2b9e8bc24340f3612c8a5ff9625 Parents: fc28436 Author: Romain manni-Bucau <rmannibu...@gmail.com> Authored: Fri Jun 24 09:38:16 2016 +0200 Committer: Romain manni-Bucau <rmannibu...@gmail.com> Committed: Fri Jun 24 09:38:16 2016 +0200 ---------------------------------------------------------------------- .../arquillian-tomee-jaxws-tests/pom.xml | 34 +++++++-- .../tests/jaxws/EarClassLoaderTest.java | 11 +-- .../jaxws/EarWebAppFirstClassLoaderTest.java | 76 ++++++++++++++++++++ .../tomee/catalina/TomEEWebappClassLoader.java | 13 ++-- .../tomee/catalina/TomEEWebappLoader.java | 6 ++ .../catalina/WebAppFirstEarClassLoader.java | 62 ++++++++++++++++ 6 files changed, 188 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/475b1e0f/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/pom.xml ---------------------------------------------------------------------- diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/pom.xml b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/pom.xml index 178ce89..71a9cce 100644 --- a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/pom.xml +++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/pom.xml @@ -36,15 +36,37 @@ <version>${project.version}</version> <scope>test</scope> </dependency> - <dependency> <!-- org.apache.openejb.arquillian.tests.jaxws.EarClassLoaderTest --> - <groupId>joda-time</groupId> - <artifactId>joda-time</artifactId> - <version>2.5</version> - <scope>test</scope> - </dependency> </dependencies> <properties> <profile-under-test>plus</profile-under-test> </properties> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <version>2.10</version> + <executions> + <execution> + <id>get-joda</id> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <artifactItem> + <groupId>joda-time</groupId> + <artifactId>joda-time</artifactId> + <version>2.5</version> + <outputDirectory>${project.build.directory}/placeholder-dep</outputDirectory> + </artifactItem> + </artifactItems> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> </project> http://git-wip-us.apache.org/repos/asf/tomee/blob/475b1e0f/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarClassLoaderTest.java ---------------------------------------------------------------------- diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarClassLoaderTest.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarClassLoaderTest.java index c875bff..4b75d78 100644 --- a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarClassLoaderTest.java +++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarClassLoaderTest.java @@ -33,10 +33,10 @@ import org.junit.runner.RunWith; import java.io.IOException; import java.net.URL; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; -@RunWith(Arquillian.class) +@RunWith(Arquillian.class) // TODO: move it and EarWebAppFirstClassLoaderTest to webprofile? public class EarClassLoaderTest { @Deployment(testable = false) public static Archive<?> ear() { @@ -59,7 +59,10 @@ public class EarClassLoaderTest { private URL url; @Test - public void checkIfWasCorretlyLoaded() throws IOException { // when writing this test we ship joda-time 2.2 - assertTrue(IO.slurp(new URL(url.toExternalForm() + (url.getPath().isEmpty() ? "/broken-web/" : "") + "joda")).endsWith("joda-time-2.5.jar")); + public void checkIfWasCorretlyLoaded() throws IOException { + // embedded case uses the classpath for a lot of reasons + assumeFalse(System.getProperty("openejb.arquillian.adapter", "embedded").contains("embedded")); + final String slurp = IO.slurp(new URL(url.toExternalForm() + (url.getPath().isEmpty() ? "/broken-web/" : "") + "joda")); + assertTrue(slurp.endsWith("broken-web/WEB-INF/lib/joda-time-2.5.jar")); } } http://git-wip-us.apache.org/repos/asf/tomee/blob/475b1e0f/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarWebAppFirstClassLoaderTest.java ---------------------------------------------------------------------- diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarWebAppFirstClassLoaderTest.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarWebAppFirstClassLoaderTest.java new file mode 100644 index 0000000..3ebfb91 --- /dev/null +++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarWebAppFirstClassLoaderTest.java @@ -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.openejb.arquillian.tests.jaxws; + +import org.apache.openejb.arquillian.common.IO; +import org.apache.tomee.catalina.TomEEWebappLoader; +import org.apache.tomee.catalina.WebAppFirstEarClassLoader; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.EnterpriseArchive; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.jboss.shrinkwrap.resolver.api.maven.Maven; +import org.jboss.shrinkwrap.resolver.api.maven.ScopeType; +import org.jboss.shrinkwrap.resolver.api.maven.strategy.AcceptScopesStrategy; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.IOException; +import java.net.URL; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; + +@RunWith(Arquillian.class) // TODO: move it and EarClassLoaderTest to webprofile? +public class EarWebAppFirstClassLoaderTest { + @Deployment(testable = false) + public static Archive<?> ear() { + final File[] joda = Maven.resolver() + .offline() + .resolve("joda-time:joda-time:2.5") + .withClassPathResolution(true) + .using(new AcceptScopesStrategy(ScopeType.COMPILE, ScopeType.RUNTIME)) + .asFile(); + return ShrinkWrap.create(EnterpriseArchive.class, "broken.ear") + .addAsLibraries(joda) + .addAsModule(ShrinkWrap.create(WebArchive.class, "broken-web.war") + .addClasses(LoadJodaFromTheWebAppResource.class) + .addAsManifestResource(new StringAsset( + "<Context>" + + "<Loader className=\"" + TomEEWebappLoader.class.getName() + + "\" loaderClass=\"" + WebAppFirstEarClassLoader.class.getName() + "\" />" + + "</Context>"), "context.xml") + .addAsLibraries(joda)); + } + + @ArquillianResource + private URL url; + + @Test + public void checkIfWasCorretlyLoaded() throws IOException { + assumeFalse(System.getProperty("openejb.arquillian.adapter", "embedded").contains("embedded")); + final String slurp = IO.slurp(new URL(url.toExternalForm() + (url.getPath().isEmpty() ? "/broken-web/" : "") + "joda")); + assertTrue(slurp.endsWith("broken-web/WEB-INF/lib/joda-time-2.5.jar")); + assertFalse(slurp.endsWith("broken/lib/joda-time-2.5.jar")); // useless cause of the previous but to make it obvious + } +} http://git-wip-us.apache.org/repos/asf/tomee/blob/475b1e0f/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappClassLoader.java ---------------------------------------------------------------------- diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappClassLoader.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappClassLoader.java index aee4bf7..fbdd7bd 100644 --- a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappClassLoader.java +++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappClassLoader.java @@ -69,6 +69,7 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader { private static final ThreadLocal<Context> CONTEXT = new ThreadLocal<>(); public static final String TOMEE_WEBAPP_FIRST = "tomee.webapp-first"; + public static final String TOMEE_EAR_DEFAULT = "tomee.ear.webapp-first"; static { boolean result = ClassLoader.registerAsParallelCapable(); @@ -95,7 +96,7 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader { hashCode = construct(); setJavaseClassLoader(getSystemClassLoader()); containerClassLoader = ParentClassLoaderFinder.Helper.get(); - isEar = getParent() != null && !getParent().equals(containerClassLoader); + isEar = getParent() != null && !getParent().equals(containerClassLoader) && defaultEarBehavior(); originalDelegate = getDelegate(); } @@ -104,7 +105,7 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader { hashCode = construct(); setJavaseClassLoader(getSystemClassLoader()); containerClassLoader = ParentClassLoaderFinder.Helper.get(); - isEar = getParent() != null && !getParent().equals(containerClassLoader); + isEar = getParent() != null && !getParent().equals(containerClassLoader) && defaultEarBehavior(); originalDelegate = getDelegate(); } @@ -181,7 +182,7 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader { } synchronized (this) { // TODO: rework it to avoid it and get aligned on Java 7 classloaders (but not a big issue) if (isEar) { - final boolean filter = filter(name); + final boolean filter = filter(name, true); filterTempCache.put(name, filter); // will be called again by super.loadClass() so cache it if (!filter) { if (URLClassLoaderFirst.class.isInstance(getParent())) { // true @@ -403,7 +404,11 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader { return true; } - public static boolean isDelegate() { + protected boolean defaultEarBehavior() { + return !SystemInstance.get().getOptions().get(TOMEE_EAR_DEFAULT, false /*bck compat*/); + } + + private static boolean isDelegate() { return !SystemInstance.get().getOptions().get(TOMEE_WEBAPP_FIRST, true); } http://git-wip-us.apache.org/repos/asf/tomee/blob/475b1e0f/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappLoader.java ---------------------------------------------------------------------- diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappLoader.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappLoader.java index 2308db0..4ca9539 100644 --- a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappLoader.java +++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEEWebappLoader.java @@ -44,6 +44,8 @@ public class TomEEWebappLoader extends WebappLoader { public static final boolean SKIP_BACKGROUND_PROCESS = "true".equals(SystemInstance.get().getProperty("tomee.classloader.skip-background-process", "false")); private volatile ClassLoader loader; + private String forceSkip; + private String[] forceSkipRuntime; @Override public void backgroundProcess() { @@ -112,6 +114,10 @@ public class TomEEWebappLoader extends WebappLoader { } finally { TomEEWebappClassLoader.cleanContext(); } + + if (forceSkip != null && WebAppFirstEarClassLoader.class.isInstance(getClassLoader())) { + WebAppFirstEarClassLoader.class.cast(getClassLoader()).setForceSkip(forceSkip.split(" *, *")); + } } @Override http://git-wip-us.apache.org/repos/asf/tomee/blob/475b1e0f/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/WebAppFirstEarClassLoader.java ---------------------------------------------------------------------- diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/WebAppFirstEarClassLoader.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/WebAppFirstEarClassLoader.java new file mode 100644 index 0000000..327f58d --- /dev/null +++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/WebAppFirstEarClassLoader.java @@ -0,0 +1,62 @@ +/* + * 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.catalina; + +import org.apache.catalina.LifecycleException; + +// a TomEEWebappClassLoader enforcing webapp first classloading in ears +public class WebAppFirstEarClassLoader extends TomEEWebappClassLoader { + static { + ClassLoader.registerAsParallelCapable(); + } + + private String[] forceSkip; + + public WebAppFirstEarClassLoader() { + super(); + } + + public WebAppFirstEarClassLoader(final ClassLoader parent) { + super(parent); + } + + @Override + public void start() throws LifecycleException { + super.start(); + } + + @Override + public Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException { + if (forceSkip != null) { + for (final String p : forceSkip) { + if (name.startsWith(p)) { + return getParent().loadClass(name); + } + } + } + return super.loadClass(name, resolve); + } + + @Override + protected boolean defaultEarBehavior() { + return false; + } + + void setForceSkip(final String[] forceSkip) { + this.forceSkip = forceSkip; + } +}