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/04/20 13:07:59 UTC

tomee git commit: binding WebResourceRoot (stop part) lifecycle to the TomEEWebAppClassLoader to ensure we dont eagerly close resources. TODO: see if we can merge openejb and tomcat lifecycle in a better manner

Repository: tomee
Updated Branches:
  refs/heads/master 757e4e83f -> 1665a38f5


binding WebResourceRoot (stop part) lifecycle to the TomEEWebAppClassLoader to ensure we dont eagerly close resources. TODO: see if we can merge openejb and tomcat lifecycle in a better manner


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/1665a38f
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/1665a38f
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/1665a38f

Branch: refs/heads/master
Commit: 1665a38f5c850b656be14ae94285ee369dea90a7
Parents: 757e4e8
Author: Romain Manni-Bucau <rm...@apache.org>
Authored: Mon Apr 20 13:07:44 2015 +0200
Committer: Romain Manni-Bucau <rm...@apache.org>
Committed: Mon Apr 20 13:07:44 2015 +0200

----------------------------------------------------------------------
 .../tomee/catalina/LazyStopStandardRoot.java    | 327 +++++++++++++++++++
 .../tomee/catalina/TomEEWebappClassLoader.java  |  36 +-
 .../tomee/catalina/TomcatWebAppBuilder.java     |  48 ++-
 3 files changed, 386 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/1665a38f/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/LazyStopStandardRoot.java
