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 2012/11/12 14:50:19 UTC

svn commit: r1408286 - in /openejb/trunk/openejb: container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ container/openejb-core/src/main/java/org/apache/openejb/config/ container/openejb-core/src/main/java/org/apache/openejb/web/ co...

Author: rmannibucau
Date: Mon Nov 12 13:50:17 2012
New Revision: 1408286

URL: http://svn.apache.org/viewvc?rev=1408286&view=rev
Log:
OPENEJB-1932 basic filter + servletcontextinitializer for applicationcomposer

Added:
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/FilterInfo.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ListenerInfo.java
    openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/FilterListener.java
    openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/FilterRegistrationTest.java
      - copied, changed from r1408118, openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ServletRegistrationTest.java
    openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ServletContextListenerRegistrationTest.java
Modified:
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/web/LightweightWebAppBuilder.java
    openejb/trunk/openejb/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java
    openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpListenerRegistry.java
    openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java
    openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletListener.java
    openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletRequestAdapter.java
    openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/util/HttpUtil.java

Added: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/FilterInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/FilterInfo.java?rev=1408286&view=auto
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/FilterInfo.java (added)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/FilterInfo.java Mon Nov 12 13:50:17 2012
@@ -0,0 +1,28 @@
+/*
+ * 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.assembler.classic;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class FilterInfo {
+    public String classname;
+    public List<String> mappings;
+    public Map<String, String> initParams = new HashMap<String, String>();
+    public String name;
+}

Added: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ListenerInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ListenerInfo.java?rev=1408286&view=auto
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ListenerInfo.java (added)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ListenerInfo.java Mon Nov 12 13:50:17 2012
@@ -0,0 +1,21 @@
+/*
+ * 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.assembler.classic;
+
+public class ListenerInfo {
+    public String classname;
+}

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java?rev=1408286&r1=1408285&r2=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java Mon Nov 12 13:50:17 2012
@@ -42,4 +42,6 @@ public class WebAppInfo extends CommonIn
     public final List<ServletInfo> servlets = new ArrayList<ServletInfo>();
     public final List<ClassListInfo> jsfAnnotatedClasses = new ArrayList<ClassListInfo>();
     public final Set<String> jaxRsProviders = new TreeSet<String>();
+    public final List<ListenerInfo> listeners = new ArrayList<ListenerInfo>();
+    public final List<FilterInfo> filters = new ArrayList<FilterInfo>();
 }

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java?rev=1408286&r1=1408285&r2=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java Mon Nov 12 13:50:17 2012
@@ -26,9 +26,11 @@ import org.apache.openejb.assembler.clas
 import org.apache.openejb.assembler.classic.EjbJarInfo;
 import org.apache.openejb.assembler.classic.EnterpriseBeanInfo;
 import org.apache.openejb.assembler.classic.EntityManagerFactoryCallable;
+import org.apache.openejb.assembler.classic.FilterInfo;
 import org.apache.openejb.assembler.classic.HandlerChainInfo;
 import org.apache.openejb.assembler.classic.IdPropertiesInfo;
 import org.apache.openejb.assembler.classic.JndiEncInfo;
+import org.apache.openejb.assembler.classic.ListenerInfo;
 import org.apache.openejb.assembler.classic.MdbContainerInfo;
 import org.apache.openejb.assembler.classic.MessageDrivenBeanInfo;
 import org.apache.openejb.assembler.classic.PersistenceUnitInfo;
@@ -47,9 +49,12 @@ import org.apache.openejb.jee.ConfigProp
 import org.apache.openejb.jee.ConnectionDefinition;
 import org.apache.openejb.jee.Connector;
 import org.apache.openejb.jee.EnterpriseBean;
+import org.apache.openejb.jee.Filter;
 import org.apache.openejb.jee.InboundResourceadapter;
+import org.apache.openejb.jee.Listener;
 import org.apache.openejb.jee.MessageListener;
 import org.apache.openejb.jee.OutboundResourceAdapter;
+import org.apache.openejb.jee.ParamValue;
 import org.apache.openejb.jee.PortComponent;
 import org.apache.openejb.jee.ResourceAdapter;
 import org.apache.openejb.jee.ServiceImplBean;
@@ -399,6 +404,23 @@ class AppInfoBuilder {
                 webAppInfo.servlets.add(servletInfo);
             }
 
+            for (Listener listener : webModule.getWebApp().getListener()) {
+                final ListenerInfo listenerInfo = new ListenerInfo();
+                listenerInfo.classname = listener.getListenerClass();
+                webAppInfo.listeners.add(listenerInfo);
+            }
+
+            for (Filter filter : webModule.getWebApp().getFilter()) {
+                final FilterInfo filterInfo = new FilterInfo();
+                filterInfo.name = filter.getFilterName();
+                filterInfo.classname = filter.getFilterClass();
+                filterInfo.mappings = webModule.getWebApp().getFilterMappings(filter.getFilterName());
+                for (ParamValue pv : filter.getInitParam()) {
+                    filterInfo.initParams.put(pv.getParamName(), pv.getParamValue());
+                }
+                webAppInfo.filters.add(filterInfo);
+            }
+
             appInfo.webApps.add(webAppInfo);
         }
     }

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/web/LightweightWebAppBuilder.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/web/LightweightWebAppBuilder.java?rev=1408286&r1=1408285&r2=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/web/LightweightWebAppBuilder.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/web/LightweightWebAppBuilder.java Mon Nov 12 13:50:17 2012
@@ -21,8 +21,10 @@ import org.apache.openejb.Injection;
 import org.apache.openejb.OpenEJBRuntimeException;
 import org.apache.openejb.assembler.classic.AppInfo;
 import org.apache.openejb.assembler.classic.ClassListInfo;
+import org.apache.openejb.assembler.classic.FilterInfo;
 import org.apache.openejb.assembler.classic.InjectionBuilder;
 import org.apache.openejb.assembler.classic.JndiEncBuilder;
+import org.apache.openejb.assembler.classic.ListenerInfo;
 import org.apache.openejb.assembler.classic.ServletInfo;
 import org.apache.openejb.assembler.classic.WebAppBuilder;
 import org.apache.openejb.assembler.classic.WebAppInfo;
@@ -30,8 +32,10 @@ import org.apache.openejb.core.CoreConta
 import org.apache.openejb.core.WebContext;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.spi.ContainerSystem;
+import org.apache.openejb.util.ArrayEnumeration;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
+import org.apache.webbeans.web.lifecycle.test.MockServletContextEvent;
 
 import javax.naming.Binding;
 import javax.naming.Context;
@@ -41,12 +45,19 @@ import javax.naming.NameNotFoundExceptio
 import javax.naming.NameParser;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.annotation.WebInitParam;
 import javax.servlet.annotation.WebServlet;
 import java.io.File;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
@@ -56,23 +67,33 @@ import java.util.Set;
 public class LightweightWebAppBuilder implements WebAppBuilder {
     private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB, LightweightWebAppBuilder.class);
 
-    private static final Method addServletMethod;
-    private static final Method removeServletMethod;
+    private static Method addServletMethod = null;
+    private static Method removeServletMethod = null;
+    private static Method addFilterMethod = null;
+    private static Method removeFilterMethod = null;
 
     static {
         try {
             final Class<?> utilClass = LightweightWebAppBuilder.class.getClassLoader().loadClass("org.apache.openejb.server.httpd.util.HttpUtil");
             addServletMethod = utilClass.getMethod("addServlet", String.class, WebContext.class, String.class);
             removeServletMethod = utilClass.getMethod("removeServlet", String.class, WebContext.class);
+            addFilterMethod = utilClass.getMethod("addFilter", String.class, WebContext.class, String.class, FilterConfig.class);
+            removeFilterMethod = utilClass.getMethod("removeFilter", String.class, WebContext.class);
         } catch (Exception e) {
-            throw new OpenEJBRuntimeException(e);
+            LOGGER.info("Web features will not be available, add openejb-http if you need them");
         }
     }
 
-    private final Map<WebAppInfo, DeployedServlet> deploymentInfo = new HashMap<WebAppInfo, DeployedServlet>();
+    private final Map<WebAppInfo, DeployedWebObjects> servletDeploymentInfo = new HashMap<WebAppInfo, DeployedWebObjects>();
+    private final Map<WebAppInfo, List<Object>> listeners = new HashMap<WebAppInfo, List<Object>>();
+    private final Map<WebAppInfo, ServletContextEvent> servletContextEvents = new HashMap<WebAppInfo, ServletContextEvent>();
 
     @Override
     public void deployWebApps(final AppInfo appInfo, final ClassLoader classLoader) throws Exception {
+        if (addServletMethod == null) {
+            return;
+        }
+
         final CoreContainerSystem cs = (CoreContainerSystem) SystemInstance.get().getComponent(ContainerSystem.class);
         final AppContext appContext = cs.getAppContext(appInfo.appId);
         if (appContext == null) {
@@ -100,15 +121,75 @@ public class LightweightWebAppBuilder im
             appContext.getWebContexts().add(webContext);
             cs.addWebContext(webContext);
 
-            final DeployedServlet deployedServlet = new DeployedServlet();
-            deployedServlet.webContext = webContext;
+            final ServletContextEvent sce = new MockServletContextEvent();
+            servletContextEvents.put(webAppInfo, sce);
+
+            // otherwise myfaces can't start at all with our light http layer
+            sce.getServletContext().setAttribute("org.apache.myfaces.DYNAMICALLY_ADDED_FACES_SERVLET", true);
+
+            // listeners
+            for (ListenerInfo listener : webAppInfo.listeners) {
+                final Class<?> clazz = webContext.getClassLoader().loadClass(listener.classname);
+                final Object instance = webContext.newInstance(clazz);
+                if (ServletContextListener.class.isInstance(instance)) {
+                    ((ServletContextListener) instance).contextInitialized(sce);
+                }
+
+                List<Object> list = listeners.get(webAppInfo);
+                if (list == null) {
+                    list = new ArrayList<Object>();
+                    listeners.put(webAppInfo, list);
+                }
+                list.add(instance);
+            }
+
+            final DeployedWebObjects deployedWebObjects = new DeployedWebObjects();
+            deployedWebObjects.webContext = webContext;
+
+            // register filters
+            for (FilterInfo info : webAppInfo.filters) {
+                for (String mapping : info.mappings) {
+                    final FilterConfig config = new SimpleFilterConfig(sce.getServletContext(), info.name, info.initParams);
+                    try {
+                        addFilterMethod.invoke(null, info.classname, webContext, mapping, config);
+                        deployedWebObjects.filterMappings.add(mapping);
+                    } catch (Exception e) {
+                        LOGGER.warning(e.getMessage(), e);
+                    }
+                }
+            }
+            for (ClassListInfo info : webAppInfo.webAnnotatedClasses) {
+                final String url = info.name;
+                for (String filterPath : info.list) {
+                    String classname = nameFromUrls(url, filterPath);
+
+                    final Class<?> clazz = webContext.getClassLoader().loadClass(classname);
+                    final WebFilter annotation = clazz.getAnnotation(WebFilter.class);
+                    if (annotation != null) {
+                        final Map<String, String> initParams = new HashMap<String, String>();
+                        for (WebInitParam param : annotation.initParams()) {
+                            initParams.put(param.name(), param.value());
+                        }
+
+                        final FilterConfig config = new SimpleFilterConfig(sce.getServletContext(), info.name, initParams);
+                        for (String mapping: annotation.urlPatterns()) {
+                            try {
+                                addFilterMethod.invoke(null, classname, webContext, mapping, config);
+                                deployedWebObjects.filterMappings.add(mapping);
+                            } catch (Exception e) {
+                                LOGGER.warning(e.getMessage(), e);
+                            }
+                        }
+                    }
+                }
+            }
 
             // register servlets
             for (ServletInfo info : webAppInfo.servlets) {
                 for (String mapping : info.mappings) {
                     try {
                         addServletMethod.invoke(null, info.servletClass, webContext, mapping);
-                        deployedServlet.mappings.add(mapping);
+                        deployedWebObjects.mappings.add(mapping);
                     } catch (Exception e) {
                         LOGGER.warning(e.getMessage(), e);
                     }
@@ -117,8 +198,7 @@ public class LightweightWebAppBuilder im
             for (ClassListInfo info : webAppInfo.webAnnotatedClasses) {
                 final String url = info.name;
                 for (String servletPath : info.list) {
-                    String classname = servletPath.substring(url.length()).replace(File.separatorChar, '/').replace('/', '.');
-                    classname = classname.substring(0, classname.length() - ".class".length());
+                    String classname = nameFromUrls(url, servletPath);
 
                     final Class<?> clazz = webContext.getClassLoader().loadClass(classname);
                     final WebServlet annotation = clazz.getAnnotation(WebServlet.class);
@@ -126,7 +206,7 @@ public class LightweightWebAppBuilder im
                         for (String mapping: annotation.urlPatterns()) {
                             try {
                                 addServletMethod.invoke(null, classname, webContext, mapping);
-                                deployedServlet.mappings.add(mapping);
+                                deployedWebObjects.mappings.add(mapping);
                             } catch (Exception e) {
                                 LOGGER.warning(e.getMessage(), e);
                             }
@@ -135,14 +215,25 @@ public class LightweightWebAppBuilder im
                 }
             }
 
-            deploymentInfo.put(webAppInfo, deployedServlet);
+            servletDeploymentInfo.put(webAppInfo, deployedWebObjects);
         }
     }
 
+    private static String nameFromUrls(final String url, final String path) {
+        final String value = path.substring(url.length()).replace(File.separatorChar, '/').replace('/', '.');
+        return value.substring(0, value.length() - ".class".length());
+    }
+
     @Override
     public void undeployWebApps(final AppInfo appInfo) throws Exception {
+        if (addServletMethod == null) {
+            return;
+        }
+
         for (WebAppInfo webAppInfo : appInfo.webApps) {
-            final DeployedServlet context = deploymentInfo.remove(webAppInfo);
+            final DeployedWebObjects context = servletDeploymentInfo.remove(webAppInfo);
+            final ServletContextEvent sce = servletContextEvents.remove(webAppInfo);
+            final List<Object> listenerInstances = listeners.remove(webAppInfo);
 
             for (String mapping : context.mappings) {
                 try {
@@ -151,6 +242,22 @@ public class LightweightWebAppBuilder im
                     // no-op
                 }
             }
+
+            for (String mapping : context.filterMappings) {
+                try {
+                    removeFilterMethod.invoke(null, mapping, context.webContext);
+                } catch (Exception e) {
+                    // no-op
+                }
+            }
+
+            if (listenerInstances != null) {
+                for (Object instance : listenerInstances) {
+                    if (ServletContextListener.class.isInstance(instance)) {
+                        ((ServletContextListener) instance).contextDestroyed(sce);
+                    }
+                }
+            }
         }
     }
 
@@ -159,8 +266,9 @@ public class LightweightWebAppBuilder im
         return Collections.emptyMap(); // while we don't manage servlet in embedded mode we don't need it
     }
 
-    private static class DeployedServlet {
+    private static class DeployedWebObjects {
         public List<String> mappings = new ArrayList<String>();
+        public List<String> filterMappings = new ArrayList<String>();
         public WebContext webContext;
     }
 
@@ -322,4 +430,36 @@ public class LightweightWebAppBuilder im
             return null;
         }
     }
+
+    private static class SimpleFilterConfig implements FilterConfig {
+        private final Map<String, String> params;
+        private final String name;
+        private final ServletContext servletContext;
+
+        public SimpleFilterConfig(final ServletContext sc, final String name, final Map<String, String> initParams) {
+            this.name = name;
+            params = initParams;
+            servletContext = sc;
+        }
+
+        @Override
+        public String getFilterName() {
+            return name;
+        }
+
+        @Override
+        public ServletContext getServletContext() {
+            return servletContext;
+        }
+
+        @Override
+        public String getInitParameter(final String name) {
+            return params.get(name);
+        }
+
+        @Override
+        public Enumeration<String> getInitParameterNames() {
+            return new ArrayEnumeration(params.keySet());
+        }
+    }
 }

Modified: openejb/trunk/openejb/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java?rev=1408286&r1=1408285&r2=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java (original)
+++ openejb/trunk/openejb/container/openejb-jee/src/main/java/org/apache/openejb/jee/WebApp.java Mon Nov 12 13:50:17 2012
@@ -637,6 +637,18 @@ public class WebApp implements WebCommon
         return Collections.emptyList();
     }
 
+    public List<String> getFilterMappings(final String filterName) {
+        if (filterMapping == null || filterName == null) {
+            return Collections.emptyList();
+        }
+        for (FilterMapping mapping : filterMapping) {
+            if (filterName.equals(mapping.getFilterName())) {
+                return mapping.getUrlPattern();
+            }
+        }
+        return Collections.emptyList();
+    }
+
     private Servlet findServlet(final String name) {
         for (Servlet s : getServlet()) {
             if (name.equals(s.getServletName())) {
@@ -680,8 +692,58 @@ public class WebApp implements WebCommon
         return this;
     }
 
+    public WebApp addFilter(final String name, final String clazz, final String... mappings) {
+        final Filter newFilter = new Filter();
+        newFilter.setFilterName(name);
+        newFilter.setFilterClass(clazz);
+
+        if (mappings != null && mappings.length > 0) {
+            final FilterMapping sm = new FilterMapping();
+            sm.setFilterName(name);
+
+            for (String mapping : mappings) {
+                if (filterMapping == null) {
+                    filterMapping = new ArrayList<FilterMapping>();
+                }
+
+                sm.getUrlPattern().add(mapping);
+            }
+            filterMapping.add(sm);
+        }
+
+        getFilter().add(newFilter);
+
+        return this;
+    }
+
+    public WebApp addFilterInitParam(final String filterName, final String name, final String value) {
+        final ParamValue paramValue = new ParamValue();
+        paramValue.setParamName(name);
+        paramValue.setParamValue(value);
+
+        findFilter(filterName).getInitParam().add(paramValue);
+
+        return this;
+    }
+
+    private Filter findFilter(final String filterName) {
+        for (Filter s : getFilter()) {
+            if (filterName.equals(s.getFilterName())) {
+                return s;
+            }
+        }
+        return null;
+    }
+
     public WebApp contextRoot(final String root) {
         setContextRoot(root);
         return this;
     }
+
+    public WebApp addListener(final String classname) {
+        final Listener l = new Listener();
+        l.setListenerClass(classname);
+        getListener().add(l);
+        return this;
+    }
 }

Added: openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/FilterListener.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/FilterListener.java?rev=1408286&view=auto
==============================================================================
--- openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/FilterListener.java (added)
+++ openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/FilterListener.java Mon Nov 12 13:50:17 2012
@@ -0,0 +1,79 @@
+/*
+ * 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.server.httpd;
+
+import org.apache.openejb.loader.SystemInstance;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+public class FilterListener implements HttpListener {
+    private final String context;
+    private final Filter delegate;
+
+    public FilterListener(final Filter filter, final String contextRoot) {
+        delegate = filter;
+        context = contextRoot;
+    }
+
+    @Override
+    public void onMessage(final HttpRequest request, final HttpResponse response) throws Exception {
+        HttpRequestImpl req = null;
+        if (request instanceof HttpRequestImpl) {
+            req = (HttpRequestImpl) request;
+        } else if (request instanceof ServletRequestAdapter) {
+            final HttpServletRequest delegate = ((ServletRequestAdapter) request).getRequest();
+            if (delegate instanceof HttpRequestImpl) {
+                req = (HttpRequestImpl) delegate;
+            }
+        }
+        if (req != null) {
+            req.initPathFromContext(context);
+        }
+        delegate.doFilter(request, response, new SimpleFilterChain(this));
+    }
+
+    public Filter getDelegate() {
+        return delegate;
+    }
+
+    private static class SimpleFilterChain implements FilterChain {
+        private final FilterListener origin;
+
+        private SimpleFilterChain(final FilterListener origin) {
+            this.origin = origin;
+        }
+
+        @Override
+        public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
+            final HttpListenerRegistry registry = SystemInstance.get().getComponent(HttpListenerRegistry.class);
+            registry.setOrigin(origin);
+            try {
+                registry.onMessage((HttpRequest) request, (HttpResponse) response);
+            } catch (Exception e) {
+                throw new ServletException(e);
+            } finally {
+                registry.setOrigin(origin);
+            }
+        }
+    }
+}

Modified: openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpListenerRegistry.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpListenerRegistry.java?rev=1408286&r1=1408285&r2=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpListenerRegistry.java (original)
+++ openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpListenerRegistry.java Mon Nov 12 13:50:17 2012
@@ -16,6 +16,8 @@
  */
 package org.apache.openejb.server.httpd;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -25,22 +27,52 @@ import java.util.Map;
  */
 public class HttpListenerRegistry implements HttpListener {
     private final Map<String, HttpListener> registry = new LinkedHashMap<String, HttpListener>();
+    private final Map<String, Collection<HttpListener>> filterRegistry = new LinkedHashMap<String, Collection<HttpListener>>();
+    private final ThreadLocal<FilterListener> currentFilterListener = new ThreadLocal<FilterListener>();
 
     public HttpListenerRegistry() {
     }
 
     public void onMessage(HttpRequest request, HttpResponse response) throws Exception {
-        Map<String, HttpListener> listeners;
-        synchronized (registry) {
-            listeners = new HashMap<String, HttpListener>(registry);
+        final String path = request.getURI().getPath();
+        final FilterListener currentFL = currentFilterListener.get();
+
+        // first look filters
+        Map<String, Collection<HttpListener>> filters;
+        synchronized (filterRegistry) {
+            filters = new HashMap<String, Collection<HttpListener>>(filterRegistry);
         }
 
-        String path = request.getURI().getPath();
-        for (Map.Entry<String, HttpListener> entry : listeners.entrySet()) {
-            String pattern = entry.getKey();
-            if (path.matches(pattern)) {
-                entry.getValue().onMessage(request, response);
-                break;
+        try {
+            boolean lastWasCurrent = false;
+            for (Map.Entry<String, Collection<HttpListener>> entry : filters.entrySet()) {
+                String pattern = entry.getKey();
+                for (HttpListener listener : entry.getValue()) {
+                    if ((lastWasCurrent || currentFL == null) && path.matches(pattern)) {
+                        listener.onMessage(request, response);
+                        return;
+                    }
+                    lastWasCurrent = listener == currentFL;
+                }
+            }
+
+
+            // then others
+            Map<String, HttpListener> listeners;
+            synchronized (registry) {
+                listeners = new HashMap<String, HttpListener>(registry);
+            }
+
+            for (Map.Entry<String, HttpListener> entry : listeners.entrySet()) {
+                String pattern = entry.getKey();
+                if (path.matches(pattern)) {
+                    entry.getValue().onMessage(request, response);
+                    break;
+                }
+            }
+        } finally {
+            if (currentFL == null) {
+                currentFilterListener.remove();
             }
         }
     }
@@ -58,4 +90,27 @@ public class HttpListenerRegistry implem
         }
         return listener;
     }
+
+    public void addHttpFilter(HttpListener listener, String regex) {
+        synchronized (filterRegistry) {
+            if (!filterRegistry.containsKey(regex)) {
+                filterRegistry.put(regex, new ArrayList<HttpListener>());
+            }
+            filterRegistry.get(regex).add(listener);
+        }
+    }
+
+    public Collection<HttpListener> removeHttpFilter(String regex) {
+        synchronized (filterRegistry) {
+            return filterRegistry.remove(regex);
+        }
+    }
+
+    public void setOrigin(final FilterListener origin) {
+        if (origin == null) {
+            currentFilterListener.remove();
+        } else {
+            currentFilterListener.set(origin);
+        }
+    }
 }

Modified: openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java?rev=1408286&r1=1408285&r2=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java (original)
+++ openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpRequestImpl.java Mon Nov 12 13:50:17 2012
@@ -962,4 +962,15 @@ public class HttpRequestImpl implements 
             return getRequestURI();
         }
     }
