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/12/29 10:26:19 UTC

tomee git commit: TOMEE-1687 firing ApplicationScoped initialized event after webapp start

Repository: tomee
Updated Branches:
  refs/heads/master ee551e05d -> b25b8bda8


TOMEE-1687 firing ApplicationScoped initialized event after webapp start


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

Branch: refs/heads/master
Commit: b25b8bda863132382bb9c9c68664fb240bf4e454
Parents: ee551e0
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Tue Dec 29 10:24:44 2015 +0100
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Tue Dec 29 10:24:44 2015 +0100

----------------------------------------------------------------------
 .../embedded/AppContextStartedTest.java         | 73 ++++++++++++++++++++
 .../openejb/arquillian/embedded/Start.java      | 45 ++++++++++++
 .../openejb/cdi/CdiAppContextsService.java      | 24 ++++---
 .../apache/openejb/cdi/OpenEJBLifecycle.java    | 30 +-------
 .../java/org/apache/openejb/cdi/Proxys.java     | 12 +++-
 .../openejb/cdi/AppScopeInitEventTest.java      | 45 ++++++++++++
 .../server/httpd/EmbeddedServletContext.java    | 22 ++++++
 .../server/httpd/AppScopeInitEventTest.java     | 72 +++++++++++++++++++
 .../tomee/catalina/TomcatWebAppBuilder.java     | 22 +++++-
 .../catalina/cdi/ServletContextHandler.java     | 21 +++++-
 10 files changed, 323 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/arquillian/arquillian-tomee-embedded/src/test/java/org/apache/openejb/arquillian/embedded/AppContextStartedTest.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-embedded/src/test/java/org/apache/openejb/arquillian/embedded/AppContextStartedTest.java b/arquillian/arquillian-tomee-embedded/src/test/java/org/apache/openejb/arquillian/embedded/AppContextStartedTest.java