----------------------------------------------------------------------
diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/LazyStopStandardRoot.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/LazyStopStandardRoot.java
new file mode 100644
index 0000000..80a49af
--- /dev/null
+++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/LazyStopStandardRoot.java
@@ -0,0 +1,327 @@
+/*
+ * 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.Context;
+import org.apache.catalina.JmxEnabled;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.LifecycleState;
+import org.apache.catalina.TrackedWebResource;
+import org.apache.catalina.WebResource;
+import org.apache.catalina.WebResourceRoot;
+import org.apache.catalina.WebResourceSet;
+import org.apache.catalina.util.LifecycleMBeanBase;
+import org.apache.catalina.webresources.StandardRoot;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.List;
+import java.util.Set;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+public class LazyStopStandardRoot implements WebResourceRoot, JmxEnabled {
+    private final WebResourceRoot delegate;
+    private final boolean isJmxEnabled;
+    private final boolean isLifecycleMBeanBase;
+
+    public LazyStopStandardRoot(final WebResourceRoot delegate) {
+        this.delegate = delegate;
+        this.isJmxEnabled = JmxEnabled.class.isInstance(delegate);
+        this.isLifecycleMBeanBase = LifecycleMBeanBase.class.isInstance(delegate);
+    }
+
+    @Override
+    public String[] list(final String path) {
+        return delegate.list(path);
+    }
+
+    @Override
+    public Set<String> listWebAppPaths(final String path) {
+        return delegate.listWebAppPaths(path);
+    }
+
+    @Override
+    public boolean mkdir(final String path) {
+        return delegate.mkdir(path);
+    }
+
+    @Override
+    public boolean write(final String path, final InputStream is, final boolean overwrite) {
+        return delegate.write(path, is, overwrite);
+    }
+
+    @Override
+    public WebResource getResource(final String path) {
+        return delegate.getResource(path);
+    }
+
+    @Override
+    public WebResource getClassLoaderResource(final String path) {
+        return delegate.getClassLoaderResource(path);
+    }
+
+    @Override
+    public WebResource[] getClassLoaderResources(final String path) {
+        return delegate.getClassLoaderResources(path);
+    }
+
+    @Override
+    public WebResource[] getResources(final String path) {
+        return delegate.getResources(path);
+    }
+
+    @Override
+    public WebResource[] listResources(final String path) {
+        return delegate.listResources(path);
+    }
+
+    @Override
+    public void createWebResourceSet(final ResourceSetType type, final String webAppMount, final URL url, final String internalPath) {
+        delegate.createWebResourceSet(type, webAppMount, url, internalPath);
+    }
+
+    @Override
+    public void createWebResourceSet(final ResourceSetType type, final String webAppMount, final String base, final String archivePath, final String internalPath) {
+        delegate.createWebResourceSet(type, webAppMount, base, archivePath, internalPath);
+    }
+
+    @Override
+    public void addPreResources(final WebResourceSet webResourceSet) {
+        delegate.addPreResources(webResourceSet);
+    }
+
+    @Override
+    public WebResourceSet[] getPreResources() {
+        return delegate.getPreResources();
+    }
+
+    @Override
+    public void addJarResources(final WebResourceSet webResourceSet) {
+        delegate.addJarResources(webResourceSet);
+    }
+
+    @Override
+    public WebResourceSet[] getJarResources() {
+        return delegate.getJarResources();
+    }
+
+    @Override
+    public void addPostResources(final WebResourceSet webResourceSet) {
+        delegate.addPostResources(webResourceSet);
+    }
+
+    @Override
+    public WebResourceSet[] getPostResources() {
+        return delegate.getPostResources();
+    }
+
+    @Override
+    public void setAllowLinking(final boolean allowLinking) {
+        delegate.setAllowLinking(allowLinking);
+    }
+
+    @Override
+    public boolean getAllowLinking() {
+        return delegate.getAllowLinking();
+    }
+
+    @Override
+    public void setCachingAllowed(final boolean cachingAllowed) {
+        delegate.setCachingAllowed(cachingAllowed);
+    }
+
+    @Override
+    public boolean isCachingAllowed() {
+        return delegate.isCachingAllowed();
+    }
+
+    @Override
+    public long getCacheTtl() {
+        return delegate.getCacheTtl();
+    }
+
+    @Override
+    public void setCacheTtl(final long cacheTtl) {
+        delegate.setCacheTtl(cacheTtl);
+    }
+
+    @Override
+    public long getCacheMaxSize() {
+        return delegate.getCacheMaxSize();
+    }
+
+    @Override
+    public void setCacheMaxSize(final long cacheMaxSize) {
+        delegate.setCacheMaxSize(cacheMaxSize);
+    }
+
+    @Override
+    public void setCacheObjectMaxSize(final int cacheObjectMaxSize) {
+        delegate.setCacheObjectMaxSize(cacheObjectMaxSize);
+    }
+
+    @Override
+    public int getCacheObjectMaxSize() {
+        return delegate.getCacheObjectMaxSize();
+    }
+
+    @Override
+    public void setTrackLockedFiles(final boolean trackLockedFiles) {
+        delegate.setTrackLockedFiles(trackLockedFiles);
+    }
+
+    @Override
+    public boolean getTrackLockedFiles() {
+        return delegate.getTrackLockedFiles();
+    }
+
+    public List<String> getTrackedResources() { // IDE?
+        return StandardRoot.class.cast(delegate).getTrackedResources();
+    }
+
+    @Override
+    public Context getContext() {
+        return delegate.getContext();
+    }
+
+    @Override
+    public void setContext(final Context context) {
+        delegate.setContext(context);
+    }
+
+    @Override
+    public void backgroundProcess() {
+        delegate.backgroundProcess();
+    }
+
+    @Override
+    public void gc() {
+        delegate.gc();
+    }
+
+    @Override
+    public void registerTrackedResource(final TrackedWebResource trackedResource) {
+        delegate.registerTrackedResource(trackedResource);
+    }
+
+    @Override
+    public void deregisterTrackedResource(final TrackedWebResource trackedResource) {
+        delegate.deregisterTrackedResource(trackedResource);
+    }
+
+    @Override
+    public List<URL> getBaseUrls() {
+        return delegate.getBaseUrls();
+    }
+
+    public void setDomain(final String domain) {
+        if (isJmxEnabled) {
+            JmxEnabled.class.cast(delegate).setDomain(domain);
+        }
+    }
+
+    public String getDomain() {
+        if (isJmxEnabled) {
+            return JmxEnabled.class.cast(delegate).getDomain();
+        }
+        return null;
+    }
+
+    public ObjectName getObjectName() {
+        if (isJmxEnabled) {
+            return JmxEnabled.class.cast(delegate).getObjectName();
+        }
+        return null;
+    }
+
+    public void postDeregister() {
+        if (isLifecycleMBeanBase) {
+            LifecycleMBeanBase.class.cast(delegate).postDeregister();
+        }
+    }
+
+    public void postRegister(final Boolean registrationDone) {
+        if (isLifecycleMBeanBase) {
+            LifecycleMBeanBase.class.cast(delegate).postRegister(registrationDone);
+        }
+    }
+
+    public void preDeregister() throws Exception {
+        if (isLifecycleMBeanBase) {
+            LifecycleMBeanBase.class.cast(delegate).preDeregister();
+        }
+    }
+
+    public ObjectName preRegister(final MBeanServer server, final ObjectName name) throws Exception {
+        if (isLifecycleMBeanBase) {
+            return LifecycleMBeanBase.class.cast(delegate).preRegister(server, name);
+        }
+        return name;
+    }
+
+    @Override
+    public void addLifecycleListener(final LifecycleListener listener) {
+        delegate.addLifecycleListener(listener);
+    }
+
+    @Override
+    public LifecycleListener[] findLifecycleListeners() {
+        return delegate.findLifecycleListeners();
+    }
+
+    @Override
+    public void removeLifecycleListener(final LifecycleListener listener) {
+        delegate.removeLifecycleListener(listener);
+    }
+
+    @Override
+    public LifecycleState getState() {
+        return delegate.getState();
+    }
+
+    @Override
+    public String getStateName() {
+        return delegate.getStateName();
+    }
+
+    @Override
+    public void init() throws LifecycleException {
+        delegate.init();
+    }
+
+    @Override
+    public void start() throws LifecycleException {
+        delegate.start();
+    }
+
+    @Override
+    public void stop() throws LifecycleException {
+        // delegate.stop();
+    }
+
+    @Override
+    public void destroy() throws LifecycleException {
+        // delegate.destroy();
+    }
+
+    public void internalStop() throws LifecycleException {
+        delegate.stop();
+        delegate.destroy();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/1665a38f/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 9930946..e2364e6 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
@@ -80,7 +80,7 @@ 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 boolean forceStopPhase = Boolean.parseBoolean(SystemInstance.get().getProperty("tomee.webappclassloader.force-stop-phase", "false"));
     private ClassLoaderConfigurer configurer;
     private final boolean isEar;
     private final ClassLoader containerClassLoader;
@@ -89,6 +89,7 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
     private Collection<File> additionalRepos;
     private volatile boolean stopped = false;
     private final Map<String, Boolean> filterTempCache = new HashMap<>(); // used only in sync block + isEar
+    private volatile LazyStopStandardRoot webResourceRoot;
 
     public TomEEWebappClassLoader() {
         hashCode = construct();
@@ -263,9 +264,16 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
         thread.setContextClassLoader(this);
         try {
             super.stop();
+            super.destroy();
+            if (webResourceRoot != null) {
+                webResourceRoot.internalStop();
+            }
             stopped = true;
         } finally {
             thread.setContextClassLoader(loader);
+            if (!forceStopPhase) {
+                cleanUpClassLoader();
+            }
         }
     }
 
@@ -281,6 +289,10 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
         return restarting;
     }
 
+    public boolean isForceStopPhase() {
+        return forceStopPhase;
+    }
+
     public boolean isStopped() {
         return stopped;
     }
@@ -432,16 +444,22 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
 
     @Override
     public void destroy() {
-        try {
-            super.destroy();
-        } finally {
-            final LogManager lm = LogManager.getLogManager();
-            if (ClassLoaderLogManager.class.isInstance(lm)) { // weak ref but ensure it is really removed otherwise in some cases we leak
-                Map.class.cast(Reflections.get(lm, "classLoaderLoggers")).remove(this);
+        if (forceStopPhase) {
+            try {
+                super.destroy();
+            } finally {
+                cleanUpClassLoader();
             }
         }
     }
 
+    private void cleanUpClassLoader() {
+        final LogManager lm = LogManager.getLogManager();
+        if (ClassLoaderLogManager.class.isInstance(lm)) { // weak ref but ensure it is really removed otherwise in some cases we leak
+            Map.class.cast(Reflections.get(lm, "classLoaderLoggers")).remove(this);
+        }
+    }
+
     public static void initContext(final ClassLoaderConfigurer configurer) {
         INIT_CONFIGURER.set(configurer);
     }
@@ -455,6 +473,10 @@ public class TomEEWebappClassLoader extends ParallelWebappClassLoader {
         CONTEXT.remove();
     }
 
+    public void setWebResourceRoot(LazyStopStandardRoot webResourceRoot) {
+        this.webResourceRoot = webResourceRoot;
+    }
+
     private static class NoClassClassLoader extends ClassLoader {
         private static final NoClassClassLoader INSTANCE = new NoClassClassLoader();
 

http://git-wip-us.apache.org/repos/asf/tomee/blob/1665a38f/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java
----------------------------------------------------------------------
diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java
index 319293a..fbf604b 100644
--- a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java
+++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatWebAppBuilder.java
@@ -106,6 +106,7 @@ import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
 import org.apache.openejb.util.URLs;
 import org.apache.openejb.util.proxy.LocalBeanProxyFactory;
+import org.apache.openejb.util.reflection.Reflections;
 import org.apache.tomcat.InstanceManager;
 import org.apache.tomcat.JarScanFilter;
 import org.apache.tomcat.util.descriptor.web.ApplicationParameter;
@@ -130,22 +131,6 @@ import org.apache.webbeans.config.WebBeansContext;
 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.http.HttpServletRequest;
-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;
@@ -169,6 +154,22 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReference;
 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.http.HttpServletRequest;
+import javax.servlet.jsp.JspApplicationContext;
+import javax.servlet.jsp.JspFactory;
+import javax.sql.DataSource;
+import javax.transaction.TransactionManager;
+import javax.transaction.TransactionSynchronizationRegistry;
 
 import static java.util.Arrays.asList;
 import static org.apache.tomee.catalina.Contexts.warPath;
@@ -1510,7 +1511,7 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
 
         // skip undeployment if restarting
         final TomEEWebappClassLoader tomEEWebappClassLoader = lazyClassLoader(
-            org.apache.catalina.Context.class.isInstance(child)? org.apache.catalina.Context.class.cast(child) : null);
+                org.apache.catalina.Context.class.isInstance(child) ? org.apache.catalina.Context.class.cast(child) : null);
         if (tomEEWebappClassLoader != null && tomEEWebappClassLoader.isRestarting()) {
             return true;
         }
@@ -1846,9 +1847,20 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
      */
     @Override
     public void beforeStop(final StandardContext standardContext) {
+        final ClassLoader classLoader = standardContext.getLoader().getClassLoader();
+
         // if it is not our custom loader clean up now otherwise wait afterStop
         if (!(standardContext.getLoader() instanceof LazyStopLoader)) {
-            jsfClasses.remove(standardContext.getLoader().getClassLoader());
+            jsfClasses.remove(classLoader);
+        }
+
+        // ensure we can stop it lazily - before all was in the classloader, now we align webresourceroot on the classloader config
+        // we wrap it only here to not modify at all runtime
+        if (!LazyStopStandardRoot.class.isInstance(standardContext.getResources())
+                && TomEEWebappClassLoader.class.isInstance(classLoader) && !TomEEWebappClassLoader.class.cast(classLoader).isForceStopPhase()) {
+            final LazyStopStandardRoot standardRoot = new LazyStopStandardRoot(standardContext.getResources());
+            Reflections.set(standardContext, "resources", standardRoot);
+            TomEEWebappClassLoader.class.cast(classLoader).setWebResourceRoot(standardRoot); // cause Assembler relies on the classloader only
         }
     }