FELIX-4060 : Implement HTTP Service Update (RFC-189) - merge two manager classes into single one

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1670916 13f79535-47bb-0310-9956-ffa450edef68
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 83262cc..d6b2eab 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
@@ -24,7 +24,7 @@
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
 import org.apache.felix.http.base.internal.runtime.dto.RegistryRuntime;
 import org.apache.felix.http.base.internal.runtime.dto.RuntimeDTOBuilder;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.service.http.runtime.HttpServiceRuntime;
 import org.osgi.service.http.runtime.dto.RequestInfoDTO;
 import org.osgi.service.http.runtime.dto.RuntimeDTO;
@@ -34,15 +34,16 @@
     private final Hashtable<String, Object> attributes = new Hashtable<String, Object>();
 
     private final HandlerRegistry registry;
-    private final ServletContextHelperManager contextManager;
+    private final WhiteboardManager contextManager;
 
     public HttpServiceRuntimeImpl(HandlerRegistry registry,
-            ServletContextHelperManager contextManager)
+            WhiteboardManager contextManager)
     {
         this.registry = registry;
         this.contextManager = contextManager;
     }
 
+    @Override
     public synchronized RuntimeDTO getRuntimeDTO()
     {
         RegistryRuntime runtime = contextManager.getRuntime(registry);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
deleted file mode 100644
index 546b2f4..0000000
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * 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.whiteboard;
-
-import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING;
-import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE;
-import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_UNKNOWN;
-import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_VALIDATION_FAILED;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentSkipListMap;
-
-import javax.annotation.Nonnull;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextListener;
-
-import org.apache.felix.http.base.internal.handler.HandlerRegistry;
-import org.apache.felix.http.base.internal.logger.SystemLogger;
-import org.apache.felix.http.base.internal.runtime.AbstractInfo;
-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.ServletContextHelperInfo;
-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.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.runtime.dto.ContextRuntime;
-import org.apache.felix.http.base.internal.runtime.dto.FailureRuntime;
-import org.apache.felix.http.base.internal.runtime.dto.RegistryRuntime;
-import org.apache.felix.http.base.internal.runtime.dto.ServletContextHelperRuntime;
-import org.apache.felix.http.base.internal.util.MimeTypes;
-import org.apache.felix.http.base.internal.whiteboard.tracker.FilterTracker;
-import org.apache.felix.http.base.internal.whiteboard.tracker.HttpSessionAttributeListenerTracker;
-import org.apache.felix.http.base.internal.whiteboard.tracker.HttpSessionListenerTracker;
-import org.apache.felix.http.base.internal.whiteboard.tracker.ResourceTracker;
-import org.apache.felix.http.base.internal.whiteboard.tracker.ServletContextAttributeListenerTracker;
-import org.apache.felix.http.base.internal.whiteboard.tracker.ServletContextHelperTracker;
-import org.apache.felix.http.base.internal.whiteboard.tracker.ServletContextListenerTracker;
-import org.apache.felix.http.base.internal.whiteboard.tracker.ServletRequestAttributeListenerTracker;
-import org.apache.felix.http.base.internal.whiteboard.tracker.ServletRequestListenerTracker;
-import org.apache.felix.http.base.internal.whiteboard.tracker.ServletTracker;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceFactory;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.http.context.ServletContextHelper;
-import org.osgi.service.http.runtime.HttpServiceRuntime;
-import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
-import org.osgi.util.tracker.ServiceTracker;
-
-public final class ServletContextHelperManager
-{
-    /** A map containing all servlet context registrations. Mapped by context name */
-    private final Map<String, List<ContextHandler>> contextMap = new HashMap<String, List<ContextHandler>>();
-
-    /** A map with all servlet/filter registrations, mapped by abstract info. */
-    private final Map<WhiteboardServiceInfo<?>, List<ContextHandler>> servicesMap = new HashMap<WhiteboardServiceInfo<?>, List<ContextHandler>>();
-
-    private final WhiteboardHttpService httpService;
-
-    private final ListenerRegistry listenerRegistry;
-
-    private final BundleContext bundleContext;
-
-    private final Map<AbstractInfo<?>, Integer> serviceFailures = new ConcurrentSkipListMap<AbstractInfo<?>, Integer>();
-
-    private volatile ServletContext webContext;
-
-    private volatile ServiceReference<HttpServiceRuntime> httpServiceRuntime;
-
-    private volatile ServiceRegistration<ServletContextHelper> defaultContextRegistration;
-
-    private final List<ServiceTracker<?, ?>> trackers = new ArrayList<ServiceTracker<?, ?>>();
-
-    /**
-     * Create a new servlet context helper manager
-     * and the default context
-     */
-    public ServletContextHelperManager(final BundleContext bundleContext,
-            final HandlerRegistry registry)
-    {
-        this.bundleContext = bundleContext;
-        this.httpService = new WhiteboardHttpService(this.bundleContext, registry);
-        this.listenerRegistry = new ListenerRegistry(bundleContext.getBundle());
-    }
-
-    public void start(ServletContext webContext, ServiceReference<HttpServiceRuntime> httpServiceRuntime)
-    {
-        this.webContext = webContext;
-        this.httpServiceRuntime = httpServiceRuntime;
-
-        final Dictionary<String, Object> props = new Hashtable<String, Object>();
-        props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, HttpWhiteboardConstants.HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME);
-        props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, "/");
-        props.put(Constants.SERVICE_RANKING, Integer.MIN_VALUE);
-
-        this.defaultContextRegistration = bundleContext.registerService(
-                ServletContextHelper.class,
-                new ServiceFactory<ServletContextHelper>()
-                {
-
-                    @Override
-                    public ServletContextHelper getService(
-                            final Bundle bundle,
-                            final ServiceRegistration<ServletContextHelper> registration)
-                    {
-                        return new ServletContextHelper(bundle)
-                        {
-
-                            @Override
-                            public String getMimeType(final String file)
-                            {
-                                return MimeTypes.get().getByFile(file);
-                            }
-                        };
-                    }
-
-                    @Override
-                    public void ungetService(
-                            final Bundle bundle,
-                            final ServiceRegistration<ServletContextHelper> registration,
-                            final ServletContextHelper service)
-                    {
-                        // nothing to do
-                    }
-                }, props);
-        addTracker(new FilterTracker(this.bundleContext, this));
-        addTracker(new ServletTracker(this.bundleContext, this));
-        addTracker(new ResourceTracker(this.bundleContext, this));
-
-        addTracker(new HttpSessionListenerTracker(this.bundleContext, this));
-        addTracker(new HttpSessionAttributeListenerTracker(this.bundleContext, this));
-
-        addTracker(new ServletContextHelperTracker(this.bundleContext, this));
-        addTracker(new ServletContextListenerTracker(this.bundleContext, this));
-        addTracker(new ServletContextAttributeListenerTracker(this.bundleContext, this));
-
-        addTracker(new ServletRequestListenerTracker(this.bundleContext, this));
-        addTracker(new ServletRequestAttributeListenerTracker(this.bundleContext, this));
-    }
-
-    private void addTracker(ServiceTracker<?, ?> tracker)
-    {
-        this.trackers.add(tracker);
-        tracker.open();
-    }
-
-    /**
-     * Stop the instance
-     */
-    public void stop()
-    {
-        for(final ServiceTracker<?, ?> t : this.trackers)
-        {
-            t.close();
-        }
-        this.trackers.clear();
-
-        // TODO cleanup
-        if (this.defaultContextRegistration != null)
-        {
-            this.defaultContextRegistration.unregister();
-            this.defaultContextRegistration = null;
-        }
-    }
-
-    /**
-     * Activate a servlet context helper.
-     * @param contextInfo A context info
-     */
-    private void activate(final ContextHandler handler)
-    {
-        handler.activate();
-
-        this.httpService.registerContext(handler);
-
-        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());
-                }
-                removeFailure(entry.getKey(), FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
-            }
-        }
-        // context listeners first
-        for(final ServletContextListenerInfo info : listeners.values())
-        {
-            this.listenerRegistry.initialized(info, handler);
-        }
-        // now register services
-        for(final WhiteboardServiceInfo<?> info : services)
-        {
-            this.registerWhiteboardService(handler, info);
-        }
-    }
-
-    /**
-     * Deactivate a servlet context helper.
-     * @param contextInfo A context info
-     */
-    private void deactivate(final ContextHandler handler)
-    {
-        // context listeners last
-        final Map<ServiceReference<ServletContextListener>, ServletContextListenerInfo> listeners = new TreeMap<ServiceReference<ServletContextListener>, ServletContextListenerInfo>();
-        final Iterator<Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>>> i = this.servicesMap.entrySet().iterator();
-        while ( i.hasNext() )
-        {
-            final Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>> entry = i.next();
-            if ( entry.getValue().remove(handler) )
-            {
-                if ( entry.getKey() instanceof ServletContextListenerInfo )
-                {
-                    final ServletContextListenerInfo info = (ServletContextListenerInfo)entry.getKey();
-                    listeners.put(info.getServiceReference(), info);
-                }
-                else
-                {
-                    this.unregisterWhiteboardService(handler, entry.getKey());
-                }
-            }
-        }
-        for(final ServletContextListenerInfo info : listeners.values())
-        {
-            this.listenerRegistry.destroyed(info, handler);
-        }
-        handler.deactivate();
-
-        this.httpService.unregisterContext(handler);
-    }
-
-    /**
-     * Add a servlet context helper.
-     */
-    public void addContextHelper(final ServletContextHelperInfo info)
-    {
-        // no failure DTO and no logging if not matching
-        if ( isMatchingService(info) )
-        {
-            if ( info.isValid() )
-            {
-                synchronized ( this.contextMap )
-                {
-                    PerContextEventListener contextEventListener = listenerRegistry.addContext(info);
-                    ContextHandler handler = new ContextHandler(info,
-                            this.webContext,
-                            contextEventListener,
-                            this.bundleContext.getBundle());
-
-                    List<ContextHandler> handlerList = this.contextMap.get(info.getName());
-                    if ( handlerList == null )
-                    {
-                        handlerList = new ArrayList<ContextHandler>();
-                        this.contextMap.put(info.getName(), handlerList);
-                    }
-                    handlerList.add(handler);
-                    Collections.sort(handlerList);
-                    // check for activate/deactivate
-                    if ( handlerList.get(0) == handler )
-                    {
-                        // check for deactivate
-                        if ( handlerList.size() > 1 )
-                        {
-                            ContextHandler oldHead = handlerList.get(1);
-                            this.deactivate(oldHead);
-                            this.serviceFailures.put(oldHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
-                        }
-                        removeFailure(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
-                        this.activate(handler);
-                    }
-                    else
-                    {
-                        this.serviceFailures.put(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
-                    }
-                }
-            }
-            else
-            {
-                final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
-                SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
-                this.serviceFailures.put(info, FAILURE_REASON_VALIDATION_FAILED);
-            }
-        }
-    }
-
-    /**
-     * Remove a servlet context helper
-     */
-    public void removeContextHelper(final ServletContextHelperInfo info)
-    {
-        // no failure DTO and no logging if not matching
-        if ( isMatchingService(info) )
-        {
-            if ( info.isValid() )
-            {
-                synchronized ( this.contextMap )
-                {
-                    final List<ContextHandler> handlerList = this.contextMap.get(info.getName());
-                    if ( handlerList != null )
-                    {
-                        final Iterator<ContextHandler> i = handlerList.iterator();
-                        boolean first = true;
-                        boolean activateNext = false;
-                        while ( i.hasNext() )
-                        {
-                            final ContextHandler handler = i.next();
-                            if ( handler.getContextInfo().compareTo(info) == 0 )
-                            {
-                                i.remove();
-                                // check for deactivate
-                                if ( first )
-                                {
-                                    this.deactivate(handler);
-                                    activateNext = true;
-                                }
-                                break;
-                            }
-                            first = false;
-                        }
-                        if ( handlerList.isEmpty() )
-                        {
-                            this.contextMap.remove(info.getName());
-                        }
-                        else if ( activateNext )
-                        {
-                            ContextHandler newHead = handlerList.get(0);
-                            this.activate(newHead);
-                            removeFailure(newHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
-                        }
-                        listenerRegistry.removeContext(info);
-                    }
-                }
-            }
-            this.serviceFailures.remove(info);
-        }
-    }
-
-    /**
-     * Find the list of matching contexts for the whiteboard service
-     */
-    private List<ContextHandler> getMatchingContexts(final WhiteboardServiceInfo<?> info)
-    {
-        final List<ContextHandler> result = new ArrayList<ContextHandler>();
-        for(final List<ContextHandler> handlerList : this.contextMap.values()) {
-            final ContextHandler h = handlerList.get(0);
-            if ( info.getContextSelectionFilter().match(h.getContextInfo().getServiceReference()) )
-            {
-                result.add(h);
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Add new whiteboard service to the registry
-     * @param info Whiteboard service info
-     */
-    public void addWhiteboardService(@Nonnull final WhiteboardServiceInfo<?> info)
-    {
-        // no logging and no DTO if other target service
-        if ( isMatchingService(info) )
-        {
-            if ( info.isValid() )
-            {
-                synchronized ( this.contextMap )
-                {
-                    final List<ContextHandler> handlerList = this.getMatchingContexts(info);
-                    this.servicesMap.put(info, handlerList);
-                    if (handlerList.isEmpty())
-                    {
-                        this.serviceFailures.put(info, FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
-                    }
-                    else
-                    {
-                        for(final ContextHandler h : handlerList)
-                        {
-                            this.registerWhiteboardService(h, info);
-                        }
-                    }
-                }
-            }
-            else
-            {
-                final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
-                SystemLogger.debug("Ignoring invalid " + type + " service " + info.getServiceReference());
-                this.serviceFailures.put(info, FAILURE_REASON_VALIDATION_FAILED);
-            }
-        }
-    }
-
-    /**
-     * Remove whiteboard service from the registry
-     * @param info Whiteboard service info
-     */
-    public void removeWhiteboardService(@Nonnull final WhiteboardServiceInfo<?> info)
-    {
-        // no logging and no DTO if other target service
-        if ( isMatchingService(info) ) {
-            if ( info.isValid() )
-            {
-                synchronized ( this.contextMap )
-                {
-                    final List<ContextHandler> handlerList = this.servicesMap.remove(info);
-                    if ( handlerList != null )
-                    {
-                        for(final ContextHandler h : handlerList)
-                        {
-                            this.unregisterWhiteboardService(h, info);
-                        }
-                    }
-                }
-            }
-            this.serviceFailures.remove(info);
-        }
-    }
-
-    /**
-     * Register whiteboard service in the http service
-     * @param handler Context handler
-     * @param info Whiteboard service info
-     */
-    private void registerWhiteboardService(final ContextHandler handler, final WhiteboardServiceInfo<?> info)
-    {
-        try
-        {
-            if ( info instanceof ServletInfo )
-            {
-                this.httpService.registerServlet(handler, (ServletInfo)info);
-            }
-            else if ( info instanceof FilterInfo )
-            {
-                this.httpService.registerFilter(handler, (FilterInfo)info);
-            }
-            else if ( info instanceof ResourceInfo )
-            {
-                this.httpService.registerResource(handler, (ResourceInfo)info);
-            }
-
-            else if ( info instanceof ServletContextAttributeListenerInfo )
-            {
-                this.listenerRegistry.addListener((ServletContextAttributeListenerInfo) info, handler);
-            }
-            else if ( info instanceof HttpSessionListenerInfo )
-            {
-                this.listenerRegistry.addListener((HttpSessionListenerInfo) info, handler);
-            }
-            else if ( info instanceof HttpSessionAttributeListenerInfo )
-            {
-                this.listenerRegistry.addListener((HttpSessionAttributeListenerInfo) info, handler);
-            }
-            else if ( info instanceof HttpSessionIdListenerInfo )
-            {
-                this.listenerRegistry.addListener((HttpSessionIdListenerInfo) info, handler);
-            }
-            else if ( info instanceof ServletRequestListenerInfo )
-            {
-                this.listenerRegistry.addListener((ServletRequestListenerInfo) info, handler);
-            }
-            else if ( info instanceof ServletRequestAttributeListenerInfo )
-            {
-                this.listenerRegistry.addListener((ServletRequestAttributeListenerInfo) info, handler);
-            }
-        }
-        catch (final RegistrationFailureException e)
-        {
-            serviceFailures.put(e.getInfo(), e.getErrorCode());
-            SystemLogger.error("Exception while registering whiteboard service " + info.getServiceReference(), e);
-        }
-        catch (final RuntimeException e)
-        {
-            serviceFailures.put(info, FAILURE_REASON_UNKNOWN);
-            SystemLogger.error("Exception while registering whiteboard service " + info.getServiceReference(), e);
-        }
-    }
-
-    /**
-     * Unregister whiteboard service from the http service
-     * @param handler Context handler
-     * @param info Whiteboard service info
-     */
-    private void unregisterWhiteboardService(final ContextHandler handler, final WhiteboardServiceInfo<?> info)
-    {
-        try
-        {
-            if ( info instanceof ServletInfo )
-            {
-                this.httpService.unregisterServlet(handler, (ServletInfo)info);
-            }
-            else if ( info instanceof FilterInfo )
-            {
-                this.httpService.unregisterFilter(handler, (FilterInfo)info);
-            }
-            else if ( info instanceof ResourceInfo )
-            {
-                this.httpService.unregisterResource(handler, (ResourceInfo)info);
-            }
-
-            else if ( info instanceof ServletContextAttributeListenerInfo )
-            {
-                this.listenerRegistry.removeListener((ServletContextAttributeListenerInfo) info, handler);
-            }
-            else if ( info instanceof HttpSessionListenerInfo )
-            {
-                this.listenerRegistry.removeListener((HttpSessionListenerInfo) info, handler);
-            }
-            else if ( info instanceof HttpSessionAttributeListenerInfo )
-            {
-                this.listenerRegistry.removeListener((HttpSessionAttributeListenerInfo) info, handler);
-            }
-            else if ( info instanceof HttpSessionIdListenerInfo )
-            {
-                this.listenerRegistry.removeListener((HttpSessionIdListenerInfo) info, handler);
-            }
-            else if ( info instanceof ServletRequestListenerInfo )
-            {
-                this.listenerRegistry.removeListener((ServletRequestListenerInfo) info, handler);
-            }
-            else if ( info instanceof ServletRequestAttributeListenerInfo )
-            {
-                this.listenerRegistry.removeListener((ServletRequestAttributeListenerInfo) info, handler);
-            }
-        }
-        catch (final RegistrationFailureException e)
-        {
-            serviceFailures.put(e.getInfo(), e.getErrorCode());
-            SystemLogger.error("Exception while removing servlet", e);
-        }
-        serviceFailures.remove(info);
-    }
-
-    private void removeFailure(AbstractInfo<?> info, int failureCode)
-    {
-        Integer registeredFailureCode = this.serviceFailures.get(info);
-        if (registeredFailureCode != null && registeredFailureCode == failureCode)
-        {
-            this.serviceFailures.remove(info);
-        }
-    }
-
-    /**
-     * Check whether the service is specifying a target http service runtime
-     * and if so if that is matching this runtime
-     */
-    private boolean isMatchingService(final AbstractInfo<?> info)
-    {
-        final String target = info.getTarget();
-        if ( target != null )
-        {
-            try
-            {
-                final Filter f = this.bundleContext.createFilter(target);
-                return f.match(this.httpServiceRuntime);
-            }
-            catch ( final InvalidSyntaxException ise)
-            {
-                // log and ignore service
-                SystemLogger.error("Invalid target filter expression for " + info.getServiceReference() + " : " + target, ise);
-                return false;
-            }
-        }
-        return true;
-    }
-
-    public ContextHandler getContextHandler(final Long contextId)
-    {
-        synchronized ( this.contextMap )
-        {
-            for(final List<ContextHandler> handlerList : this.contextMap.values())
-            {
-                final ContextHandler h = handlerList.get(0);
-                if ( h.getContextInfo().getServiceId() == contextId )
-                {
-                    return h;
-                }
-            }
-        }
-        return null;
-    }
-
-    public Collection<ContextHandler> getContextHandlers()
-    {
-         final List<ContextHandler> handlers = new ArrayList<ContextHandler>();
-         synchronized ( this.contextMap )
-         {
-             for(final List<ContextHandler> handlerList : this.contextMap.values())
-             {
-                 final ContextHandler h = handlerList.get(0);
-                 handlers.add(h);
-             }
-         }
-         return handlers;
-    }
-
-    public RegistryRuntime getRuntime(HandlerRegistry registry)
-    {
-        Collection<ServletContextHelperRuntime> contextRuntimes = new TreeSet<ServletContextHelperRuntime>(ServletContextHelperRuntime.COMPARATOR);
-        List<ContextRuntime> handlerRuntimes;
-        Map<Long, Collection<ServiceReference<?>>> listenerRuntimes;
-        FailureRuntime.Builder failureRuntime = FailureRuntime.builder();
-        synchronized ( this.contextMap )
-        {
-            for (List<ContextHandler> contextHandlerList : this.contextMap.values())
-            {
-                if ( !contextHandlerList.isEmpty() )
-                {
-                    contextRuntimes.add(contextHandlerList.get(0));
-                }
-            }
-            handlerRuntimes = registry.getRuntime(failureRuntime);
-            listenerRuntimes = listenerRegistry.getContextRuntimes();
-            failureRuntime.add(serviceFailures);
-        }
-        return new RegistryRuntime(contextRuntimes, handlerRuntimes, listenerRuntimes, failureRuntime.build());
-    }
-}
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 f750db2..82020a5 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
@@ -16,22 +16,77 @@
  */
 package org.apache.felix.http.base.internal.whiteboard;
 
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_UNKNOWN;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_VALIDATION_FAILED;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentSkipListMap;
 
 import javax.annotation.Nonnull;
 import javax.servlet.ServletContext;
+import javax.servlet.ServletContextListener;
 import javax.servlet.http.HttpSession;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
 import org.apache.felix.http.base.internal.handler.HttpSessionWrapper;
+import org.apache.felix.http.base.internal.logger.SystemLogger;
+import org.apache.felix.http.base.internal.runtime.AbstractInfo;
+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.ServletContextHelperInfo;
+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.runtime.WhiteboardServiceInfo;
+import org.apache.felix.http.base.internal.runtime.dto.ContextRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.FailureRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.RegistryRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.ServletContextHelperRuntime;
 import org.apache.felix.http.base.internal.service.HttpServiceFactory;
 import org.apache.felix.http.base.internal.service.HttpServiceRuntimeImpl;
+import org.apache.felix.http.base.internal.util.MimeTypes;
+import org.apache.felix.http.base.internal.whiteboard.tracker.FilterTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.HttpSessionAttributeListenerTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.HttpSessionListenerTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.ResourceTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.ServletContextAttributeListenerTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.ServletContextHelperTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.ServletContextListenerTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.ServletRequestAttributeListenerTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.ServletRequestListenerTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.ServletTracker;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.context.ServletContextHelper;
 import org.osgi.service.http.runtime.HttpServiceRuntime;
 import org.osgi.service.http.runtime.HttpServiceRuntimeConstants;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
+import org.osgi.util.tracker.ServiceTracker;
 
 public final class WhiteboardManager
 {
@@ -41,7 +96,25 @@
 
     private final HttpServiceRuntimeImpl serviceRuntime;
 
-    private final ServletContextHelperManager contextManager;
+    /** A map containing all servlet context registrations. Mapped by context name */
+    private final Map<String, List<ContextHandler>> contextMap = new HashMap<String, List<ContextHandler>>();
+
+    /** A map with all servlet/filter registrations, mapped by abstract info. */
+    private final Map<WhiteboardServiceInfo<?>, List<ContextHandler>> servicesMap = new HashMap<WhiteboardServiceInfo<?>, List<ContextHandler>>();
+
+    private final WhiteboardHttpService httpService;
+
+    private final ListenerRegistry listenerRegistry;
+
+    private final Map<AbstractInfo<?>, Integer> serviceFailures = new ConcurrentSkipListMap<AbstractInfo<?>, Integer>();
+
+    private volatile ServletContext webContext;
+
+    private volatile ServiceReference<HttpServiceRuntime> httpServiceRuntime;
+
+    private volatile ServiceRegistration<ServletContextHelper> defaultContextRegistration;
+
+    private final List<ServiceTracker<?, ?>> trackers = new ArrayList<ServiceTracker<?, ?>>();
 
     private volatile ServiceRegistration<HttpServiceRuntime> runtimeServiceReg;
 
@@ -57,8 +130,9 @@
     {
         this.bundleContext = bundleContext;
         this.httpServiceFactory = httpServiceFactory;
-        this.contextManager = new ServletContextHelperManager(bundleContext, registry);
-        this.serviceRuntime = new HttpServiceRuntimeImpl(registry, this.contextManager);
+        this.httpService = new WhiteboardHttpService(this.bundleContext, registry);
+        this.listenerRegistry = new ListenerRegistry(bundleContext.getBundle());
+        this.serviceRuntime = new HttpServiceRuntimeImpl(registry, this);
     }
 
     public void start(final ServletContext context)
@@ -70,12 +144,82 @@
                 serviceRuntime,
                 this.serviceRuntime.getAttributes());
 
-        this.contextManager.start(context, this.runtimeServiceReg.getReference());
+        this.webContext = webContext;
+        this.httpServiceRuntime = httpServiceRuntime;
+
+        final Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, HttpWhiteboardConstants.HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME);
+        props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, "/");
+        props.put(Constants.SERVICE_RANKING, Integer.MIN_VALUE);
+
+        this.defaultContextRegistration = bundleContext.registerService(
+                ServletContextHelper.class,
+                new ServiceFactory<ServletContextHelper>()
+                {
+
+                    @Override
+                    public ServletContextHelper getService(
+                            final Bundle bundle,
+                            final ServiceRegistration<ServletContextHelper> registration)
+                    {
+                        return new ServletContextHelper(bundle)
+                        {
+
+                            @Override
+                            public String getMimeType(final String file)
+                            {
+                                return MimeTypes.get().getByFile(file);
+                            }
+                        };
+                    }
+
+                    @Override
+                    public void ungetService(
+                            final Bundle bundle,
+                            final ServiceRegistration<ServletContextHelper> registration,
+                            final ServletContextHelper service)
+                    {
+                        // nothing to do
+                    }
+                }, props);
+        addTracker(new FilterTracker(this.bundleContext, this));
+        addTracker(new ServletTracker(this.bundleContext, this));
+        addTracker(new ResourceTracker(this.bundleContext, this));
+
+        addTracker(new HttpSessionListenerTracker(this.bundleContext, this));
+        addTracker(new HttpSessionAttributeListenerTracker(this.bundleContext, this));
+
+        addTracker(new ServletContextHelperTracker(this.bundleContext, this));
+        addTracker(new ServletContextListenerTracker(this.bundleContext, this));
+        addTracker(new ServletContextAttributeListenerTracker(this.bundleContext, this));
+
+        addTracker(new ServletRequestListenerTracker(this.bundleContext, this));
+        addTracker(new ServletRequestAttributeListenerTracker(this.bundleContext, this));
     }
 
+    private void addTracker(ServiceTracker<?, ?> tracker)
+    {
+        this.trackers.add(tracker);
+        tracker.open();
+    }
+
+    /**
+     * Stop the instance
+     */
     public void stop()
     {
-        this.contextManager.stop();
+        for(final ServiceTracker<?, ?> t : this.trackers)
+        {
+            t.close();
+        }
+        this.trackers.clear();
+
+        // TODO cleanup
+        if (this.defaultContextRegistration != null)
+        {
+            this.defaultContextRegistration.unregister();
+            this.defaultContextRegistration = null;
+        }
 
         if ( this.runtimeServiceReg != null )
         {
@@ -101,17 +245,473 @@
     {
         for(final Long contextId : contextIds)
         {
-            // TODO - on shutdown context manager is already NULL which shouldn't be the case
-            if ( this.contextManager != null )
+            final ContextHandler handler = this.getContextHandler(contextId);
+            if ( handler != null )
             {
-                final ContextHandler handler = this.contextManager.getContextHandler(contextId);
-                if ( handler != null )
+                final ExtServletContext context = handler.getServletContext(this.bundleContext.getBundle());
+                new HttpSessionWrapper(contextId, session, context, true).invalidate();
+                handler.ungetServletContext(this.bundleContext.getBundle());
+            }
+        }
+    }
+
+    /**
+     * Activate a servlet context helper.
+     * @param contextInfo A context info
+     */
+    private void activate(final ContextHandler handler)
+    {
+        handler.activate();
+
+        this.httpService.registerContext(handler);
+
+        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 ExtServletContext context = handler.getServletContext(this.bundleContext.getBundle());
-                    new HttpSessionWrapper(contextId, session, context, true).invalidate();
-                    handler.ungetServletContext(this.bundleContext.getBundle());
+                    final ServletContextListenerInfo info = (ServletContextListenerInfo)entry.getKey();
+                    listeners.put(info.getServiceReference(), info);
+                }
+                else
+                {
+                    services.add(entry.getKey());
+                }
+                removeFailure(entry.getKey(), FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
+            }
+        }
+        // context listeners first
+        for(final ServletContextListenerInfo info : listeners.values())
+        {
+            this.listenerRegistry.initialized(info, handler);
+        }
+        // now register services
+        for(final WhiteboardServiceInfo<?> info : services)
+        {
+            this.registerWhiteboardService(handler, info);
+        }
+    }
+
+    /**
+     * Deactivate a servlet context helper.
+     * @param contextInfo A context info
+     */
+    private void deactivate(final ContextHandler handler)
+    {
+        // context listeners last
+        final Map<ServiceReference<ServletContextListener>, ServletContextListenerInfo> listeners = new TreeMap<ServiceReference<ServletContextListener>, ServletContextListenerInfo>();
+        final Iterator<Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>>> i = this.servicesMap.entrySet().iterator();
+        while ( i.hasNext() )
+        {
+            final Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>> entry = i.next();
+            if ( entry.getValue().remove(handler) )
+            {
+                if ( entry.getKey() instanceof ServletContextListenerInfo )
+                {
+                    final ServletContextListenerInfo info = (ServletContextListenerInfo)entry.getKey();
+                    listeners.put(info.getServiceReference(), info);
+                }
+                else
+                {
+                    this.unregisterWhiteboardService(handler, entry.getKey());
                 }
             }
         }
+        for(final ServletContextListenerInfo info : listeners.values())
+        {
+            this.listenerRegistry.destroyed(info, handler);
+        }
+        handler.deactivate();
+
+        this.httpService.unregisterContext(handler);
+    }
+
+    /**
+     * Add a servlet context helper.
+     */
+    public void addContextHelper(final ServletContextHelperInfo info)
+    {
+        // no failure DTO and no logging if not matching
+        if ( isMatchingService(info) )
+        {
+            if ( info.isValid() )
+            {
+                synchronized ( this.contextMap )
+                {
+                    PerContextEventListener contextEventListener = listenerRegistry.addContext(info);
+                    ContextHandler handler = new ContextHandler(info,
+                            this.webContext,
+                            contextEventListener,
+                            this.bundleContext.getBundle());
+
+                    List<ContextHandler> handlerList = this.contextMap.get(info.getName());
+                    if ( handlerList == null )
+                    {
+                        handlerList = new ArrayList<ContextHandler>();
+                        this.contextMap.put(info.getName(), handlerList);
+                    }
+                    handlerList.add(handler);
+                    Collections.sort(handlerList);
+                    // check for activate/deactivate
+                    if ( handlerList.get(0) == handler )
+                    {
+                        // check for deactivate
+                        if ( handlerList.size() > 1 )
+                        {
+                            ContextHandler oldHead = handlerList.get(1);
+                            this.deactivate(oldHead);
+                            this.serviceFailures.put(oldHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                        }
+                        removeFailure(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                        this.activate(handler);
+                    }
+                    else
+                    {
+                        this.serviceFailures.put(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                    }
+                }
+            }
+            else
+            {
+                final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
+                SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
+                this.serviceFailures.put(info, FAILURE_REASON_VALIDATION_FAILED);
+            }
+        }
+    }
+
+    /**
+     * Remove a servlet context helper
+     */
+    public void removeContextHelper(final ServletContextHelperInfo info)
+    {
+        // no failure DTO and no logging if not matching
+        if ( isMatchingService(info) )
+        {
+            if ( info.isValid() )
+            {
+                synchronized ( this.contextMap )
+                {
+                    final List<ContextHandler> handlerList = this.contextMap.get(info.getName());
+                    if ( handlerList != null )
+                    {
+                        final Iterator<ContextHandler> i = handlerList.iterator();
+                        boolean first = true;
+                        boolean activateNext = false;
+                        while ( i.hasNext() )
+                        {
+                            final ContextHandler handler = i.next();
+                            if ( handler.getContextInfo().compareTo(info) == 0 )
+                            {
+                                i.remove();
+                                // check for deactivate
+                                if ( first )
+                                {
+                                    this.deactivate(handler);
+                                    activateNext = true;
+                                }
+                                break;
+                            }
+                            first = false;
+                        }
+                        if ( handlerList.isEmpty() )
+                        {
+                            this.contextMap.remove(info.getName());
+                        }
+                        else if ( activateNext )
+                        {
+                            ContextHandler newHead = handlerList.get(0);
+                            this.activate(newHead);
+                            removeFailure(newHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                        }
+                        listenerRegistry.removeContext(info);
+                    }
+                }
+            }
+            this.serviceFailures.remove(info);
+        }
+    }
+
+    /**
+     * Find the list of matching contexts for the whiteboard service
+     */
+    private List<ContextHandler> getMatchingContexts(final WhiteboardServiceInfo<?> info)
+    {
+        final List<ContextHandler> result = new ArrayList<ContextHandler>();
+        for(final List<ContextHandler> handlerList : this.contextMap.values()) {
+            final ContextHandler h = handlerList.get(0);
+            if ( info.getContextSelectionFilter().match(h.getContextInfo().getServiceReference()) )
+            {
+                result.add(h);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Add new whiteboard service to the registry
+     * @param info Whiteboard service info
+     */
+    public void addWhiteboardService(@Nonnull final WhiteboardServiceInfo<?> info)
+    {
+        // no logging and no DTO if other target service
+        if ( isMatchingService(info) )
+        {
+            if ( info.isValid() )
+            {
+                synchronized ( this.contextMap )
+                {
+                    final List<ContextHandler> handlerList = this.getMatchingContexts(info);
+                    this.servicesMap.put(info, handlerList);
+                    if (handlerList.isEmpty())
+                    {
+                        this.serviceFailures.put(info, FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
+                    }
+                    else
+                    {
+                        for(final ContextHandler h : handlerList)
+                        {
+                            this.registerWhiteboardService(h, info);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
+                SystemLogger.debug("Ignoring invalid " + type + " service " + info.getServiceReference());
+                this.serviceFailures.put(info, FAILURE_REASON_VALIDATION_FAILED);
+            }
+        }
+    }
+
+    /**
+     * Remove whiteboard service from the registry
+     * @param info Whiteboard service info
+     */
+    public void removeWhiteboardService(@Nonnull final WhiteboardServiceInfo<?> info)
+    {
+        // no logging and no DTO if other target service
+        if ( isMatchingService(info) ) {
+            if ( info.isValid() )
+            {
+                synchronized ( this.contextMap )
+                {
+                    final List<ContextHandler> handlerList = this.servicesMap.remove(info);
+                    if ( handlerList != null )
+                    {
+                        for(final ContextHandler h : handlerList)
+                        {
+                            this.unregisterWhiteboardService(h, info);
+                        }
+                    }
+                }
+            }
+            this.serviceFailures.remove(info);
+        }
+    }
+
+    /**
+     * Register whiteboard service in the http service
+     * @param handler Context handler
+     * @param info Whiteboard service info
+     */
+    private void registerWhiteboardService(final ContextHandler handler, final WhiteboardServiceInfo<?> info)
+    {
+        try
+        {
+            if ( info instanceof ServletInfo )
+            {
+                this.httpService.registerServlet(handler, (ServletInfo)info);
+            }
+            else if ( info instanceof FilterInfo )
+            {
+                this.httpService.registerFilter(handler, (FilterInfo)info);
+            }
+            else if ( info instanceof ResourceInfo )
+            {
+                this.httpService.registerResource(handler, (ResourceInfo)info);
+            }
+
+            else if ( info instanceof ServletContextAttributeListenerInfo )
+            {
+                this.listenerRegistry.addListener((ServletContextAttributeListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionListenerInfo )
+            {
+                this.listenerRegistry.addListener((HttpSessionListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionAttributeListenerInfo )
+            {
+                this.listenerRegistry.addListener((HttpSessionAttributeListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionIdListenerInfo )
+            {
+                this.listenerRegistry.addListener((HttpSessionIdListenerInfo) info, handler);
+            }
+            else if ( info instanceof ServletRequestListenerInfo )
+            {
+                this.listenerRegistry.addListener((ServletRequestListenerInfo) info, handler);
+            }
+            else if ( info instanceof ServletRequestAttributeListenerInfo )
+            {
+                this.listenerRegistry.addListener((ServletRequestAttributeListenerInfo) info, handler);
+            }
+        }
+        catch (final RegistrationFailureException e)
+        {
+            serviceFailures.put(e.getInfo(), e.getErrorCode());
+            SystemLogger.error("Exception while registering whiteboard service " + info.getServiceReference(), e);
+        }
+        catch (final RuntimeException e)
+        {
+            serviceFailures.put(info, FAILURE_REASON_UNKNOWN);
+            SystemLogger.error("Exception while registering whiteboard service " + info.getServiceReference(), e);
+        }
+    }
+
+    /**
+     * Unregister whiteboard service from the http service
+     * @param handler Context handler
+     * @param info Whiteboard service info
+     */
+    private void unregisterWhiteboardService(final ContextHandler handler, final WhiteboardServiceInfo<?> info)
+    {
+        try
+        {
+            if ( info instanceof ServletInfo )
+            {
+                this.httpService.unregisterServlet(handler, (ServletInfo)info);
+            }
+            else if ( info instanceof FilterInfo )
+            {
+                this.httpService.unregisterFilter(handler, (FilterInfo)info);
+            }
+            else if ( info instanceof ResourceInfo )
+            {
+                this.httpService.unregisterResource(handler, (ResourceInfo)info);
+            }
+
+            else if ( info instanceof ServletContextAttributeListenerInfo )
+            {
+                this.listenerRegistry.removeListener((ServletContextAttributeListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionListenerInfo )
+            {
+                this.listenerRegistry.removeListener((HttpSessionListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionAttributeListenerInfo )
+            {
+                this.listenerRegistry.removeListener((HttpSessionAttributeListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionIdListenerInfo )
+            {
+                this.listenerRegistry.removeListener((HttpSessionIdListenerInfo) info, handler);
+            }
+            else if ( info instanceof ServletRequestListenerInfo )
+            {
+                this.listenerRegistry.removeListener((ServletRequestListenerInfo) info, handler);
+            }
+            else if ( info instanceof ServletRequestAttributeListenerInfo )
+            {
+                this.listenerRegistry.removeListener((ServletRequestAttributeListenerInfo) info, handler);
+            }
+        }
+        catch (final RegistrationFailureException e)
+        {
+            serviceFailures.put(e.getInfo(), e.getErrorCode());
+            SystemLogger.error("Exception while removing servlet", e);
+        }
+        serviceFailures.remove(info);
+    }
+
+    private void removeFailure(AbstractInfo<?> info, int failureCode)
+    {
+        Integer registeredFailureCode = this.serviceFailures.get(info);
+        if (registeredFailureCode != null && registeredFailureCode == failureCode)
+        {
+            this.serviceFailures.remove(info);
+        }
+    }
+
+    /**
+     * Check whether the service is specifying a target http service runtime
+     * and if so if that is matching this runtime
+     */
+    private boolean isMatchingService(final AbstractInfo<?> info)
+    {
+        final String target = info.getTarget();
+        if ( target != null )
+        {
+            try
+            {
+                final Filter f = this.bundleContext.createFilter(target);
+                return f.match(this.httpServiceRuntime);
+            }
+            catch ( final InvalidSyntaxException ise)
+            {
+                // log and ignore service
+                SystemLogger.error("Invalid target filter expression for " + info.getServiceReference() + " : " + target, ise);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public ContextHandler getContextHandler(final Long contextId)
+    {
+        synchronized ( this.contextMap )
+        {
+            for(final List<ContextHandler> handlerList : this.contextMap.values())
+            {
+                final ContextHandler h = handlerList.get(0);
+                if ( h.getContextInfo().getServiceId() == contextId )
+                {
+                    return h;
+                }
+            }
+        }
+        return null;
+    }
+
+    public Collection<ContextHandler> getContextHandlers()
+    {
+         final List<ContextHandler> handlers = new ArrayList<ContextHandler>();
+         synchronized ( this.contextMap )
+         {
+             for(final List<ContextHandler> handlerList : this.contextMap.values())
+             {
+                 final ContextHandler h = handlerList.get(0);
+                 handlers.add(h);
+             }
+         }
+         return handlers;
+    }
+
+    public RegistryRuntime getRuntime(HandlerRegistry registry)
+    {
+        Collection<ServletContextHelperRuntime> contextRuntimes = new TreeSet<ServletContextHelperRuntime>(ServletContextHelperRuntime.COMPARATOR);
+        List<ContextRuntime> handlerRuntimes;
+        Map<Long, Collection<ServiceReference<?>>> listenerRuntimes;
+        FailureRuntime.Builder failureRuntime = FailureRuntime.builder();
+        synchronized ( this.contextMap )
+        {
+            for (List<ContextHandler> contextHandlerList : this.contextMap.values())
+            {
+                if ( !contextHandlerList.isEmpty() )
+                {
+                    contextRuntimes.add(contextHandlerList.get(0));
+                }
+            }
+            handlerRuntimes = registry.getRuntime(failureRuntime);
+            listenerRuntimes = listenerRegistry.getContextRuntimes();
+            failureRuntime.add(serviceFailures);
+        }
+        return new RegistryRuntime(contextRuntimes, handlerRuntimes, listenerRuntimes, failureRuntime.build());
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/FilterTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/FilterTracker.java
index 5f594bb..3a10f33 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/FilterTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/FilterTracker.java
@@ -20,14 +20,14 @@
 
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
 public final class FilterTracker extends WhiteboardServiceTracker<Filter>
 {
-    public FilterTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public FilterTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, String.format("(&(objectClass=%s)(|(%s=*)(%s=*)(%s=*)))",
                 Filter.class.getName(),
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionAttributeListenerTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionAttributeListenerTracker.java
index 0971399..64f2003 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionAttributeListenerTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionAttributeListenerTracker.java
@@ -20,13 +20,13 @@
 
 import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
 public final class HttpSessionAttributeListenerTracker extends WhiteboardServiceTracker<HttpSessionAttributeListener>
 {
-    public HttpSessionAttributeListenerTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public HttpSessionAttributeListenerTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, createListenerFilterExpression(HttpSessionAttributeListener.class));
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionIdListenerTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionIdListenerTracker.java
index 894e2a8..1256862 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionIdListenerTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionIdListenerTracker.java
@@ -20,13 +20,13 @@
 
 import org.apache.felix.http.base.internal.runtime.HttpSessionIdListenerInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
 public final class HttpSessionIdListenerTracker extends WhiteboardServiceTracker<HttpSessionIdListener>
 {
-    public HttpSessionIdListenerTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public HttpSessionIdListenerTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, createListenerFilterExpression(HttpSessionIdListener.class));
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionListenerTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionListenerTracker.java
index bf70059..cc351fa 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionListenerTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/HttpSessionListenerTracker.java
@@ -20,13 +20,13 @@
 
 import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
 public final class HttpSessionListenerTracker extends WhiteboardServiceTracker<HttpSessionListener>
 {
-    public HttpSessionListenerTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public HttpSessionListenerTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, createListenerFilterExpression(HttpSessionListener.class));
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ResourceTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ResourceTracker.java
index 4c22004..e902d06 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ResourceTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ResourceTracker.java
@@ -18,14 +18,14 @@
 
 import org.apache.felix.http.base.internal.runtime.ResourceInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
 public final class ResourceTracker extends WhiteboardServiceTracker<Object>
 {
-    public ResourceTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public ResourceTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, String.format("(&(%s=*)(%s=*))",
                 HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN,
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextAttributeListenerTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextAttributeListenerTracker.java
index a64e6d2..f0edbf2 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextAttributeListenerTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextAttributeListenerTracker.java
@@ -20,13 +20,13 @@
 
 import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
 public final class ServletContextAttributeListenerTracker extends WhiteboardServiceTracker<ServletContextAttributeListener>
 {
-    public ServletContextAttributeListenerTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public ServletContextAttributeListenerTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, createListenerFilterExpression(ServletContextAttributeListener.class));
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
index 3818437..6b5fe65 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
@@ -19,7 +19,7 @@
 import javax.annotation.Nonnull;
 
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
@@ -31,7 +31,7 @@
  */
 public final class ServletContextHelperTracker extends ServiceTracker<ServletContextHelper, ServiceReference<ServletContextHelper>>
 {
-    private final ServletContextHelperManager contextManager;
+    private final WhiteboardManager contextManager;
 
     private static org.osgi.framework.Filter createFilter(final BundleContext btx)
     {
@@ -47,7 +47,7 @@
         return null; // we never get here - and if we get an NPE which is fine
     }
 
-    public ServletContextHelperTracker(@Nonnull final BundleContext context, @Nonnull final ServletContextHelperManager manager)
+    public ServletContextHelperTracker(@Nonnull final BundleContext context, @Nonnull final WhiteboardManager manager)
     {
         super(context, createFilter(context), null);
         this.contextManager = manager;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextListenerTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextListenerTracker.java
index 618902b..bc48043 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextListenerTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextListenerTracker.java
@@ -20,13 +20,13 @@
 
 import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
 public final class ServletContextListenerTracker extends WhiteboardServiceTracker<ServletContextListener>
 {
-    public ServletContextListenerTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public ServletContextListenerTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, createListenerFilterExpression(ServletContextListener.class));
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletRequestAttributeListenerTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletRequestAttributeListenerTracker.java
index 42cb1c3..1931d3a 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletRequestAttributeListenerTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletRequestAttributeListenerTracker.java
@@ -20,13 +20,13 @@
 
 import org.apache.felix.http.base.internal.runtime.ServletRequestAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
 public final class ServletRequestAttributeListenerTracker extends WhiteboardServiceTracker<ServletRequestAttributeListener>
 {
-    public ServletRequestAttributeListenerTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public ServletRequestAttributeListenerTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, createListenerFilterExpression(ServletRequestAttributeListener.class));
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletRequestListenerTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletRequestListenerTracker.java
index 40343bc..e7c2eca 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletRequestListenerTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletRequestListenerTracker.java
@@ -20,13 +20,13 @@
 
 import org.apache.felix.http.base.internal.runtime.ServletRequestListenerInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
 public final class ServletRequestListenerTracker extends WhiteboardServiceTracker<ServletRequestListener>
 {
-    public ServletRequestListenerTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public ServletRequestListenerTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, createListenerFilterExpression(ServletRequestListener.class));
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletTracker.java
index 4088432..ea7bfe0 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletTracker.java
@@ -20,14 +20,14 @@
 
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
 public final class ServletTracker extends WhiteboardServiceTracker<Servlet>
 {
-    public ServletTracker(final BundleContext context, final ServletContextHelperManager manager)
+    public ServletTracker(final BundleContext context, final WhiteboardManager manager)
     {
         super(manager, context, String.format("(&(objectClass=%s)(|(%s=*)(%s=*)))",
                 Servlet.class.getName(),
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
index 8a2c515..ba3c72c 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
@@ -17,7 +17,7 @@
 package org.apache.felix.http.base.internal.whiteboard.tracker;
 
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
-import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
+import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
@@ -56,8 +56,8 @@
         return null; // we never get here - and if we get an NPE which is fine
     }
 
-    /** The context manager is called for each added/removed reference. */
-    private final ServletContextHelperManager contextManager;
+    /** The  manager is called for each added/removed reference. */
+    private final WhiteboardManager contextManager;
 
     /**
      * Create a new tracker
@@ -65,7 +65,7 @@
      * @param bundleContext The bundle context.
      * @param filterExpr The filter expression for the services to track
      */
-    public WhiteboardServiceTracker(final ServletContextHelperManager contextManager,
+    public WhiteboardServiceTracker(final WhiteboardManager contextManager,
             final BundleContext bundleContext, final String filterExpr)
     {
         super(bundleContext, createFilter(bundleContext, filterExpr), null);