new file mode 100644
index 0000000..322255f
--- /dev/null
+++ b/arquillian/arquillian-tomee-embedded/src/test/java/org/apache/openejb/arquillian/embedded/AppContextStartedTest.java
@@ -0,0 +1,73 @@
+/**
+ * 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.embedded;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jboss.shrinkwrap.descriptor.api.Descriptors;
+import org.jboss.shrinkwrap.descriptor.api.webapp31.WebAppDescriptor;
+import org.jboss.shrinkwrap.descriptor.api.webcommon31.WebAppVersionType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(Arquillian.class)
+public class AppContextStartedTest {
+    @Deployment
+    public static Archive<?> app() {
+        return ShrinkWrap.create(WebArchive.class, AppContextStartedTest.class.getSimpleName() + ".war")
+            .addClass(Start.class)
+            .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
+            .setWebXML(new StringAsset(
+                Descriptors.create(WebAppDescriptor.class)
+                    .version(WebAppVersionType._3_1)
+                    .getOrCreateContextParam()
+                        .paramName("test")
+                        .paramValue("start")
+                    .up()
+                    .exportAsString()
+            ));
+    }
+
+    @Inject
+    private Start start;
+
+    @Inject
+    private ServletContext context;
+
+    @Test
+    public void checkAccessAtStartup() {
+        assertNotNull(start.getContext());
+        assertEquals("start", start.getValue());
+    }
+
+    @Test
+    public void checkAccessAtRuntime() {
+        assertEquals("start", start.getContext().getInitParameter("test"));
+        assertEquals("start", context.getInitParameter("test"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/arquillian/arquillian-tomee-embedded/src/test/java/org/apache/openejb/arquillian/embedded/Start.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-embedded/src/test/java/org/apache/openejb/arquillian/embedded/Start.java b/arquillian/arquillian-tomee-embedded/src/test/java/org/apache/openejb/arquillian/embedded/Start.java
new file mode 100644
index 0000000..c33efad
--- /dev/null
+++ b/arquillian/arquillian-tomee-embedded/src/test/java/org/apache/openejb/arquillian/embedded/Start.java
@@ -0,0 +1,45 @@
+/**
+ * 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.embedded;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Initialized;
+import javax.enterprise.event.Observes;
+import javax.servlet.ServletContext;
+
+@ApplicationScoped
+public class Start {
+    private volatile ServletContext context;
+    private volatile String value;
+
+    private void capture(@Observes @Initialized(ApplicationScoped.class) final ServletContext context) {
+        if (this.context != null) {
+            throw new IllegalStateException("app context started twice");
+        }
+
+        this.context = context;
+        this.value = context.getInitParameter("test");
+    }
+
+    public ServletContext getContext() {
+        return context;
+    }
+
+    public String getValue() {
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiAppContextsService.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiAppContextsService.java b/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiAppContextsService.java
index c03778b..c5f69eb 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiAppContextsService.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/cdi/CdiAppContextsService.java
@@ -82,17 +82,23 @@ public class CdiAppContextsService extends WebContextsService implements Context
             } else if (ServletContextEvent.class.isInstance(initializeObject)) {
                 event = ServletContextEvent.class.cast(initializeObject).getServletContext();
             }
-            Object appEvent = event != null ? event : applicationContext;
-            webBeansContext.getBeanManagerImpl().fireEvent(
-                    appEvent,
-                    new EventMetadataImpl(null,
-                            ServletContext.class.isInstance(appEvent) ? ServletContext.class : Object.class, null,
-                            new Annotation[]{InitializedLiteral.INSTANCE_APPLICATION_SCOPED},
-                            webBeansContext),
-                    false);
+            if (!FiredManually.class.isInstance(event)) {
+                applicationStarted(event);
+            }
         }
     }
 
+    public void applicationStarted(final Object event) {
+        Object appEvent = event != null ? event : applicationContext;
+        webBeansContext.getBeanManagerImpl().fireEvent(
+                appEvent,
+                new EventMetadataImpl(null,
+                        ServletContext.class.isInstance(appEvent) ? ServletContext.class : Object.class, null,
+                        new Annotation[]{InitializedLiteral.INSTANCE_APPLICATION_SCOPED},
+                        webBeansContext),
+                false);
+    }
+
     public void destroy(final Object destroyObject) {
         super.destroy(destroyObject);
         removeThreadLocals();
@@ -106,4 +112,6 @@ public class CdiAppContextsService extends WebContextsService implements Context
 
         super.destroyRequestContext(requestEvent);
     }
+
+    public interface FiredManually {}
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/container/openejb-core/src/main/java/org/apache/openejb/cdi/OpenEJBLifecycle.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/cdi/OpenEJBLifecycle.java b/container/openejb-core/src/main/java/org/apache/openejb/cdi/OpenEJBLifecycle.java
index dd25ddf..a718bb8 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/cdi/OpenEJBLifecycle.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/cdi/OpenEJBLifecycle.java
@@ -73,9 +73,6 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Properties;
 import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
 
 /**
  * @version $Rev:$ $Date:$
@@ -111,7 +108,6 @@ public class OpenEJBLifecycle implements ContainerLifecycle {
     /**
      * Manages unused conversations
      */