+
+    public void initPathFromContext(final String context) {
+        if (!"/".equals(path)) { // already done
+            return;
+        }
+
+        final String rawPath = requestRawPath();
+        if (context != null) {
+            setPath(rawPath.substring(1 + context.length(), rawPath.length())); // 1 because of the first /
+        }
+    }
 }
\ No newline at end of file

Modified: openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletListener.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletListener.java?rev=1408286&r1=1408285&r2=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletListener.java (original)
+++ openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletListener.java Mon Nov 12 13:50:17 2012
@@ -31,10 +31,7 @@ public class ServletListener implements 
     public void onMessage(final HttpRequest request, final HttpResponse response) throws Exception {
         if (request instanceof HttpRequestImpl) {
             final HttpRequestImpl req = (HttpRequestImpl) request;
-            final String rawPath = req.requestRawPath();
-            if (context != null) {
-                req.setPath(rawPath.substring(1 + context.length(), rawPath.length())); // 1 because of the first /
-            }
+            req.initPathFromContext(context);
         }
         delegate.service(request, response);
     }

Modified: openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletRequestAdapter.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletRequestAdapter.java?rev=1408286&r1=1408285&r2=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletRequestAdapter.java (original)
+++ openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/ServletRequestAdapter.java Mon Nov 12 13:50:17 2012
@@ -397,4 +397,7 @@ public class ServletRequestAdapter imple
         request.removeAttribute(s);
     }
 
