TOMEE-1572 add a ThreadBindingListener to prevent mem leaks in async servlet requests
Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/c8c7f5c9 Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/c8c7f5c9 Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/c8c7f5c9 Branch: refs/heads/master Commit: c8c7f5c91a94ed3c40f42b8e635cb0e6bb9aaae5 Parents: ac291b9 Author: Mark Struberg <[email protected]> Authored: Thu May 14 18:50:14 2015 +0200 Committer: Mark Struberg <[email protected]> Committed: Thu May 14 18:50:14 2015 +0200 ---------------------------------------------------------------------- .../tomee/catalina/TomcatWebAppBuilder.java | 8 +++ .../cdi/WebBeansThreadBindingListener.java | 56 ++++++++++++++++++++ 2 files changed, 64 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/c8c7f5c9/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 8137673..a64dab3 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 @@ -79,6 +79,7 @@ import org.apache.openejb.assembler.classic.WebAppBuilder; import org.apache.openejb.assembler.classic.WebAppInfo; import org.apache.openejb.assembler.classic.event.NewEjbAvailableAfterApplicationCreated; import org.apache.openejb.cdi.CdiBuilder; +import org.apache.openejb.cdi.OWBContextThreadListener; import org.apache.openejb.cdi.OpenEJBLifecycle; import org.apache.openejb.cdi.Proxys; import org.apache.openejb.config.AppModule; @@ -118,6 +119,7 @@ import org.apache.tomcat.util.descriptor.web.FilterMap; import org.apache.tomcat.util.descriptor.web.ResourceBase; import org.apache.tomcat.util.scan.StandardJarScanFilter; import org.apache.tomee.catalina.cdi.ServletContextHandler; +import org.apache.tomee.catalina.cdi.WebBeansThreadBindingListener; import org.apache.tomee.catalina.cluster.ClusterObserver; import org.apache.tomee.catalina.cluster.TomEEClusterListener; import org.apache.tomee.catalina.environment.Hosts; @@ -1678,6 +1680,12 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare newLifecycleListeners[newLifecycleListeners.length - 1] = endWebBeansListener; standardContext.setApplicationLifecycleListeners(newLifecycleListeners); } + + // also add the ThreadBindingListener to clean up async thread executions + { + WebBeansThreadBindingListener webBeansThreadBindingListener = new WebBeansThreadBindingListener(webBeansContext, standardContext.getThreadBindingListener()); + standardContext.setThreadBindingListener(webBeansThreadBindingListener); + } } else { // just add the end listener to be able to stack tasks to execute at the request end final EndWebBeansListener endWebBeansListener = new EndWebBeansListener(webBeansContext); http://git-wip-us.apache.org/repos/asf/tomee/blob/c8c7f5c9/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/cdi/WebBeansThreadBindingListener.java ---------------------------------------------------------------------- diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/cdi/WebBeansThreadBindingListener.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/cdi/WebBeansThreadBindingListener.java new file mode 100644 index 0000000..10bb76a --- /dev/null +++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/cdi/WebBeansThreadBindingListener.java @@ -0,0 +1,56 @@ +/** + * 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.cdi; + +import javax.enterprise.context.RequestScoped; + +import org.apache.catalina.ThreadBindingListener; +import org.apache.webbeans.config.WebBeansContext; +import org.apache.webbeans.spi.ContextsService; + +/** + * For Tomcat we need to implement a ThreadBindingListener to + * release the ServletRequest in case of Async requests. + * Tomcat only sends the requestDestroyed event only when the 'final' + * detached response gets rendered. But this happens on a totally + * different Thread. + * Thus in order to release e.g. locks on Conversations and prevent mem leaks + * we need to end the request on unbind() as well. + * Note that the ContextsService will do nothing if the Request was already + * properly destroyed in standard synchronous Servlet Requests. + */ +public class WebBeansThreadBindingListener implements ThreadBindingListener { + + private final ContextsService contextsService; + private final ThreadBindingListener delegate; + + public WebBeansThreadBindingListener(WebBeansContext webBeansContext, ThreadBindingListener delegate) { + this.contextsService = webBeansContext.getContextsService(); + this.delegate = delegate; + } + + @Override + public void bind() { + delegate.bind(); + } + + @Override + public void unbind() { + contextsService.endContext(RequestScoped.class, null); + delegate.unbind(); + } +}
