FELIX-4060 : Implement HTTP Whiteboard Service (RFC-189). Move handler registration to own registry class.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1681425 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
index 2fcdae4..888efe1 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
@@ -34,7 +34,7 @@
  * The filter handler handles the initialization and destruction of filter
  * objects.
  */
-public class FilterHandler implements Comparable<FilterHandler>
+public abstract class FilterHandler implements Comparable<FilterHandler>
 {
     private final long contextServiceId;
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java
new file mode 100644
index 0000000..a93a84b
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ListenerHandler.java
@@ -0,0 +1,144 @@
+/*
+ * 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.felix.http.base.internal.handler;
+
+import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.runtime.ListenerInfo;
+import org.osgi.service.http.runtime.dto.DTOConstants;
+
+/**
+ * The listener handler handles the initialization and destruction of listener
+ * objects.
+ */
+public abstract class ListenerHandler<T> implements Comparable<ListenerHandler<T>>
+{
+    private final long contextServiceId;
+
+    private final ListenerInfo<T> listenerInfo;
+
+    private final ExtServletContext context;
+
+    private T listener;
+
+    protected volatile int useCount;
+
+    public ListenerHandler(final long contextServiceId,
+            final ExtServletContext context,
+            final ListenerInfo<T> listenerInfo)
+    {
+        this.contextServiceId = contextServiceId;
+        this.context = context;
+        this.listenerInfo = listenerInfo;
+    }
+
+    @Override
+    public int compareTo(final ListenerHandler<T> other)
+    {
+        return this.listenerInfo.compareTo(other.listenerInfo);
+    }
+
+    public ExtServletContext getContext()
+    {
+        return this.context;
+    }
+
+    public long getContextServiceId()
+    {
+        return this.contextServiceId;
+    }
+
+    public T getListener()
+    {
+        return listener;
+    }
+
+    protected void setListener(final T f)
+    {
+        this.listener = f;
+    }
+
+    public ListenerInfo<T> getListenerInfo()
+    {
+        return this.listenerInfo;
+    }
+
+    /**
+     * Initialize the object
+     * @return {code -1} on success, a failure reason according to {@link DTOConstants} otherwise.
+     */
+    public int init()
+    {
+        if ( this.useCount > 0 )
+        {
+            this.useCount++;
+            return -1;
+        }
+
+        if (this.listener == null)
+        {
+            return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+        }
+
+        this.useCount++;
+        return -1;
+    }
+
+    public boolean destroy()
+    {
+        if (this.listener == null)
+        {
+            return false;
+        }
+
+        this.useCount--;
+        if ( this.useCount == 0 )
+        {
+
+            listener = null;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean dispose()
+    {
+        // fully destroy the listener
+        this.useCount = 1;
+        return this.destroy();
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return 31 + listenerInfo.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        final ListenerHandler<T> other = (ListenerHandler<T>) obj;
+        return listenerInfo.equals(other.listenerInfo);
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardListenerHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardListenerHandler.java
new file mode 100644
index 0000000..b17210a
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/WhiteboardListenerHandler.java
@@ -0,0 +1,86 @@
+/*
+ * 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.felix.http.base.internal.handler;
+
+import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.runtime.ListenerInfo;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Listener handler for listeners registered through the http whiteboard.
+ */
+public final class WhiteboardListenerHandler<T> extends ListenerHandler<T>
+{
+    private final BundleContext bundleContext;
+
+    public WhiteboardListenerHandler(final long contextServiceId,
+            final ExtServletContext context,
+            final ListenerInfo<T> listenerInfo,
+            final BundleContext bundleContext)
+    {
+        super(contextServiceId, context, listenerInfo);
+        this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public int init()
+    {
+        if ( this.useCount > 0 )
+        {
+            this.useCount++;
+            return -1;
+        }
+
+        final ServiceReference<T> serviceReference = getListenerInfo().getServiceReference();
+        final ServiceObjects<T> so = this.bundleContext.getServiceObjects(serviceReference);
+
+        this.setListener((so == null ? null : so.getService()));
+
+        final int reason = super.init();
+        if ( reason != -1 )
+        {
+            if ( so != null )
+            {
+                so.ungetService(this.getListener());
+            }
+            this.setListener(null);
+        }
+        return reason;
+    }
+
+    @Override
+    public boolean destroy()
+    {
+        final T s = this.getListener();
+        if ( s != null )
+        {
+            if ( super.destroy() )
+            {
+
+                final ServiceObjects<T> so = this.bundleContext.getServiceObjects(getListenerInfo().getServiceReference());
+                if (so != null)
+                {
+                    so.ungetService(s);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
index dfcf458..cd47a05 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
@@ -253,6 +253,12 @@
         }
     }
 
+    public synchronized void cleanup()
+    {
+        this.errorMapping.clear();
+        this.status = Collections.emptyList();
+    }
+
     private void addErrorHandling(final ServletHandler handler, final ErrorRegistrationStatus status, final long code, final String exception)
     {
         final String key = (exception != null ? exception : String.valueOf(code));
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
index c921a58..392ba71 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
@@ -16,13 +16,10 @@
  */
 package org.apache.felix.http.base.internal.registry;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.annotation.Nonnull;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletContextAttributeEvent;
 import javax.servlet.ServletContextAttributeListener;
 import javax.servlet.ServletContextEvent;
@@ -37,19 +34,16 @@
 import javax.servlet.http.HttpSessionIdListener;
 import javax.servlet.http.HttpSessionListener;
 
+import org.apache.felix.http.base.internal.handler.ListenerHandler;
 import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.HttpSessionIdListenerInfo;
 import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletRequestAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletRequestListenerInfo;
-import org.apache.felix.http.base.internal.runtime.dto.ListenerDTOBuilder;
-import org.apache.felix.http.base.internal.util.CollectionUtils;
-import org.apache.felix.http.base.internal.whiteboard.ContextHandler;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.runtime.dto.DTOConstants;
+import org.osgi.service.http.runtime.dto.FailedListenerDTO;
 import org.osgi.service.http.runtime.dto.ListenerDTO;
 import org.osgi.service.http.runtime.dto.ServletContextDTO;
 
@@ -65,87 +59,65 @@
         ServletRequestAttributeListener
 {
     /** Servlet context listeners. */
-    private final Map<ServiceReference<ServletContextListener>, ServletContextListener> contextListeners = new ConcurrentSkipListMap<ServiceReference<ServletContextListener>, ServletContextListener>();
+    private final ListenerMap<ServletContextListener> contextListeners = new ListenerMap<ServletContextListener>();
 
     /** Servlet context attribute listeners. */
-    private final Map<ServiceReference<ServletContextAttributeListener>, ServletContextAttributeListener> contextAttributeListeners = new ConcurrentSkipListMap<ServiceReference<ServletContextAttributeListener>, ServletContextAttributeListener>();
+    private final ListenerMap<ServletContextAttributeListener> contextAttributeListeners = new ListenerMap<ServletContextAttributeListener>();
 
     /** Session attribute listeners. */
-    private final Map<ServiceReference<HttpSessionAttributeListener>, HttpSessionAttributeListener> sessionAttributeListeners = new ConcurrentSkipListMap<ServiceReference<HttpSessionAttributeListener>, HttpSessionAttributeListener>();
+    private final ListenerMap<HttpSessionAttributeListener> sessionAttributeListeners = new ListenerMap<HttpSessionAttributeListener>();
 
     /** Session listeners. */
-    private final Map<ServiceReference<HttpSessionListener>, HttpSessionListener> sessionListeners = new ConcurrentSkipListMap<ServiceReference<HttpSessionListener>, HttpSessionListener>();
+    private final ListenerMap<HttpSessionListener> sessionListeners = new ListenerMap<HttpSessionListener>();
 
     /** Session id listeners. */
-    private final Map<ServiceReference<HttpSessionIdListener>, HttpSessionIdListener> sessionIdListeners = new ConcurrentSkipListMap<ServiceReference<HttpSessionIdListener>, HttpSessionIdListener>();
+    private final ListenerMap<HttpSessionIdListener> sessionIdListeners = new ListenerMap<HttpSessionIdListener>();
 
     /** Request listeners. */
-    private final Map<ServiceReference<ServletRequestListener>, ServletRequestListener> requestListeners = new ConcurrentSkipListMap<ServiceReference<ServletRequestListener>, ServletRequestListener>();
+    private final ListenerMap<ServletRequestListener> requestListeners = new ListenerMap<ServletRequestListener>();
 
     /** Request attribute listeners. */
-    private final Map<ServiceReference<ServletRequestAttributeListener>, ServletRequestAttributeListener> requestAttributeListeners = new ConcurrentSkipListMap<ServiceReference<ServletRequestAttributeListener>, ServletRequestAttributeListener>();
+    private final ListenerMap<ServletRequestAttributeListener> requestAttributeListeners = new ListenerMap<ServletRequestAttributeListener>();
 
-    private final Bundle bundle;
-
-    public EventListenerRegistry(final Bundle bundle)
+    public synchronized void cleanup()
     {
-        this.bundle = bundle;
+        this.contextListeners.cleanup();
+        this.contextAttributeListeners.cleanup();
+        this.sessionAttributeListeners.cleanup();
+        this.sessionListeners.cleanup();
+        this.sessionIdListeners.cleanup();
+        this.requestListeners.cleanup();
+        this.requestAttributeListeners.cleanup();
     }
 
-    public int initialized(@Nonnull final ServletContextListenerInfo listenerInfo, @Nonnull final ContextHandler contextHandler)
+    /**
+     * Add servlet context listener
+     *
+     * @param handler
+     */
+    public void addServletContextListener(@Nonnull final ListenerHandler<ServletContextListener> handler)
     {
-        final ServletContextListener listener = listenerInfo.getService(bundle);
-        if (listener != null)
-        {
-            final ServletContext context = contextHandler
-                    .getServletContext(listenerInfo.getServiceReference()
-                            .getBundle());
-            if ( context != null )
-            {
-                this.contextListeners.put(listenerInfo.getServiceReference(), listener);
-
-                listener.contextInitialized(new ServletContextEvent(context));
-                return -1;
-            }
-            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
-        }
-        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+        this.contextListeners.add(handler);
     }
 
-    public void destroyed(@Nonnull final ServletContextListenerInfo listenerInfo, @Nonnull final ContextHandler contextHandler)
+    /**
+     * Remove servlet context listener
+     *
+     * @param info
+     */
+    public void removeServletContextListener(@Nonnull final ServletContextListenerInfo info)
     {
-        final ServiceReference<ServletContextListener> listenerRef = listenerInfo
-                .getServiceReference();
-        final ServletContextListener listener = this.contextListeners
-                .remove(listenerRef);
-        if (listener != null)
-        {
-            final ServletContext context = contextHandler
-                    .getServletContext(listenerRef.getBundle());
-            listener.contextDestroyed(new ServletContextEvent(context));
-            // call unget twice, once for the call in initialized and once for
-            // the call in this method(!)
-            contextHandler.ungetServletContext(listenerRef.getBundle());
-            contextHandler.ungetServletContext(listenerRef.getBundle());
-            listenerInfo.ungetService(bundle, listener);
-        }
+        this.contextListeners.remove(info);
     }
 
     /**
      * Add servlet context attribute listener
      *
-     * @param info
+     * @param handler
      */
-    public int addListener(@Nonnull final ServletContextAttributeListenerInfo info)
+    public void addServletContextAttributeListener(@Nonnull final ListenerHandler<ServletContextAttributeListener> handler)
     {
-        final ServletContextAttributeListener service = info.getService(bundle);
-        if (service != null)
-        {
-            this.contextAttributeListeners.put(info.getServiceReference(),
-                    service);
-            return -1;
-        }
-        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+        this.contextAttributeListeners.add(handler);
     }
 
     /**
@@ -153,31 +125,19 @@
      *
      * @param info
      */
-    public void removeListener(@Nonnull final ServletContextAttributeListenerInfo info)
+    public void removeServletContextAttributeListener(@Nonnull final ServletContextAttributeListenerInfo info)
     {
-        final ServletContextAttributeListener service = this.contextAttributeListeners
-                .remove(info.getServiceReference());
-        if (service != null)
-        {
-            info.ungetService(bundle, service);
-        }
+        this.contextAttributeListeners.remove(info);
     }
 
     /**
      * Add session attribute listener
      *
-     * @param info
+     * @param handler
      */
-    public int addListener(@Nonnull final HttpSessionAttributeListenerInfo info)
+    public void addSessionAttributeListener(@Nonnull final ListenerHandler<HttpSessionAttributeListener> handler)
     {
-        final HttpSessionAttributeListener service = info.getService(bundle);
-        if (service != null)
-        {
-            this.sessionAttributeListeners.put(info.getServiceReference(),
-                    service);
-            return -1;
-        }
-        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+        this.sessionAttributeListeners.add(handler);
     }
 
     /**
@@ -185,30 +145,19 @@
      *
      * @param info
      */
-    public void removeListener(@Nonnull final HttpSessionAttributeListenerInfo info)
+    public void removeSessionAttributeListener(@Nonnull final HttpSessionAttributeListenerInfo info)
     {
-        final HttpSessionAttributeListener service = this.sessionAttributeListeners
-                .remove(info.getServiceReference());
-        if (service != null)
-        {
-            info.ungetService(bundle, service);
-        }
+        this.sessionAttributeListeners.remove(info);
     }
 
     /**
      * Add session listener
      *
-     * @param info
+     * @param handler
      */
-    public int addListener(@Nonnull final HttpSessionListenerInfo info)
+    public void addSessionListener(@Nonnull final ListenerHandler<HttpSessionListener> handler)
     {
-        final HttpSessionListener service = info.getService(bundle);
-        if (service != null)
-        {
-            this.sessionListeners.put(info.getServiceReference(), service);
-            return -1;
-        }
-        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+        this.sessionListeners.add(handler);
     }
 
     /**
@@ -216,31 +165,19 @@
      *
      * @param info
      */
-    public void removeListener(@Nonnull final HttpSessionListenerInfo info)
+    public void removeSessionListener(@Nonnull final HttpSessionListenerInfo info)
     {
-        final HttpSessionListener service = this.sessionListeners.remove(info
-                .getServiceReference());
-        if (service != null)
-        {
-            info.ungetService(bundle, service);
-        }
+        this.sessionListeners.remove(info);
     }
 
     /**
      * Add session id listener
      *
-     * @param info
+     * @param handler
      */
-    public  int addListener(@Nonnull final HttpSessionIdListenerInfo info)
+    public void addSessionIdListener(@Nonnull final ListenerHandler<HttpSessionIdListener> handler)
     {
-        final HttpSessionIdListener service = info.getService(bundle);
-        if (service != null)
-        {
-            this.sessionIdListeners.put(info.getServiceReference(),
-                    service);
-            return -1;
-        }
-        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+        this.sessionIdListeners.add(handler);
     }
 
     /**
@@ -248,29 +185,19 @@
      *
      * @param info
      */
-    public void removeListener(@Nonnull final HttpSessionIdListenerInfo info)
+    public void removeSessionIdListener(@Nonnull final HttpSessionIdListenerInfo info)
     {
-        final HttpSessionIdListener service = this.sessionIdListeners.remove(info.getServiceReference());
-        if (service != null)
-        {
-            info.ungetService(bundle, service);
-        }
+        this.sessionIdListeners.remove(info);
     }
 
     /**
      * Add request listener
      *
-     * @param info
+     * @param handler
      */
-    public int addListener(@Nonnull final ServletRequestListenerInfo info)
+    public void addServletRequestListener(@Nonnull final ListenerHandler<ServletRequestListener> handler)
     {
-        final ServletRequestListener service = info.getService(bundle);
-        if (service != null)
-        {
-            this.requestListeners.put(info.getServiceReference(), service);
-            return -1;
-        }
-        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+        this.requestListeners.add(handler);
     }
 
     /**
@@ -278,31 +205,19 @@
      *
      * @param info
      */
-    public void removeListener(@Nonnull final ServletRequestListenerInfo info)
+    public void removeServletRequestListener(@Nonnull final ServletRequestListenerInfo info)
     {
-        final ServletRequestListener service = this.requestListeners
-                .remove(info.getServiceReference());
-        if (service != null)
-        {
-            info.ungetService(bundle, service);
-        }
+        this.requestListeners.remove(info);
     }
 
     /**
      * Add request attribute listener
      *
-     * @param info
+     * @param handler
      */
-    public int addListener(@Nonnull final ServletRequestAttributeListenerInfo info)
+    public void addServletRequestAttributeListener(@Nonnull final ListenerHandler<ServletRequestAttributeListener> handler)
     {
-        final ServletRequestAttributeListener service = info.getService(bundle);
-        if (service != null)
-        {
-            this.requestAttributeListeners.put(info.getServiceReference(),
-                    service);
-            return -1;
-        }
-        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+        this.requestAttributeListeners.add(handler);
     }
 
     /**
@@ -310,21 +225,42 @@
      *
      * @param info
      */
-    public void removeListener(@Nonnull final ServletRequestAttributeListenerInfo info)
+    public void removeServletRequestAttributeListener(@Nonnull final ServletRequestAttributeListenerInfo info)
     {
-        final ServletRequestAttributeListener service = this.requestAttributeListeners
-                .remove(info.getServiceReference());
-        if (service != null)
+        this.requestAttributeListeners.remove(info);
+    }
+
+    public ListenerHandler<ServletContextListener> getServletContextListener(@Nonnull final ListenerInfo<ServletContextListener> info)
+    {
+        return this.contextListeners.getListenerHandler(info);
+    }
+
+    public void contextInitialized() {
+        for (final ListenerHandler<ServletContextListener> l : contextListeners.getActiveHandlers())
         {
-            info.ungetService(bundle, service);
+            final ServletContextListener listener = l.getListener();
+            if ( listener != null )
+            {
+                listener.contextInitialized(new ServletContextEvent(l.getContext()));
+            }
+        }
+    }
+
+    public void contextDestroyed() {
+        for (final ListenerHandler<ServletContextListener> l : contextListeners.getActiveHandlers())
+        {
+            final ServletContextListener listener = l.getListener();
+            if ( listener != null )
+            {
+                listener.contextDestroyed(new ServletContextEvent(l.getContext()));
+            }
         }
     }
 
     @Override
     public void attributeReplaced(final HttpSessionBindingEvent event)
     {
-        for (final HttpSessionAttributeListener l : sessionAttributeListeners
-                .values())
+        for (final HttpSessionAttributeListener l : sessionAttributeListeners.getActiveListeners())
         {
             l.attributeReplaced(event);
         }
@@ -333,8 +269,7 @@
     @Override
     public void attributeRemoved(final HttpSessionBindingEvent event)
     {
-        for (final HttpSessionAttributeListener l : sessionAttributeListeners
-                .values())
+        for (final HttpSessionAttributeListener l : sessionAttributeListeners.getActiveListeners())
         {
             l.attributeReplaced(event);
         }
@@ -343,8 +278,7 @@
     @Override
     public void attributeAdded(final HttpSessionBindingEvent event)
     {
-        for (final HttpSessionAttributeListener l : sessionAttributeListeners
-                .values())
+        for (final HttpSessionAttributeListener l : sessionAttributeListeners.getActiveListeners())
         {
             l.attributeReplaced(event);
         }
@@ -353,8 +287,7 @@
     @Override
     public void attributeReplaced(final ServletContextAttributeEvent event)
     {
-        for (final ServletContextAttributeListener l : contextAttributeListeners
-                .values())
+        for (final ServletContextAttributeListener l : contextAttributeListeners.getActiveListeners())
         {
             l.attributeReplaced(event);
         }
@@ -363,8 +296,7 @@
     @Override
     public void attributeRemoved(final ServletContextAttributeEvent event)
     {
-        for (final ServletContextAttributeListener l : contextAttributeListeners
-                .values())
+        for (final ServletContextAttributeListener l : contextAttributeListeners.getActiveListeners())
         {
             l.attributeReplaced(event);
         }
@@ -373,8 +305,7 @@
     @Override
     public void attributeAdded(final ServletContextAttributeEvent event)
     {
-        for (final ServletContextAttributeListener l : contextAttributeListeners
-                .values())
+        for (final ServletContextAttributeListener l : contextAttributeListeners.getActiveListeners())
         {
             l.attributeReplaced(event);
         }
@@ -383,7 +314,7 @@
     @Override
     public void sessionCreated(final HttpSessionEvent se)
     {
-        for (final HttpSessionListener l : sessionListeners.values())
+        for (final HttpSessionListener l : sessionListeners.getActiveListeners())
         {
             l.sessionCreated(se);
         }
@@ -392,7 +323,7 @@
     @Override
     public void sessionDestroyed(final HttpSessionEvent se)
     {
-        for (final HttpSessionListener l : sessionListeners.values())
+        for (final HttpSessionListener l : sessionListeners.getActiveListeners())
         {
             l.sessionDestroyed(se);
         }
@@ -401,7 +332,7 @@
     @Override
     public void requestDestroyed(final ServletRequestEvent sre)
     {
-        for (final ServletRequestListener l : requestListeners.values())
+        for (final ServletRequestListener l : requestListeners.getActiveListeners())
         {
             l.requestDestroyed(sre);
         }
@@ -410,7 +341,7 @@
     @Override
     public void requestInitialized(final ServletRequestEvent sre)
     {
-        for (final ServletRequestListener l : requestListeners.values())
+        for (final ServletRequestListener l : requestListeners.getActiveListeners())
         {
             l.requestInitialized(sre);
         }
@@ -419,8 +350,7 @@
     @Override
     public void attributeAdded(final ServletRequestAttributeEvent srae)
     {
-        for (final ServletRequestAttributeListener l : requestAttributeListeners
-                .values())
+        for (final ServletRequestAttributeListener l : requestAttributeListeners.getActiveListeners())
         {
             l.attributeAdded(srae);
         }
@@ -429,8 +359,7 @@
     @Override
     public void attributeRemoved(final ServletRequestAttributeEvent srae)
     {
-        for (final ServletRequestAttributeListener l : requestAttributeListeners
-                .values())
+        for (final ServletRequestAttributeListener l : requestAttributeListeners.getActiveListeners())
         {
             l.attributeRemoved(srae);
         }
@@ -439,8 +368,7 @@
     @Override
     public void attributeReplaced(final ServletRequestAttributeEvent srae)
     {
-        for (final ServletRequestAttributeListener l : requestAttributeListeners
-                .values())
+        for (final ServletRequestAttributeListener l : requestAttributeListeners.getActiveListeners())
         {
             l.attributeReplaced(srae);
         }
@@ -451,29 +379,26 @@
      */
     @Override
     public void sessionIdChanged(@Nonnull final HttpSessionEvent event, @Nonnull final String oldSessionId) {
-        for (final HttpSessionIdListener l : sessionIdListeners.values())
+        for (final HttpSessionIdListener l : sessionIdListeners.getActiveListeners())
         {
             l.sessionIdChanged(event, oldSessionId);
         }
     }
 
-    @SuppressWarnings("unchecked")
-    public void getRuntime(final ServletContextDTO dto)
+    public void getRuntimeInfo(final ServletContextDTO dto, final List<FailedListenerDTO> failedListenerDTOs)
     {
-        final Collection<ServiceReference<?>> col = CollectionUtils.<ServiceReference<?>>sortedUnion(
-                Collections.<ServiceReference<?>>reverseOrder(),
-                contextListeners.keySet(),
-                contextAttributeListeners.keySet(),
-                sessionAttributeListeners.keySet(),
-                sessionIdListeners.keySet(),
-                sessionListeners.keySet(),
-                requestAttributeListeners.keySet(),
-                requestListeners.keySet());
-        dto.listenerDTOs = new ListenerDTO[col.size()];
-        int index = 0;
-        for(final ServiceReference<?> ref : col)
+        final List<ListenerDTO> listenerDTOs = new ArrayList<ListenerDTO>();
+        this.contextListeners.getRuntimeInfo(listenerDTOs, failedListenerDTOs);
+        this.contextAttributeListeners.getRuntimeInfo(listenerDTOs, failedListenerDTOs);
+        this.requestListeners.getRuntimeInfo(listenerDTOs, failedListenerDTOs);
+        this.requestAttributeListeners.getRuntimeInfo(listenerDTOs, failedListenerDTOs);
+        this.sessionListeners.getRuntimeInfo(listenerDTOs, failedListenerDTOs);
+        this.sessionAttributeListeners.getRuntimeInfo(listenerDTOs, failedListenerDTOs);
+        this.sessionIdListeners.getRuntimeInfo(listenerDTOs, failedListenerDTOs);
+
+        if ( listenerDTOs.size() > 0 )
         {
-            dto.listenerDTOs[index++] = ListenerDTOBuilder.build(ref, dto.serviceId);
+            dto.listenerDTOs = listenerDTOs.toArray(new ListenerDTO[listenerDTOs.size()]);
         }
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
index 81acbae6..ad0695e 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
@@ -159,6 +159,11 @@
         }
     }
 
+    public synchronized void cleanup()
+    {
+        this.filters = Collections.emptyList();
+    }
+
     /**
      * Get all filters handling the request.
      * Filters are applied to the url and/or the servlet
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/HandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/HandlerRegistry.java
index f1c01d5..a3fd974 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/HandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/HandlerRegistry.java
@@ -74,18 +74,6 @@
     }
 
     /**
-     * Add a context registration.
-     * @param info The servlet context helper info
-     */
-    public void add(@Nonnull ServletContextHelperInfo info)
-    {
-        synchronized ( this )
-        {
-            this.add(new PerContextHandlerRegistry(info));
-        }
-    }
-
-    /**
      * Remove a context registration.
      * @param info The servlet context helper info
      */
@@ -112,7 +100,7 @@
     /**
      * Add a new context registration.
      */
-    private void add(@Nonnull PerContextHandlerRegistry registry)
+    public void add(@Nonnull PerContextHandlerRegistry registry)
     {
         synchronized ( this )
         {
@@ -277,7 +265,7 @@
         return null;
     }
 
-    public boolean getRuntime(final ServletContextDTO dto,
+    public boolean getRuntimeInfo(final ServletContextDTO dto,
             final FailedDTOHolder failedDTOHolder)
     {
         final PerContextHandlerRegistry reg = this.getRegistry(dto.serviceId);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ListenerMap.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ListenerMap.java
new file mode 100644
index 0000000..fdbc4f0
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ListenerMap.java
@@ -0,0 +1,301 @@
+/*
+ * 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.felix.http.base.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.annotation.Nonnull;
+
+import org.apache.felix.http.base.internal.handler.ListenerHandler;
+import org.apache.felix.http.base.internal.runtime.ListenerInfo;
+import org.apache.felix.http.base.internal.runtime.dto.ListenerDTOBuilder;
+import org.osgi.service.http.runtime.dto.FailedListenerDTO;
+import org.osgi.service.http.runtime.dto.ListenerDTO;
+
+public class ListenerMap<T> {
+
+    private volatile List<ListenerRegistrationStatus<T>> handlers = Collections.emptyList();
+
+    /**
+     * The status object keeps track of the registration status of a listener
+     * The status objects are sorted by result first, followed by ranking. The active
+     * listeners ( result == -1) are first, followed by the inactive ones. This sorting
+     * allows to only traverse over the active ones and also avoids any sorting
+     * as the listeners are processed in the correct order already.
+     */
+    private static final class ListenerRegistrationStatus<T> implements Comparable<ListenerRegistrationStatus<T>>
+    {
+        private final int result;
+        private final ListenerHandler<T> handler;
+
+        public ListenerRegistrationStatus(@Nonnull final ListenerHandler<T> handler, final int result)
+        {
+            this.handler = handler;
+            this.result = result;
+        }
+
+        public int getResult()
+        {
+            return this.result;
+        }
+
+        public @Nonnull ListenerHandler<T> getHandler()
+        {
+            return this.handler;
+        }
+
+        @Override
+        public int compareTo(final ListenerRegistrationStatus<T> o)
+        {
+            int result = this.result - o.result;
+            if ( result == 0 )
+            {
+                result = this.handler.compareTo(o.handler);
+            }
+            return result;
+        }
+    }
+
+    public void cleanup()
+    {
+        this.handlers = Collections.emptyList();
+    }
+
+    public synchronized void add(final ListenerHandler<T> handler)
+    {
+        final int reason = handler.init();
+        final ListenerRegistrationStatus<T> status = new ListenerRegistrationStatus<T>(handler, reason);
+
+        final List<ListenerRegistrationStatus<T>> newList = new ArrayList<ListenerMap.ListenerRegistrationStatus<T>>(this.handlers);
+        newList.add(status);
+        Collections.sort(newList);
+        this.handlers = newList;
+    }
+
+    public synchronized void remove(final ListenerInfo<T> info)
+    {
+        final List<ListenerRegistrationStatus<T>> newList = new ArrayList<ListenerMap.ListenerRegistrationStatus<T>>(this.handlers);
+        final Iterator<ListenerRegistrationStatus<T>> i = newList.iterator();
+        while ( i.hasNext() )
+        {
+            final ListenerRegistrationStatus<T> status = i.next();
+            if ( status.getHandler().getListenerInfo().equals(info) )
+            {
+                if ( status.getResult() == - 1 )
+                {
+                    status.getHandler().destroy();
+                }
+                i.remove();
+                this.handlers = newList;
+                break;
+            }
+        }
+    }
+
+    public ListenerHandler<T> getListenerHandler(@Nonnull final ListenerInfo<T> info)
+    {
+        final List<ListenerRegistrationStatus<T>> list = this.handlers;
+        for(final ListenerRegistrationStatus<T> status : list)
+        {
+            if ( status.getHandler().getListenerInfo().equals(info) )
+            {
+                return status.getHandler();
+            }
+        }
+        return null;
+    }
+
+    public Iterable<ListenerHandler<T>> getActiveHandlers()
+    {
+        final List<ListenerRegistrationStatus<T>> list = this.handlers;
+        final Iterator<ListenerRegistrationStatus<T>> iter = list.iterator();
+        final Iterator<ListenerHandler<T>> newIter = new Iterator<ListenerHandler<T>>()
+        {
+
+            private ListenerHandler<T> next;
+
+            {
+                peek();
+            }
+
+            private void peek()
+            {
+                next = null;
+                if ( iter.hasNext() )
+                {
+                    final ListenerRegistrationStatus<T> status = iter.next();
+                    if ( status.getResult() == -1 )
+                    {
+                        next = status.getHandler();
+                    }
+                }
+            }
+
+            @Override
+            public boolean hasNext()
+            {
+                return this.next != null;
+            }
+
+            @Override
+            public ListenerHandler<T> next()
+            {
+                if ( this.next == null )
+                {
+                    throw new NoSuchElementException();
+                }
+                final ListenerHandler<T> result = this.next;
+                peek();
+                return result;
+            }
+
+            @Override
+            public void remove()
+            {
+                throw new UnsupportedOperationException();
+            }
+        };
+        return new Iterable<ListenerHandler<T>>()
+        {
+
+            @Override
+            public Iterator<ListenerHandler<T>> iterator()
+            {
+                return newIter;
+            }
+        };
+    }
+
+    public Iterable<T> getActiveListeners()
+    {
+        final Iterator<ListenerHandler<T>> iter = this.getActiveHandlers().iterator();
+        final Iterator<T> newIter = new Iterator<T>()
+        {
+
+            private T next;
+
+            {
+                peek();
+            }
+
+            private void peek()
+            {
+                next = null;
+                while ( next == null && iter.hasNext() )
+                {
+                    final ListenerHandler<T> handler = iter.next();
+                    next = handler.getListener();
+                }
+            }
+
+            @Override
+            public boolean hasNext()
+            {
+                return this.next != null;
+            }
+
+            @Override
+            public T next()
+            {
+                if ( this.next == null )
+                {
+                    throw new NoSuchElementException();
+                }
+                final T result = this.next;
+                peek();
+                return result;
+            }
+
+            @Override
+            public void remove()
+            {
+                throw new UnsupportedOperationException();
+            }
+        };
+        return new Iterable<T>()
+        {
+
+            @Override
+            public Iterator<T> iterator()
+            {
+                return newIter;
+            }
+        };
+    }
+
+    public void getRuntimeInfo(final List<ListenerDTO> listenerDTOs, final List<FailedListenerDTO> failedListenerDTOs)
+    {
+        final int length = listenerDTOs.size();
+        final int failedLength = failedListenerDTOs.size();
+        final List<ListenerRegistrationStatus<T>> list = this.handlers;
+        for (final ListenerRegistrationStatus<T> status : list)
+        {
+            // search for DTO with same service id and failureCode
+            if ( status.getResult() == -1 )
+            {
+                int index = 0;
+                boolean found = false;
+                final Iterator<ListenerDTO> i = listenerDTOs.iterator();
+                while ( !found && index < length )
+                {
+                    final ListenerDTO dto = i.next();
+                    if ( dto.serviceId == status.getHandler().getListenerInfo().getServiceId() )
+                    {
+                        found = true;
+                        final String[] types = new String[dto.types.length + 1];
+                        System.arraycopy(dto.types, 0, types, 0, dto.types.length);
+                        types[dto.types.length] = status.getHandler().getListenerInfo().getListenerName();
+                        dto.types = types;
+                    }
+                    index++;
+                }
+                if ( !found )
+                {
+                    listenerDTOs.add(ListenerDTOBuilder.build(status.getHandler(), status.getResult()));
+                }
+            }
+            else
+            {
+                int index = 0;
+                boolean found = false;
+                final Iterator<FailedListenerDTO> i = failedListenerDTOs.iterator();
+                while ( !found && index < failedLength )
+                {
+                    final FailedListenerDTO dto = i.next();
+                    if ( dto.serviceId == status.getHandler().getListenerInfo().getServiceId()
+                         && dto.failureReason == status.getResult() )
+                    {
+                        found = true;
+                        final String[] types = new String[dto.types.length + 1];
+                        System.arraycopy(dto.types, 0, types, 0, dto.types.length);
+                        types[dto.types.length] = status.getHandler().getListenerInfo().getListenerName();
+                        dto.types = types;
+                    }
+                    index++;
+                }
+                if ( !found )
+                {
+                    failedListenerDTOs.add((FailedListenerDTO)ListenerDTOBuilder.build(status.getHandler(), status.getResult()));
+                }
+            }
+        }
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
index 32e4453..51e942e 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
@@ -55,6 +55,8 @@
 
     private final ErrorPageRegistry errorPageRegistry = new ErrorPageRegistry();
 
+    private final EventListenerRegistry eventListenerRegistry = new EventListenerRegistry();
+
     /**
      * Default http service registry
      */
@@ -92,7 +94,10 @@
 
     public void removeAll()
     {
-        // TODO - implement
+        this.errorPageRegistry.cleanup();
+        this.eventListenerRegistry.cleanup();
+        this.filterRegistry.cleanup();
+        this.servletRegistry.cleanup();
     }
 
     @Override
@@ -181,6 +186,11 @@
         return this.errorPageRegistry.get(exception, code);
     }
 
+    public EventListenerRegistry getEventListenerRegistry()
+    {
+        return this.eventListenerRegistry;
+    }
+
     /**
      * Create all DTOs for servlets, filters, resources and error pages
      * @param dto The servlet context DTO
@@ -197,5 +207,8 @@
 
         // collect servlets and resources
         this.servletRegistry.getRuntimeInfo(dto, failedDTOHolder.failedServletDTOs, failedDTOHolder.failedResourceDTOs);
+
+        // collect listeners
+        this.eventListenerRegistry.getRuntimeInfo(dto, failedDTOHolder.failedListenerDTOs);
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
index 373a494..ced9b7c 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
@@ -293,6 +293,14 @@
         }
     }
 
+    public synchronized void cleanup()
+    {
+        this.activeServletMappings.clear();
+        this.inactiveServletMappings.clear();
+        this.servletsByName.clear();
+        this.statusMapping.clear();
+    }
+
     private void addToInactiveList(final String pattern, final ServletHandler handler, final ServletRegistrationStatus status)
     {
         List<ServletHandler> inactiveList = this.inactiveServletMappings.get(pattern);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionAttributeListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionAttributeListenerInfo.java
index f751140..da52c22 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionAttributeListenerInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionAttributeListenerInfo.java
@@ -29,6 +29,6 @@
 {
     public HttpSessionAttributeListenerInfo(final ServiceReference<HttpSessionAttributeListener> ref)
     {
-        super(ref);
+        super(ref, HttpSessionAttributeListener.class.getName());
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java
index b0eedc0..0d8296d 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java
@@ -29,6 +29,6 @@
 {
     public HttpSessionIdListenerInfo(final ServiceReference<HttpSessionIdListener> ref)
     {
-        super(ref);
+        super(ref, HttpSessionIdListener.class.getName());
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionListenerInfo.java
index aa2f1de..3473993 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionListenerInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionListenerInfo.java
@@ -29,6 +29,6 @@
 {
     public HttpSessionListenerInfo(final ServiceReference<HttpSessionListener> ref)
     {
-        super(ref);
+        super(ref, HttpSessionListener.class.getName());
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
index 15eda56..b758bd0 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
@@ -18,9 +18,6 @@
  */
 package org.apache.felix.http.base.internal.runtime;
 
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceObjects;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
@@ -32,10 +29,13 @@
 
     private final String enabled;
 
-    public ListenerInfo(final ServiceReference<T> ref)
+    private final String listenerName;
+
+    public ListenerInfo(final ServiceReference<T> ref, final String listenerName)
     {
         super(ref);
         this.enabled = this.getStringProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER);
+        this.listenerName = listenerName;
     }
 
     @Override
@@ -44,37 +44,8 @@
         return super.isValid() && "true".equalsIgnoreCase(this.enabled);
     }
 
-
-    public T getService(final Bundle bundle)
+    public String getListenerName()
     {
-        if (this.getServiceReference() != null)
-        {
-            final BundleContext bctx = bundle.getBundleContext();
-            if ( bctx != null )
-            {
-                final ServiceObjects<T> so = bctx.getServiceObjects(this.getServiceReference());
-                if (so != null)
-                {
-                    return so.getService();
-                }
-            }
-        }
-        return null;
-    }
-
-    public void ungetService(final Bundle bundle, final T service)
-    {
-        if (this.getServiceReference() != null)
-        {
-            final BundleContext bctx = bundle.getBundleContext();
-            if ( bctx != null )
-            {
-                final ServiceObjects<T> so = bctx.getServiceObjects(this.getServiceReference());
-                if (so != null)
-                {
-                    so.ungetService(service);
-                }
-            }
-        }
+        return this.listenerName;
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextAttributeListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextAttributeListenerInfo.java
index c41901c..3384557 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextAttributeListenerInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextAttributeListenerInfo.java
@@ -30,6 +30,6 @@
 
     public ServletContextAttributeListenerInfo(final ServiceReference<ServletContextAttributeListener> ref)
     {
-        super(ref);
+        super(ref, ServletContextAttributeListener.class.getName());
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextListenerInfo.java
index 1a11329..7300276 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextListenerInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextListenerInfo.java
@@ -29,6 +29,6 @@
 {
     public ServletContextListenerInfo(final ServiceReference<ServletContextListener> ref)
     {
-        super(ref);
+        super(ref, ServletContextListener.class.getName());
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestAttributeListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestAttributeListenerInfo.java
index 0898b39..7eb86d4 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestAttributeListenerInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestAttributeListenerInfo.java
@@ -29,6 +29,6 @@
 {
     public ServletRequestAttributeListenerInfo(final ServiceReference<ServletRequestAttributeListener> ref)
     {
-        super(ref);
+        super(ref, ServletRequestAttributeListener.class.getName());
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestListenerInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestListenerInfo.java
index c8eb3ca..f1e41cd 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestListenerInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestListenerInfo.java
@@ -29,6 +29,6 @@
 {
     public ServletRequestListenerInfo(final ServiceReference<ServletRequestListener> ref)
     {
-        super(ref);
+        super(ref, ServletRequestListener.class.getName());
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java
index 4df84a6..a6972c3 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java
@@ -29,9 +29,8 @@
 import javax.servlet.http.HttpSessionIdListener;
 import javax.servlet.http.HttpSessionListener;
 
+import org.apache.felix.http.base.internal.handler.ListenerHandler;
 import org.apache.felix.http.base.internal.runtime.ListenerInfo;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.runtime.dto.FailedListenerDTO;
 import org.osgi.service.http.runtime.dto.ListenerDTO;
 
@@ -54,6 +53,7 @@
         final ListenerDTO dto = (reason == -1 ? new ListenerDTO() : new FailedListenerDTO());
 
         dto.serviceId = info.getServiceId();
+        dto.types = new String[] {info.getListenerName()};
 
         if ( reason != -1 )
         {
@@ -63,22 +63,10 @@
         return dto;
     }
 
-    public static ListenerDTO build(final ServiceReference<?> listenerRef, final long servletContextId)
+    public static ListenerDTO build(final ListenerHandler<?> handler, final int reason)
     {
-        final ListenerDTO listenerDTO = new ListenerDTO();
-        listenerDTO.serviceId = (Long) listenerRef.getProperty(Constants.SERVICE_ID);
-        listenerDTO.servletContextId = servletContextId;
-
-        final String[] objectClass = (String[])listenerRef.getProperty(Constants.OBJECTCLASS);
-        final Set<String> names = new HashSet<String>();
-        for(final String name : objectClass)
-        {
-            if ( ALLOWED_INTERFACES.contains(name) )
-            {
-                names.add(name);
-            }
-        }
-        listenerDTO.types = names.toArray(new String[names.size()]);
-        return listenerDTO;
+        final ListenerDTO dto = build(handler.getListenerInfo(), reason);
+        dto.servletContextId = handler.getContextServiceId();
+        return dto;
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
index bbfeb05..6a9f76c 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
@@ -49,7 +49,7 @@
     @Override
     public RuntimeDTO getRuntimeDTO()
     {
-        final RuntimeDTOBuilder runtimeDTOBuilder = new RuntimeDTOBuilder(contextManager.getRuntime(registry),
+        final RuntimeDTOBuilder runtimeDTOBuilder = new RuntimeDTOBuilder(contextManager.getRuntimeInfo(registry),
                 this.serviceReference);
         return runtimeDTOBuilder.build();
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
index 16cbcc6..9a57ca2 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
@@ -19,11 +19,12 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.servlet.ServletContext;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
-import org.apache.felix.http.base.internal.registry.EventListenerRegistry;
+import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -35,8 +36,10 @@
     /** The info object for the context. */
     private final ServletContextHelperInfo info;
 
+    private final ServletContext webContext;
+
     /** The shared part of the servlet context. */
-    private final ServletContext sharedContext;
+    private volatile ServletContext sharedContext;
 
     /** The http bundle. */
     private final Bundle bundle;
@@ -44,20 +47,15 @@
     /** A map of all created servlet contexts. Each bundle gets it's own instance. */
     private final Map<Long, ContextHolder> perBundleContextMap = new HashMap<Long, ContextHolder>();
 
-    private final EventListenerRegistry eventListener;
+    private volatile PerContextHandlerRegistry registry;
 
     public ContextHandler(final ServletContextHelperInfo info,
             final ServletContext webContext,
             final Bundle bundle)
     {
+        this.webContext = webContext;
         this.info = info;
-        this.eventListener = new EventListenerRegistry(bundle);
         this.bundle = bundle;
-        this.sharedContext = new SharedServletContextImpl(webContext,
-                info.getName(),
-                info.getPath(),
-                info.getInitParameters(),
-                eventListener);
     }
 
     public ServletContextHelperInfo getContextInfo()
@@ -75,17 +73,37 @@
      * Activate this context.
      * @return {@code true} if it succeeded.
      */
-    public boolean activate()
+    public boolean activate(final WhiteboardHttpService httpService)
     {
-        return getServletContext(bundle) != null;
+        this.registry = new PerContextHandlerRegistry(this.info);
+        this.sharedContext = new SharedServletContextImpl(webContext,
+                info.getName(),
+                info.getPath(),
+                info.getInitParameters(),
+                this.registry.getEventListenerRegistry());
+        final boolean activate = getServletContext(bundle) != null;
+        if ( !activate )
+        {
+            this.registry = null;
+            this.sharedContext = null;
+        }
+        else
+        {
+            httpService.registerContext(this.registry);
+        }
+        return activate;
     }
 
     /**
      * Deactivate this context.
      */
-    public void deactivate()
+    public void deactivate(final WhiteboardHttpService httpService)
     {
+        httpService.unregisterContext(this);
+        this.registry = null;
+        this.sharedContext = null;
         this.ungetServletContext(bundle);
+        // TODO we should clear all state
     }
 
     public ServletContext getSharedContext()
@@ -93,8 +111,12 @@
         return sharedContext;
     }
 
-    public ExtServletContext getServletContext(@Nonnull final Bundle bundle)
+    public ExtServletContext getServletContext(@CheckForNull final Bundle bundle)
     {
+        if ( bundle == null )
+        {
+            return null;
+        }
         final Long key = bundle.getBundleId();
         synchronized ( this.perBundleContextMap )
         {
@@ -113,7 +135,7 @@
                         holder.servletContext = new PerBundleServletContextImpl(bundle,
                                 this.sharedContext,
                                 service,
-                                this.eventListener);
+                                this.registry.getEventListenerRegistry());
                         this.perBundleContextMap.put(key, holder);
                     }
                 }
@@ -161,7 +183,8 @@
         public ServletContextHelper servletContextHelper;
     }
 
-    public EventListenerRegistry getListenerRegistry() {
-        return this.eventListener;
+    public PerContextHandlerRegistry getRegistry()
+    {
+        return this.registry;
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
index 5ce2948..b6149e8 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
@@ -17,17 +17,34 @@
 package org.apache.felix.http.base.internal.whiteboard;
 
 import javax.annotation.Nonnull;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionIdListener;
+import javax.servlet.http.HttpSessionListener;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.HttpServiceServletHandler;
+import org.apache.felix.http.base.internal.handler.ListenerHandler;
 import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.handler.WhiteboardFilterHandler;
+import org.apache.felix.http.base.internal.handler.WhiteboardListenerHandler;
 import org.apache.felix.http.base.internal.handler.WhiteboardServletHandler;
 import org.apache.felix.http.base.internal.registry.HandlerRegistry;
+import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionIdListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ResourceInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestListenerInfo;
 import org.apache.felix.http.base.internal.service.ResourceServlet;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.http.runtime.dto.DTOConstants;
@@ -114,6 +131,167 @@
         contextHandler.ungetServletContext(filterInfo.getServiceReference().getBundle());
     }
 
+    public int registerListener(@Nonnull final ContextHandler contextHandler,
+            @Nonnull final ServletContextListenerInfo info)
+    {
+        final ExtServletContext context = contextHandler.getServletContext(info.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
+        final ListenerHandler<ServletContextListener> handler = new WhiteboardListenerHandler<ServletContextListener>(
+                contextHandler.getContextInfo().getServiceId(),
+                context,
+                info,
+                bundleContext);
+        contextHandler.getRegistry().getEventListenerRegistry().addServletContextListener(handler);
+        return -1;
+    }
+
+    public void unregisterListener(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletContextListenerInfo info)
+    {
+        contextHandler.getRegistry().getEventListenerRegistry().removeServletContextListener(info);
+        contextHandler.ungetServletContext(info.getServiceReference().getBundle());
+    }
+
+    public int registerListener(@Nonnull final ContextHandler contextHandler,
+            @Nonnull final ServletContextAttributeListenerInfo info)
+    {
+        final ExtServletContext context = contextHandler.getServletContext(info.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
+        final ListenerHandler<ServletContextAttributeListener> handler = new WhiteboardListenerHandler<ServletContextAttributeListener>(
+                contextHandler.getContextInfo().getServiceId(),
+                context,
+                info,
+                bundleContext);
+        contextHandler.getRegistry().getEventListenerRegistry().addServletContextAttributeListener(handler);
+        return -1;
+    }
+
+    public void unregisterListener(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletContextAttributeListenerInfo info)
+    {
+        contextHandler.getRegistry().getEventListenerRegistry().removeServletContextAttributeListener(info);
+        contextHandler.ungetServletContext(info.getServiceReference().getBundle());
+    }
+
+    public int registerListener(@Nonnull final ContextHandler contextHandler,
+            @Nonnull final HttpSessionListenerInfo info)
+    {
+        final ExtServletContext context = contextHandler.getServletContext(info.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
+        final ListenerHandler<HttpSessionListener> handler = new WhiteboardListenerHandler<HttpSessionListener>(
+                contextHandler.getContextInfo().getServiceId(),
+                context,
+                info,
+                bundleContext);
+        contextHandler.getRegistry().getEventListenerRegistry().addSessionListener(handler);
+        return -1;
+    }
+
+    public void unregisterListener(@Nonnull final ContextHandler contextHandler, @Nonnull final HttpSessionListenerInfo info)
+    {
+        contextHandler.getRegistry().getEventListenerRegistry().removeSessionListener(info);
+        contextHandler.ungetServletContext(info.getServiceReference().getBundle());
+    }
+
+    public int registerListener(@Nonnull final ContextHandler contextHandler,
+            @Nonnull final HttpSessionIdListenerInfo info)
+    {
+        final ExtServletContext context = contextHandler.getServletContext(info.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
+        final ListenerHandler<HttpSessionIdListener> handler = new WhiteboardListenerHandler<HttpSessionIdListener>(
+                contextHandler.getContextInfo().getServiceId(),
+                context,
+                info,
+                bundleContext);
+        contextHandler.getRegistry().getEventListenerRegistry().addSessionIdListener(handler);
+        return -1;
+    }
+
+    public void unregisterListener(@Nonnull final ContextHandler contextHandler, @Nonnull final HttpSessionIdListenerInfo info)
+    {
+        contextHandler.getRegistry().getEventListenerRegistry().removeSessionIdListener(info);
+        contextHandler.ungetServletContext(info.getServiceReference().getBundle());
+    }
+
+    public int registerListener(@Nonnull final ContextHandler contextHandler,
+            @Nonnull final HttpSessionAttributeListenerInfo info)
+    {
+        final ExtServletContext context = contextHandler.getServletContext(info.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
+        final ListenerHandler<HttpSessionAttributeListener> handler = new WhiteboardListenerHandler<HttpSessionAttributeListener>(
+                contextHandler.getContextInfo().getServiceId(),
+                context,
+                info,
+                bundleContext);
+        contextHandler.getRegistry().getEventListenerRegistry().addSessionAttributeListener(handler);
+        return -1;
+    }
+
+    public void unregisterListener(@Nonnull final ContextHandler contextHandler, @Nonnull final HttpSessionAttributeListenerInfo info)
+    {
+        contextHandler.getRegistry().getEventListenerRegistry().removeSessionAttributeListener(info);
+        contextHandler.ungetServletContext(info.getServiceReference().getBundle());
+    }
+
+    public int registerListener(@Nonnull final ContextHandler contextHandler,
+            @Nonnull final ServletRequestListenerInfo info)
+    {
+        final ExtServletContext context = contextHandler.getServletContext(info.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
+        final ListenerHandler<ServletRequestListener> handler = new WhiteboardListenerHandler<ServletRequestListener>(
+                contextHandler.getContextInfo().getServiceId(),
+                context,
+                info,
+                bundleContext);
+        contextHandler.getRegistry().getEventListenerRegistry().addServletRequestListener(handler);
+        return -1;
+    }
+
+    public void unregisterListener(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletRequestListenerInfo info)
+    {
+        contextHandler.getRegistry().getEventListenerRegistry().removeServletRequestListener(info);
+        contextHandler.ungetServletContext(info.getServiceReference().getBundle());
+    }
+
+    public int registerListener(@Nonnull final ContextHandler contextHandler,
+            @Nonnull final ServletRequestAttributeListenerInfo info)
+    {
+        final ExtServletContext context = contextHandler.getServletContext(info.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
+        final ListenerHandler<ServletRequestAttributeListener> handler = new WhiteboardListenerHandler<ServletRequestAttributeListener>(
+                contextHandler.getContextInfo().getServiceId(),
+                context,
+                info,
+                bundleContext);
+        contextHandler.getRegistry().getEventListenerRegistry().addServletRequestAttributeListener(handler);
+        return -1;
+    }
+
+    public void unregisterListener(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletRequestAttributeListenerInfo info)
+    {
+        contextHandler.getRegistry().getEventListenerRegistry().removeServletRequestAttributeListener(info);
+        contextHandler.ungetServletContext(info.getServiceReference().getBundle());
+    }
+
     /**
      * Register a resource.
      * @param contextInfo The servlet context helper info
@@ -151,9 +329,9 @@
         contextHandler.ungetServletContext(servletInfo.getServiceReference().getBundle());
     }
 
-    public void registerContext(@Nonnull final ContextHandler contextHandler)
+    public void registerContext(@Nonnull final PerContextHandlerRegistry registry)
     {
-        this.handlerRegistry.add(contextHandler.getContextInfo());
+        this.handlerRegistry.add(registry);
     }
 
     public void unregisterContext(@Nonnull final ContextHandler contextHandler)
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
index 89b729d..dcf17c7 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
@@ -31,10 +31,10 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TreeMap;
 
 import javax.annotation.Nonnull;
 import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.http.HttpSession;
 import javax.servlet.http.HttpSessionEvent;
@@ -42,6 +42,7 @@
 import org.apache.felix.http.base.internal.console.HttpServicePlugin;
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.HttpSessionWrapper;
+import org.apache.felix.http.base.internal.handler.ListenerHandler;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.registry.HandlerRegistry;
 import org.apache.felix.http.base.internal.runtime.AbstractInfo;
@@ -270,7 +271,7 @@
             final ContextHandler handler = this.getContextHandler(contextId);
             if ( handler != null )
             {
-                handler.getListenerRegistry().sessionIdChanged(event, oldSessionId);
+                handler.getRegistry().getEventListenerRegistry().sessionIdChanged(event, oldSessionId);
             }
         }
     }
@@ -283,49 +284,37 @@
      */
     private boolean activate(final ContextHandler handler)
     {
-        if ( !handler.activate() )
+        if ( !handler.activate(this.httpService) )
         {
             return false;
         }
 
-        this.httpService.registerContext(handler);
-
-        // use a map to sort the listeners
-        final Map<ServiceReference<ServletContextListener>, ServletContextListenerInfo> listeners = new TreeMap<ServiceReference<ServletContextListener>, ServletContextListenerInfo>();
         final List<WhiteboardServiceInfo<?>> services = new ArrayList<WhiteboardServiceInfo<?>>();
-
         for(final Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>> entry : this.servicesMap.entrySet())
         {
             if ( entry.getKey().getContextSelectionFilter().match(handler.getContextInfo().getServiceReference()) )
             {
                 entry.getValue().add(handler);
-                if ( entry.getKey() instanceof ServletContextListenerInfo )
-                {
-                    final ServletContextListenerInfo info = (ServletContextListenerInfo)entry.getKey();
-                    listeners.put(info.getServiceReference(), info);
-                }
-                else
-                {
-                    services.add(entry.getKey());
-                }
                 if ( entry.getValue().size() == 1 )
                 {
                     this.failureStateHandler.remove(entry.getKey());
                 }
+                if ( entry.getKey() instanceof ServletContextListenerInfo )
+                {
+                    // servlet context listeners will be registered directly
+                    this.registerWhiteboardService(handler, entry.getKey());
+                }
+                else
+                {
+                    // registration of other services will be delayed
+                    services.add(entry.getKey());
+                }
             }
         }
-        // context listeners first
-        for(final ServletContextListenerInfo info : listeners.values())
-        {
-            final int reason = handler.getListenerRegistry().initialized(info, handler);
-            if ( reason != -1 )
-            {
-                final String type = info.getClass().getSimpleName().substring(0,info.getClass().getSimpleName().length() - 4);
-                SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
-                this.failureStateHandler.add(info, handler.getContextInfo().getServiceId(), reason);
-            }
-        }
-        // now register services
+        // notify context listeners first
+        handler.getRegistry().getEventListenerRegistry().contextInitialized();
+
+        // register services
         for(final WhiteboardServiceInfo<?> info : services)
         {
             this.registerWhiteboardService(handler, info);
@@ -341,8 +330,8 @@
      */
     private void deactivate(final ContextHandler handler)
     {
-        // context listeners last but sorted
-        final Map<ServiceReference<ServletContextListener>, ServletContextListenerInfo> listeners = new TreeMap<ServiceReference<ServletContextListener>, ServletContextListenerInfo>();
+        // services except context listeners first
+        final List<WhiteboardServiceInfo<?>> listeners = new ArrayList<WhiteboardServiceInfo<?>>();
         final Iterator<Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>>> i = this.servicesMap.entrySet().iterator();
         while ( i.hasNext() )
         {
@@ -353,8 +342,7 @@
                 {
                     if ( entry.getKey() instanceof ServletContextListenerInfo )
                     {
-                        final ServletContextListenerInfo info = (ServletContextListenerInfo)entry.getKey();
-                        listeners.put(info.getServiceReference(), info);
+                        listeners.add(entry.getKey());
                     }
                     else
                     {
@@ -369,14 +357,14 @@
                 }
             }
         }
-        for(final ServletContextListenerInfo info : listeners.values())
+        // context listeners last
+        handler.getRegistry().getEventListenerRegistry().contextDestroyed();
+        for(final WhiteboardServiceInfo<?> info : listeners)
         {
-            handler.getListenerRegistry().destroyed(info, handler);
+            this.unregisterWhiteboardService(handler, info);
         }
 
-        this.httpService.unregisterContext(handler);
-
-        handler.deactivate();
+        handler.deactivate(this.httpService);
     }
 
     /**
@@ -584,20 +572,19 @@
                     {
                         for(final ContextHandler h : handlerList)
                         {
+                            this.registerWhiteboardService(h, info);
                             if ( info instanceof ServletContextListenerInfo )
                             {
-                                final int reason = h.getListenerRegistry().initialized((ServletContextListenerInfo)info, h);
-                                if ( reason != -1 )
+                                final ListenerHandler<ServletContextListener> handler = h.getRegistry().getEventListenerRegistry().getServletContextListener((ServletContextListenerInfo)info);
+                                if ( handler != null )
                                 {
-                                    final String type = info.getClass().getSimpleName().substring(0,info.getClass().getSimpleName().length() - 4);
-                                    SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
-                                    this.failureStateHandler.add(info, h.getContextInfo().getServiceId(), reason);
+                                    final ServletContextListener listener = handler.getListener();
+                                    if ( listener != null )
+                                    {
+                                        listener.contextInitialized(new ServletContextEvent(handler.getContext()));
+                                    }
                                 }
                             }
-                            else
-                            {
-                                this.registerWhiteboardService(h, info);
-                            }
                         }
                     }
                 }
@@ -631,14 +618,19 @@
                     {
                         if ( !failureStateHandler.remove(info, h.getContextInfo().getServiceId()) )
                         {
-                            if ( !(info instanceof ServletContextListenerInfo ) )
+                            if ( info instanceof ServletContextListenerInfo )
                             {
-                                this.unregisterWhiteboardService(h, info);
+                                final ListenerHandler<ServletContextListener> handler = h.getRegistry().getEventListenerRegistry().getServletContextListener((ServletContextListenerInfo)info);
+                                if ( handler != null )
+                                {
+                                    final ServletContextListener listener = handler.getListener();
+                                    if ( listener != null )
+                                    {
+                                        listener.contextDestroyed(new ServletContextEvent(handler.getContext()));
+                                    }
+                                }
                             }
-                            else
-                            {
-                                h.getListenerRegistry().destroyed((ServletContextListenerInfo)info, h);
-                            }
+                            this.unregisterWhiteboardService(h, info);
                         }
                     }
                 }
@@ -670,29 +662,33 @@
                 failureCode = this.httpService.registerResource(handler, (ResourceInfo)info);
             }
 
+            else if ( info instanceof ServletContextListenerInfo )
+            {
+                failureCode = this.httpService.registerListener(handler, (ServletContextListenerInfo) info);
+            }
             else if ( info instanceof ServletContextAttributeListenerInfo )
             {
-                failureCode = handler.getListenerRegistry().addListener((ServletContextAttributeListenerInfo) info);
+                failureCode = this.httpService.registerListener(handler, (ServletContextAttributeListenerInfo) info);
             }
             else if ( info instanceof HttpSessionListenerInfo )
             {
-                failureCode = handler.getListenerRegistry().addListener((HttpSessionListenerInfo) info);
+                failureCode = this.httpService.registerListener(handler, (HttpSessionListenerInfo) info);
             }
             else if ( info instanceof HttpSessionAttributeListenerInfo )
             {
-                failureCode = handler.getListenerRegistry().addListener((HttpSessionAttributeListenerInfo) info);
+                failureCode = this.httpService.registerListener(handler, (HttpSessionAttributeListenerInfo) info);
             }
             else if ( info instanceof HttpSessionIdListenerInfo )
             {
-                failureCode = handler.getListenerRegistry().addListener((HttpSessionIdListenerInfo) info);
+                failureCode = this.httpService.registerListener(handler, (HttpSessionIdListenerInfo) info);
             }
             else if ( info instanceof ServletRequestListenerInfo )
             {
-                failureCode = handler.getListenerRegistry().addListener((ServletRequestListenerInfo) info);
+                failureCode = this.httpService.registerListener(handler, (ServletRequestListenerInfo) info);
             }
             else if ( info instanceof ServletRequestAttributeListenerInfo )
             {
-                failureCode = handler.getListenerRegistry().addListener((ServletRequestAttributeListenerInfo) info);
+                failureCode = this.httpService.registerListener(handler, (ServletRequestAttributeListenerInfo) info);
             }
             else
             {
@@ -735,29 +731,33 @@
                 this.httpService.unregisterResource(handler, (ResourceInfo)info);
             }
 
+            else if ( info instanceof ServletContextListenerInfo )
+            {
+                this.httpService.unregisterListener(handler, (ServletContextListenerInfo) info);
+            }
             else if ( info instanceof ServletContextAttributeListenerInfo )
             {
-                handler.getListenerRegistry().removeListener((ServletContextAttributeListenerInfo) info);
+                this.httpService.unregisterListener(handler, (ServletContextAttributeListenerInfo) info);
             }
             else if ( info instanceof HttpSessionListenerInfo )
             {
-                handler.getListenerRegistry().removeListener((HttpSessionListenerInfo) info);
+                this.httpService.unregisterListener(handler, (HttpSessionListenerInfo) info);
             }
             else if ( info instanceof HttpSessionAttributeListenerInfo )
             {
-                handler.getListenerRegistry().removeListener((HttpSessionAttributeListenerInfo) info);
+                this.httpService.unregisterListener(handler, (HttpSessionAttributeListenerInfo) info);
             }
             else if ( info instanceof HttpSessionIdListenerInfo )
             {
-                handler.getListenerRegistry().removeListener((HttpSessionIdListenerInfo) info);
+                this.httpService.unregisterListener(handler, (HttpSessionIdListenerInfo) info);
             }
             else if ( info instanceof ServletRequestListenerInfo )
             {
-                handler.getListenerRegistry().removeListener((ServletRequestListenerInfo) info);
+                this.httpService.unregisterListener(handler, (ServletRequestListenerInfo) info);
             }
             else if ( info instanceof ServletRequestAttributeListenerInfo )
             {
-                handler.getListenerRegistry().removeListener((ServletRequestAttributeListenerInfo) info);
+                this.httpService.unregisterListener(handler, (ServletRequestAttributeListenerInfo) info);
             }
         }
         catch (final Exception e)
@@ -807,7 +807,7 @@
         return null;
     }
 
-    public RegistryRuntime getRuntime(final HandlerRegistry registry)
+    public RegistryRuntime getRuntimeInfo(final HandlerRegistry registry)
     {
         final FailedDTOHolder failedDTOHolder = new FailedDTOHolder();
 
@@ -817,7 +817,7 @@
                 HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID,
                 HttpServiceFactory.HTTP_SERVICE_CONTEXT_NAME, "/", null);
         final ServletContextDTO dto = ServletContextDTOBuilder.build(info, webContext, -1);
-        if ( registry.getRuntime(dto, failedDTOHolder) )
+        if ( registry.getRuntimeInfo(dto, failedDTOHolder) )
         {
             contextDTOs.add(dto);
         }
@@ -841,9 +841,8 @@
         {
             final ServletContextDTO scDTO = ServletContextDTOBuilder.build(handler.getContextInfo(), handler.getSharedContext(), -1);
 
-            if ( registry.getRuntime(scDTO, failedDTOHolder) )
+            if ( registry.getRuntimeInfo(scDTO, failedDTOHolder) )
             {
-                handler.getListenerRegistry().getRuntime(scDTO);
                 contextDTOs.add(scDTO);
             }
         }
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java
index a9530ed..08834df 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java
@@ -46,14 +46,14 @@
         final ServletContextDTO dto = new ServletContextDTO();
         dto.serviceId = HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID;
 
-        assertFalse(registry.getRuntime(dto, holder));
+        assertFalse(registry.getRuntimeInfo(dto, holder));
 
         registry.init();
 
-        assertTrue(registry.getRuntime(dto, holder));
+        assertTrue(registry.getRuntimeInfo(dto, holder));
 
         registry.shutdown();
-        assertFalse(registry.getRuntime(dto, holder));
+        assertFalse(registry.getRuntimeInfo(dto, holder));
     }
 
     @Test
@@ -67,28 +67,28 @@
         dto.servletDTOs = new ServletDTO[0];
 
         Servlet servlet = Mockito.mock(Servlet.class);
-        final ServletInfo info = new ServletInfo("foo", "/foo", 0, Collections.EMPTY_MAP);
+        final ServletInfo info = new ServletInfo("foo", "/foo", 0, Collections.<String, String> emptyMap());
         ServletHandler handler = new HttpServiceServletHandler(null, info, servlet);
 
-        assertTrue(registry.getRuntime(dto, holder));
+        assertTrue(registry.getRuntimeInfo(dto, holder));
         assertEquals("Precondition", 0, dto.servletDTOs.length);
 
         registry.addServlet(handler);
         Mockito.verify(servlet, Mockito.times(1)).init(Mockito.any(ServletConfig.class));
-        assertTrue(registry.getRuntime(dto, holder));
+        assertTrue(registry.getRuntimeInfo(dto, holder));
         assertEquals(1, dto.servletDTOs.length);
         assertEquals(info.getServiceId(), dto.servletDTOs[0].serviceId);
 
-        final ServletInfo info2 = new ServletInfo("bar", "/bar", 0, Collections.EMPTY_MAP);
+        final ServletInfo info2 = new ServletInfo("bar", "/bar", 0, Collections.<String, String> emptyMap());
         ServletHandler handler2 = new HttpServiceServletHandler(null, info2, Mockito.mock(Servlet.class));
         registry.addServlet(handler2);
-        assertTrue(registry.getRuntime(dto, holder));
+        assertTrue(registry.getRuntimeInfo(dto, holder));
         assertEquals(2, dto.servletDTOs.length);
 
-        final ServletInfo info3 = new ServletInfo("zar", "/foo", 0, Collections.EMPTY_MAP);
+        final ServletInfo info3 = new ServletInfo("zar", "/foo", 0, Collections.<String, String> emptyMap());
         ServletHandler handler3 = new HttpServiceServletHandler(null,info3, Mockito.mock(Servlet.class));
         registry.addServlet(handler3);
-        assertTrue(registry.getRuntime(dto, holder));
+        assertTrue(registry.getRuntimeInfo(dto, holder));
         assertEquals(2, dto.servletDTOs.length);
         assertEquals(1, holder.failedServletDTOs.size());