+    public HttpServletRequest getRequest() {
+        return request;
+    }
 }

Modified: openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/util/HttpUtil.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/util/HttpUtil.java?rev=1408286&r1=1408285&r2=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/util/HttpUtil.java (original)
+++ openejb/trunk/openejb/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/util/HttpUtil.java Mon Nov 12 13:50:17 2012
@@ -19,10 +19,15 @@ package org.apache.openejb.server.httpd.
 import org.apache.openejb.OpenEJBRuntimeException;
 import org.apache.openejb.core.WebContext;
 import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.server.httpd.FilterListener;
+import org.apache.openejb.server.httpd.HttpListener;
 import org.apache.openejb.server.httpd.HttpListenerRegistry;
 import org.apache.openejb.server.httpd.ServletListener;
 
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
 import javax.servlet.Servlet;
+import java.util.Collection;
 import java.util.List;
 
 public final class HttpUtil {
@@ -83,6 +88,39 @@ public final class HttpUtil {
         wc.destroy(servlet);
     }
 
+    public static boolean addFilter(final String classname, final WebContext wc, final String mapping, final FilterConfig config) {
+        final HttpListenerRegistry registry = SystemInstance.get().getComponent(HttpListenerRegistry.class);
+        if (registry == null || mapping == null) {
+            return false;
+        }
+
+        final FilterListener listener;
+        try {
+            listener = new FilterListener((Filter) wc.newInstance(wc.getClassLoader().loadClass(classname)), wc.getContextRoot());
+            listener.getDelegate().init(config);
+        } catch (Exception e) {
+            throw new OpenEJBRuntimeException(e);
+        }
+
+        registry.addHttpFilter(listener, pattern(wc.getContextRoot(), mapping));
+        return true;
+    }
+
+    public static void removeFilter(final String mapping, final WebContext wc) {
+        final HttpListenerRegistry registry = SystemInstance.get().getComponent(HttpListenerRegistry.class);
+        if (registry == null || mapping == null) {
+            return;
+        }
+
+        final Collection<HttpListener> filters = registry.removeHttpFilter(pattern(wc.getContextRoot(), mapping));
+        for (HttpListener listener : filters) {
+            final Filter filter = ((FilterListener) listener).getDelegate();
+            filter.destroy();
+            wc.destroy(filter);
+        }
+        filters.clear();
+    }
+
     private static String pattern(final String contextRoot, final String mapping) {
         String path = "";
         if (contextRoot != null) {

Copied: openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/FilterRegistrationTest.java (from r1408118, openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ServletRegistrationTest.java)
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/FilterRegistrationTest.java?p2=openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/FilterRegistrationTest.java&p1=openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ServletRegistrationTest.java&r1=1408118&r2=1408286&rev=1408286&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ServletRegistrationTest.java (original)
+++ openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/FilterRegistrationTest.java Mon Nov 12 13:50:17 2012
@@ -25,85 +25,103 @@ import org.apache.openejb.loader.IO;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import javax.ejb.EJB;
-import javax.ejb.Singleton;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
-import javax.servlet.annotation.WebServlet;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 @EnableServices({ "httpejbd" })
 @RunWith(ApplicationComposer.class)
-public class ServletRegistrationTest {
+public class FilterRegistrationTest {
     @Module
-    @Classes({ TestServlet.class, TestServlet2.class, TestServlet3.class, TestServlet4.class, SomeEjb.class })
     public WebApp app() {
         return new WebApp()
-                .contextRoot("servlet")
-                .addServlet("test", TestServlet.class.getName(), "/touch");
+                .contextRoot("filter")
+                .addServlet("test", TestServlet.class.getName(), "/touch")
+                .addFilter("filter", TestFilter.class.getName(), "/touch")
+                .addFilter("filter2", TestFilter2.class.getName(), "/touch");
     }
 
     @Test
     public void touch() throws IOException {
-        assertEquals("touched", IO.slurp(new URL("http://localhost:4204/servlet/touch")));
-    }
-
-    @Test
-    public void discover() throws IOException {
-        assertEquals("discovered", IO.slurp(new URL("http://localhost:4204/servlet/discover")));
-    }
-
-    @Test
-    public void wildcard() throws IOException {
-        assertEquals("wildcard", IO.slurp(new URL("http://localhost:4204/servlet/bar/openejb")));
-    }
-
-    @Test
-    public void injections() throws IOException {
-        assertEquals("true", IO.slurp(new URL("http://localhost:4204/servlet/injection")));
+        assertEquals("http://ok/filter/touch", IO.slurp(new URL("http://localhost:4204/filter/touch")));
+        assertTrue(TestFilter.init);
+        assertTrue(TestFilter.ok);
+        assertTrue(TestFilter2.ok);
     }
 
     private static class TestServlet extends HttpServlet {
         @Override
         protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
-            resp.getWriter().write("touched");
+            resp.getWriter().write(req.getRequestURI());
         }
     }
 
-    @WebServlet(urlPatterns = "/discover")
-    private static class TestServlet2 extends HttpServlet {
+    private static class TestFilter implements Filter {
+        public static boolean ok = false;
+        private static boolean init = false;
+
         @Override
-        protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
-            resp.getWriter().write("discovered");
+        public void init(final FilterConfig filterConfig) throws ServletException {
+            init = true;
         }
-    }
 
-    @WebServlet(urlPatterns = "/bar/*")
-    private static class TestServlet3 extends HttpServlet {
         @Override
-        protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
-            resp.getWriter().write("wildcard");
+        public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
+            ok = true;
+            try {
+                chain.doFilter(new HttpRequestImpl(new URI("http://ok/filter/touch")) {
+                    @Override
+                    public java.net.URI getURI() {
+                        return super.getSocketURI();
+                    }
+
+                    @Override
+                    public String getMethod() {
+                        return "GET";
+                    }
+
+                }, response);
+            } catch (URISyntaxException e) {
+                throw new ServletException(e);
+            }
+        }
+
+        @Override
+        public void destroy() {
+            System.out.println("destroyed");
         }
     }
 
-    @WebServlet(urlPatterns = "/injection")
-    private static class TestServlet4 extends HttpServlet {
-        @EJB
-        private SomeEjb ejb;
+    private static class TestFilter2 implements Filter {
+        public static boolean ok = false;
 
         @Override
-        protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
-            resp.getWriter().write(Boolean.toString(ejb != null));
+        public void init(final FilterConfig filterConfig) throws ServletException {
+            // no-op
         }
-    }
 
-    @Singleton
-    public static class SomeEjb {
+        @Override
+        public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
+            ok = true;
+            chain.doFilter(request, response);
+        }
 
+        @Override
+        public void destroy() {
+            // no-op
+        }
     }
 }

Added: openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ServletContextListenerRegistrationTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ServletContextListenerRegistrationTest.java?rev=1408286&view=auto
==============================================================================
--- openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ServletContextListenerRegistrationTest.java (added)
+++ openejb/trunk/openejb/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ServletContextListenerRegistrationTest.java Mon Nov 12 13:50:17 2012
@@ -0,0 +1,60 @@
+/*
+ * 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.server.httpd;
+
+import org.apache.openejb.jee.WebApp;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.junit.EnableServices;
+import org.apache.openejb.junit.Module;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import java.io.IOException;
+
+import static org.junit.Assert.assertTrue;
+
+@EnableServices({ "httpejbd" })
+@RunWith(ApplicationComposer.class)
+public class ServletContextListenerRegistrationTest {
+    @Module
+    public WebApp app() {
+        return new WebApp()
+                .contextRoot("init")
+                .addListener(Initializer.class.getName());
+    }
+
+    @Test
+    public void check() throws IOException {
+        assertTrue(Initializer.init);
+    }
+
+    private static class Initializer implements ServletContextListener {
+        private static boolean init = false;
+
+        @Override
+        public void contextInitialized(ServletContextEvent sce) {
+            init = sce != null;
+        }
+
+        @Override
+        public void contextDestroyed(ServletContextEvent sce) {
+            System.out.println("destroyed");
+        }
+    }
+}