You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2015/01/29 11:53:23 UTC
tomee git commit: TOMEE-1503 try to find dynamically if we should
call parent first or not in a webapp of an ear
Repository: tomee
Updated Branches:
refs/heads/develop 76e3e9e23 -> 9741e9518
TOMEE-1503 try to find dynamically if we should call parent first or not in a webapp of an ear
Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/9741e951
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/9741e951
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/9741e951
Branch: refs/heads/develop
Commit: 9741e9518c70554d9bee0e0a1f07a5756c7e75fc
Parents: 76e3e9e
Author: Romain Manni-Bucau <rm...@apache.org>
Authored: Thu Jan 29 11:52:53 2015 +0100
Committer: Romain Manni-Bucau <rm...@apache.org>
Committed: Thu Jan 29 11:52:53 2015 +0100
----------------------------------------------------------------------
.../arquillian-tomee-jaxws-tests/pom.xml | 6 ++
.../tests/jaxws/EarClassLoaderTest.java | 64 ++++++++++++++++
.../jaxws/LoadJodaFromTheWebAppResource.java | 37 +++++++++
.../src/test/resources/arquillian.xml | 1 +
.../tomee/catalina/TomEEWebappClassLoader.java | 79 +++++++++++++++++---
5 files changed, 178 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tomee/blob/9741e951/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 7d9d0fc..ee883c7 100644
--- a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/pom.xml
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/pom.xml
@@ -36,6 +36,12 @@
<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>
http://git-wip-us.apache.org/repos/asf/tomee/blob/9741e951/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
new file mode 100644
index 0000000..607d2c2
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/EarClassLoaderTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.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.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.IOException;
+import java.net.URL;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Arquillian.class)
+public class EarClassLoaderTest {
+ @Deployment(testable = false)
+ public static Archive<?> ear() {
+ return ShrinkWrap.create(EnterpriseArchive.class, "broken.ear")
+ .addAsModule(
+ ShrinkWrap.create(WebArchive.class, "broken-web.war")
+ .addClasses(LoadJodaFromTheWebAppResource.class)
+ .addAsLibraries(
+ Maven.resolver()
+ .offline()
+ .resolve("joda-time:joda-time:2.5")
+ .withClassPathResolution(true)
+ .using(new AcceptScopesStrategy(ScopeType.COMPILE, ScopeType.RUNTIME))
+ .asFile()
+ )
+ );
+ }
+
+ @ArquillianResource
+ private URL url;
+
+ @Test
+ public void checkIfWasCorretlyLoaded() throws IOException { // when writing this test we ship joda-time 2.2
+ assertEquals("2.5", IO.slurp(new URL(url.toExternalForm() + (url.getPath().isEmpty() ? "/broken-web/" : "") + "joda")));
+ }
+}
http://git-wip-us.apache.org/repos/asf/tomee/blob/9741e951/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/LoadJodaFromTheWebAppResource.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/LoadJodaFromTheWebAppResource.java b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/LoadJodaFromTheWebAppResource.java
new file mode 100644
index 0000000..bfac42c
--- /dev/null
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxws/LoadJodaFromTheWebAppResource.java
@@ -0,0 +1,37 @@
+/*
+ * 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.joda.time.LocalDateTime;
+
+import javax.ejb.Singleton;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+@Path("joda")
+@Singleton
+public class LoadJodaFromTheWebAppResource {
+ @GET
+ public String worked() {
+ LocalDateTime.now().toString(); // just trigger loading if not already done during scanning
+ return LocalDateTime.class.getPackage().getImplementationVersion();
+ }
+
+ public LocalDateTime triggerLoadingDuringScanning() {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/tomee/blob/9741e951/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/resources/arquillian.xml
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/resources/arquillian.xml b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/resources/arquillian.xml
index 710a9e5..d67d8f0 100644
--- a/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/resources/arquillian.xml
+++ b/arquillian/arquillian-tomee-tests/arquillian-tomee-jaxws-tests/src/test/resources/arquillian.xml
@@ -43,6 +43,7 @@
My\ DataSource.JdbcUrl = jdbc:hsqldb:mem:hsqldb
My\ Unmanaged\ DataSource.JdbcUrl = jdbc:hsqldb:mem:hsqldb
openejb.classloader.forced-load=org.apache.openejb.arquillian.tests
+ tomee.webapp-first=true
</property>
</configuration>
</container>
http://git-wip-us.apache.org/repos/asf/tomee/blob/9741e951/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 ef91219..0461d0e 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
@@ -31,6 +31,7 @@ import org.apache.openejb.classloader.CompositeClassLoaderConfigurer;
import org.apache.openejb.classloader.WebAppEnricher;
import org.apache.openejb.config.NewLoaderLogic;
import org.apache.openejb.config.QuickJarsTxtParser;
+import org.apache.openejb.core.ParentClassLoaderFinder;
import org.apache.openejb.loader.Files;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.util.LogCategory;
@@ -48,6 +49,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -75,22 +77,34 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
}
}
+ public static final String CLASS_EXTENSION = ".class";
+
private boolean restarting;
private boolean forceStopPhase = Boolean.parseBoolean(SystemInstance.get().getProperty("tomee.webappclassloader.force-stop-phase", "true"));
private ClassLoaderConfigurer configurer;
+ private final boolean isEar;
+ private final ClassLoader containerClassLoader;
+ private volatile boolean originalDelegate;
private final int hashCode;
private Collection<File> additionalRepos;
private volatile boolean stopped = false;
+ private final Map<String, Boolean> filterTempCache = new HashMap<>(); // used only in sync block + isEar
public TomEEWebappClassLoader() {
hashCode = construct();
setJavaseClassLoader(getSystemClassLoader());
+ containerClassLoader = ParentClassLoaderFinder.Helper.get();
+ isEar = getParent() != containerClassLoader;
+ originalDelegate = getDelegate();
}
public TomEEWebappClassLoader(final ClassLoader parent) {
super(parent);
hashCode = construct();
setJavaseClassLoader(getSystemClassLoader());
+ containerClassLoader = ParentClassLoaderFinder.Helper.get();
+ isEar = getParent() != containerClassLoader;
+ originalDelegate = getDelegate();
}
private int construct() {
@@ -100,6 +114,12 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
}
@Override
+ public void setDelegate(final boolean delegate) {
+ this.delegate = delegate;
+ this.originalDelegate = delegate;
+ }
+
+ @Override
public void stop() throws LifecycleException {
// in our destroyapplication method we need a valid classloader to TomcatWebAppBuilder.afterStop()
if (forceStopPhase || restarting) {
@@ -123,13 +143,12 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
synchronized (this) {
final ClassLoader old = getJavaseClassLoader();
setJavaseClassLoader(NoClassClassLoader.INSTANCE);
- final boolean delegate = getDelegate();
- setDelegate(false);
+ delegate = false;
try {
return super.loadClass(name);
} finally {
setJavaseClassLoader(old);
- setDelegate(delegate);
+ setDelegate(originalDelegate);
}
}
}
@@ -137,28 +156,59 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
// avoid to redefine classes from server in this classloader is it not already loaded
if (URLClassLoaderFirst.shouldDelegateToTheContainer(this, name)) { // dynamic validation handling overriding
try {
- return OpenEJB.class.getClassLoader().loadClass(name);
+ return OpenEJB.class.getClassLoader().loadClass(name); // we could use containerClassLoader but this is server loader so cut it even more
} catch (final ClassNotFoundException e) {
return super.loadClass(name);
} catch (final NoClassDefFoundError ncdfe) {
return super.loadClass(name);
}
} else if (name.startsWith("javax.faces.") || name.startsWith("org.apache.webbeans.jsf.")) {
- final boolean delegate = getDelegate();
synchronized (this) {
- setDelegate(false);
+ delegate = false;
try {
return super.loadClass(name);
} finally {
- setDelegate(delegate);
+ setDelegate(originalDelegate);
}
}
}
- synchronized (this) { // TODO: rework it to avoid it but not a big issue, see first if of this method
+ 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);
+ filterTempCache.put(name, filter); // will be called again by super.loadClass() so cache it
+ if (!filter && wouldBeLoadedFromContainer(name)) {
+ setDelegate(false);
+ try {
+ return super.loadClass(name);
+ } finally {
+ filterTempCache.remove(name); // no more needed since class is loaded, avoid to waste mem
+ setDelegate(originalDelegate);
+ }
+ }
+ }
return super.loadClass(name);
}
}
+ private boolean wouldBeLoadedFromContainer(final String name) {
+ final String resource = name.replace('.', '/') + CLASS_EXTENSION;
+
+ final URL containerUrl = containerClassLoader.getResource(resource);
+ if (containerUrl == null) {
+ return false;
+ }
+
+ final URL parentUrl = getParent().getResource(resource);
+ if (parentUrl == null) {
+ return false;
+ }
+ try {
+ return URLs.toFile(parentUrl).getCanonicalPath().equalsIgnoreCase(URLs.toFile(containerUrl).getCanonicalPath());
+ } catch (final IOException e) {
+ return false;
+ }
+ }
+
@Override
public void setResources(final WebResourceRoot resources) {
this.resources = resources;
@@ -188,7 +238,18 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
@Override
protected boolean filter(final String name) {
- return !"org.apache.tomee.mojarra.TomEEInjectionProvider".equals(name) && URLClassLoaderFirst.shouldSkip(name);
+ if ("org.apache.tomee.mojarra.TomEEInjectionProvider".equals(name)) {
+ return false;
+ }
+ if (isEar) { // check we are called from super and we already cached the result in loadClass
+ synchronized (this) {
+ final Boolean cache = filterTempCache.get(name);
+ if (cache != null) {
+ return cache;
+ }
+ }
+ }
+ return URLClassLoaderFirst.shouldSkip(name);
}
public void internalStop() throws LifecycleException {