-    private ScheduledExecutorService service;
 
     public OpenEJBLifecycle(final WebBeansContext webBeansContext) {
         this.webBeansContext = webBeansContext;
@@ -121,8 +117,6 @@ public class OpenEJBLifecycle implements ContainerLifecycle {
         this.jndiService = webBeansContext.getService(JNDIService.class);
         this.scannerService = webBeansContext.getScannerService();
         this.contextsService = webBeansContext.getContextsService();
-
-        initApplication(null);
     }
 
     @Override
@@ -282,11 +276,6 @@ public class OpenEJBLifecycle implements ContainerLifecycle {
         logger.debug("OpenWebBeans Container is stopping.");
 
         try {
-            //Sub-classes operations
-            if (service != null) {
-                service.shutdownNow();
-            }
-
             // Fire shut down
             if (WebappBeanManager.class.isInstance(beanManager)) {
                 WebappBeanManager.class.cast(beanManager).beforeStop();
@@ -381,23 +370,10 @@ public class OpenEJBLifecycle implements ContainerLifecycle {
     }
 
     public void startServletContext(final ServletContext servletContext) {
-        if (service != null) {
-            return;
-        }
-        service = initializeServletContext(servletContext, webBeansContext);
+        initializeServletContext(servletContext, webBeansContext);
     }
 
-    public static ScheduledExecutorService initializeServletContext(final ServletContext servletContext, final WebBeansContext context) {
-
-        final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1, new ThreadFactory() {
-            @Override
-            public Thread newThread(final Runnable runable) {
-                final Thread t = new Thread(runable, "OwbConversationCleaner-" + servletContext.getContextPath());
-                t.setDaemon(true);
-                return t;
-            }
-        });
-
+    public static void initializeServletContext(final ServletContext servletContext, final WebBeansContext context) {
         final ELAdaptor elAdaptor = context.getService(ELAdaptor.class);
         final ELResolver resolver = elAdaptor.getOwbELResolver();
         //Application is configured as JSP
@@ -409,8 +385,6 @@ public class OpenEJBLifecycle implements ContainerLifecycle {
 
         // Add BeanManager to the 'javax.enterprise.inject.spi.BeanManager' servlet context attribute
         servletContext.setAttribute(BeanManager.class.getName(), context.getBeanManagerImpl());
-
-        return executorService;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/container/openejb-core/src/main/java/org/apache/openejb/cdi/Proxys.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/cdi/Proxys.java b/container/openejb-core/src/main/java/org/apache/openejb/cdi/Proxys.java
index f1a7de4..c98027b 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/cdi/Proxys.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/cdi/Proxys.java
@@ -23,6 +23,10 @@ import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static java.util.Arrays.asList;
 
 // some helper reused accross several modules
 public final class Proxys {
@@ -36,9 +40,13 @@ public final class Proxys {
                 new Class<?>[] { HttpSession.class, Serializable.class }, new ThreadLocalSessionFromRequestHandler(threadLocal, defaultValue));
     }
 
-    public static <T> T handlerProxy(final Class<T> type, final InvocationHandler raw) {
+    public static <T> T handlerProxy(final InvocationHandler raw, final Class<T> main, final Class<?>... type) {
+        final Collection<Class<?>> types = new ArrayList<>(type.length + 2);
+        types.add(main);
+        types.addAll(asList(type));
+        types.add(Serializable.class);
         return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
-                new Class<?>[] { type, Serializable.class }, new EnsureExceptionIsUnwrapped(raw));
+                types.toArray(new Class<?>[types.size()]), new EnsureExceptionIsUnwrapped(raw));
     }
 
     private Proxys() {

http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/container/openejb-core/src/test/java/org/apache/openejb/cdi/AppScopeInitEventTest.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/cdi/AppScopeInitEventTest.java b/container/openejb-core/src/test/java/org/apache/openejb/cdi/AppScopeInitEventTest.java
new file mode 100644
index 0000000..e0ff032
--- /dev/null
+++ b/container/openejb-core/src/test/java/org/apache/openejb/cdi/AppScopeInitEventTest.java
@@ -0,0 +1,45 @@
+package org.apache.openejb.cdi;
+
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.testing.Classes;
+import org.apache.openejb.testing.SimpleLog;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Initialized;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+
+import static org.junit.Assert.assertNotNull;
+
+@SimpleLog
+@Classes(cdi = true, innerClassesAsBean = true)
+@RunWith(ApplicationComposer.class)
+public class AppScopeInitEventTest { // servlet context not present without config cause we miss http module
+    @Inject
+    private Start start;
+
+    @Test
+    public void checkAccessAtStartup() {
+        assertNotNull(start.getContext());
+    }
+
+    @ApplicationScoped
+    public static class Start {
+        private volatile Object context;
+
+        // ensure we start only once
+        private void capture(@Observes @Initialized(ApplicationScoped.class) final Object context) {
+            if (this.context != null) {
+                throw new IllegalStateException("app context started twice");
+            }
+
+            this.context = context;
+        }
+
+        public Object getContext() {
+            return context;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/EmbeddedServletContext.java
----------------------------------------------------------------------
diff --git a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/EmbeddedServletContext.java b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/EmbeddedServletContext.java
index d6ecc3c..18994eb 100644
--- a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/EmbeddedServletContext.java
+++ b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/EmbeddedServletContext.java
@@ -33,6 +33,7 @@ import java.util.concurrent.ConcurrentHashMap;
 
 public class EmbeddedServletContext extends MockServletContext {
     private final Map<String, Object> attributes = new ConcurrentHashMap<>();
+    private final Map<String, String> initParameters = new ConcurrentHashMap<>();
 
     private Collection<ResourceProvider> resourceProviders = new ArrayList<>();
 
@@ -43,6 +44,22 @@ public class EmbeddedServletContext extends MockServletContext {
     }
 
     @Override
+    public String getInitParameter(final String name) {
+        return initParameters.get(name);
+    }
+
+    @Override
+    public Enumeration<String> getInitParameterNames() {
+        return Collections.enumeration(initParameters.keySet());
+    }
+
+    @Override
+    public boolean setInitParameter(final String name, final String value) {
+        initParameters.put(name, value);
+        return true;
+    }
+
+    @Override
     public ClassLoader getClassLoader() {
         return Thread.currentThread().getContextClassLoader();
     }
@@ -90,6 +107,11 @@ public class EmbeddedServletContext extends MockServletContext {
     }
 
     @Override
+    public int getMinorVersion() {
+        return 1;
+    }
+
+    @Override
     public String getVirtualServerName() {
         return "openejb";
     }

http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/AppScopeInitEventTest.java
----------------------------------------------------------------------
diff --git a/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/AppScopeInitEventTest.java b/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/AppScopeInitEventTest.java
new file mode 100644
index 0000000..f1578a2
--- /dev/null
+++ b/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/AppScopeInitEventTest.java
@@ -0,0 +1,72 @@
+package org.apache.openejb.server.httpd;
+
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.testing.Classes;
+import org.apache.openejb.testing.Component;
+import org.apache.openejb.testing.EnableServices;
+import org.apache.openejb.testing.SimpleLog;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Initialized;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@SimpleLog
+@EnableServices("http")
+@Classes(cdi = true, innerClassesAsBean = true)
+@RunWith(ApplicationComposer.class)
+public class AppScopeInitEventTest {
+    @Component
+    public ServletContext context() { // default one doesnt read WebApp
+        final EmbeddedServletContext servletContext = new EmbeddedServletContext();
+        servletContext.setInitParameter("test", "start");
+        return servletContext;
+    }
+
+    @Inject
+    private Start start;
+
+    @Inject
+    private ServletContext context;
+
+    @Test
+    public void checkAccessAtStartup() {
+        assertNotNull(start.getContext());
+        assertEquals("start", start.getValue());
+    }
+
+    @Test
+    public void checkAccessAtRuntime() {
+        assertEquals("start", start.getContext().getInitParameter("test"));
+        assertEquals("start", context.getInitParameter("test"));
+    }
+
+    @ApplicationScoped
+    public static class Start {
+        private volatile ServletContext context;
+        private volatile String value;
+
+        private void capture(@Observes @Initialized(ApplicationScoped.class) final ServletContext context) {
+            if (this.context != null) {
+                throw new IllegalStateException("app context started twice");
+            }
+
+            this.context = context;
+            this.value = context.getInitParameter("test");
+        }
+
+        public ServletContext getContext() {
+            return context;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/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 a45de69..83b8a12 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.ServletInfo;
 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.CdiAppContextsService;
 import org.apache.openejb.cdi.CdiBuilder;
 import org.apache.openejb.cdi.OpenEJBLifecycle;
 import org.apache.openejb.cdi.Proxys;
@@ -129,6 +130,7 @@ import org.apache.tomee.common.NamingUtil;
 import org.apache.tomee.common.UserTransactionFactory;
 import org.apache.tomee.loader.TomcatHelper;
 import org.apache.webbeans.config.WebBeansContext;
+import org.apache.webbeans.spi.ContextsService;
 import org.apache.webbeans.spi.adaptor.ELAdaptor;
 import org.omg.CORBA.ORB;
 
@@ -265,6 +267,7 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
 
     private ClassLoader parentClassLoader;
     private boolean initJEEInfo = true;
+    private final ServletContextHandler servletContextHandler;
 
     /**
      * Creates a new web application builder
@@ -323,6 +326,7 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
         configurationFactory = new ConfigurationFactory();
         deploymentLoader = new DeploymentLoader();
 
+        servletContextHandler = new ServletContextHandler();
         setComponentsUsedByCDI();
 
         try { // before tomcat was using ServiceLoader or manually instantiation, now it uses SL for itself so we can be in conflict
@@ -341,7 +345,7 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
             systemInstance.setComponent(javax.servlet.http.HttpSession.class, Proxys.threadLocalRequestSessionProxy(OpenEJBSecurityListener.requests, null));
         }
         if (systemInstance.getComponent(ServletContext.class) == null) {
-            systemInstance.setComponent(ServletContext.class, Proxys.handlerProxy(ServletContext.class, new ServletContextHandler()));
+            systemInstance.setComponent(ServletContext.class, Proxys.handlerProxy(servletContextHandler, ServletContext.class, CdiAppContextsService.FiredManually.class));
         }
     }
 
@@ -1211,7 +1215,12 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
 
                     setFinderOnContextConfig(standardContext, appModule);
 
-                    appContext = a.createApplication(contextInfo.appInfo, classLoader);
+                    servletContextHandler.getContexts().put(classLoader, standardContext.getServletContext());
+                    try {
+                        appContext = a.createApplication(contextInfo.appInfo, classLoader);
+                    } finally {
+                        servletContextHandler.getContexts().remove(classLoader);
+                    }
                     // todo add watched resources to context
 
                     eagerInitOfLocalBeanProxies(appContext.getBeanContexts(), classLoader);
@@ -1325,6 +1334,7 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
                 if (!contextInfo.appInfo.webAppAlone) {
                     final List<BeanContext> beanContexts = assembler.initEjbs(classLoader, contextInfo.appInfo, appContext, injections, new ArrayList<BeanContext>(), webAppInfo.moduleId);
                     OpenEJBLifecycle.CURRENT_APP_INFO.set(contextInfo.appInfo);
+                    servletContextHandler.getContexts().put(classLoader, standardContext.getServletContext());
                     try {
                         new CdiBuilder().build(contextInfo.appInfo, appContext, beanContexts, webContext);
                     } catch (final Exception e) {
@@ -1334,6 +1344,7 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
                         }
                         throw e;
                     } finally {
+                        servletContextHandler.getContexts().remove(classLoader);
                         OpenEJBLifecycle.CURRENT_APP_INFO.remove();
                     }
                     assembler.startEjbs(true, beanContexts);
@@ -1694,6 +1705,11 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
                 WebBeansThreadBindingListener webBeansThreadBindingListener = new WebBeansThreadBindingListener(webBeansContext, standardContext.getThreadBindingListener());
                 standardContext.setThreadBindingListener(webBeansThreadBindingListener);
             }
+
+            final ContextsService contextsService = webBeansContext.getContextsService();
+            if (CdiAppContextsService.class.isInstance(contextsService)) { // here ServletContext is usable
+                CdiAppContextsService.class.cast(contextsService).applicationStarted(standardContext.getServletContext());
+            }
         } else {
             // just add the end listener to be able to stack tasks to execute at the request end
             final EndWebBeansListener endWebBeansListener = new EndWebBeansListener(webBeansContext);
@@ -1757,6 +1773,8 @@ public class TomcatWebAppBuilder implements WebAppBuilder, ContextListener, Pare
         }
 
         addConfiguredDocBases(standardContext, contextInfo);
+
+
     }
 
     private static String appVersion(final AppInfo appInfo) {

http://git-wip-us.apache.org/repos/asf/tomee/blob/b25b8bda/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/cdi/ServletContextHandler.java
----------------------------------------------------------------------
diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/cdi/ServletContextHandler.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/cdi/ServletContextHandler.java
index 63b3031..f7c76cc 100644
--- a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/cdi/ServletContextHandler.java
+++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/cdi/ServletContextHandler.java
@@ -23,27 +23,42 @@ import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.spi.ContainerSystem;
 import org.apache.tomee.catalina.OpenEJBSecurityListener;
 
+import javax.servlet.ServletContext;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 public class ServletContextHandler implements InvocationHandler {
+    private final ConcurrentMap<ClassLoader, ServletContext> contexts = new ConcurrentHashMap<>();
+
     @Override
     public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
-        // ITE are handler by Proxys
+        // ITE are handled by Proxys
         final Request request = OpenEJBSecurityListener.requests.get();
         if (request != null) {
             return method.invoke(request.getServletContext(), args);
         }
 
+        final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+        final ServletContext c = contexts.get(contextClassLoader);
+        if (c != null) {
+            return method.invoke(c, args);
+        }
+
         OpenEJBSecurityListener.requests.remove(); // can be a not container thread so clean it up
         for (final AppContext a : SystemInstance.get().getComponent(ContainerSystem.class).getAppContexts()) {
             for (final WebContext w : a.getWebContexts()) {
-                if (w.getClassLoader() == Thread.currentThread().getContextClassLoader()) { // not in CXF so == should be fine
+                if (w.getClassLoader() == contextClassLoader) { // not in CXF so == should be fine
                     return method.invoke(w.getServletContext(), args);
                 }
             }
         }
 
-        throw new IllegalStateException("Didnt find a web context for " + Thread.currentThread().getContextClassLoader());
+        throw new IllegalStateException("Didnt find a web context for " + contextClassLoader);
+    }
+
+    public ConcurrentMap<ClassLoader, ServletContext> getContexts() {
+        return contexts;
     }
 }