FELIX-4904 : Provide a way to associate whiteboard services with the default context of the http service

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1682004 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
index 9f54123..2f72fd8 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
@@ -34,6 +34,8 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
 import javax.servlet.AsyncContext;
 import javax.servlet.DispatcherType;
 import javax.servlet.FilterChain;
@@ -56,6 +58,7 @@
 import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.registry.HandlerRegistry;
 import org.apache.felix.http.base.internal.registry.PathResolution;
+import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
 import org.apache.felix.http.base.internal.registry.ServletResolution;
 import org.apache.felix.http.base.internal.util.UriUtils;
 import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
@@ -133,25 +136,19 @@
 
         private final AtomicInteger invocationCount = new AtomicInteger();
 
-        private final Long serviceId;
+        private final PerContextHandlerRegistry errorRegistry;
 
         private final String servletName;
 
-        public ServletResponseWrapper(final HttpServletRequest req, final HttpServletResponse res,
-                final ServletHandler servletHandler)
+        public ServletResponseWrapper(@Nonnull final HttpServletRequest req,
+                @Nonnull final HttpServletResponse res,
+                @CheckForNull final String servletName,
+                @CheckForNull final PerContextHandlerRegistry errorRegistry)
         {
             super(res);
             this.request = req;
-            if ( servletHandler != null )
-            {
-                this.serviceId = servletHandler.getContextServiceId();
-                this.servletName = servletHandler.getName();
-            }
-            else
-            {
-                this.serviceId = null;
-                this.servletName = null;
-            }
+            this.servletName = servletName;
+            this.errorRegistry = errorRegistry;
         }
 
         @Override
@@ -178,7 +175,8 @@
                     code >= SC_OK)
                 {
                     final Throwable exception = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
-                    final ServletResolution errorResolution = handlerRegistry.getErrorHandler(request.getRequestURI(), this.serviceId, code, exception);
+                    final ServletHandler errorResolution = (errorRegistry == null ? null :
+                            errorRegistry.getErrorHandler(code, exception));
 
                     if ( errorResolution != null )
                     {
@@ -201,10 +199,10 @@
 
                             final RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString);
 
-                            final FilterHandler[] filterHandlers = handlerRegistry.getFilters(errorResolution, DispatcherType.ERROR, request.getRequestURI());
+                            final FilterHandler[] filterHandlers = errorRegistry.getFilterHandlers(errorResolution, DispatcherType.ERROR, request.getRequestURI());
 
                             // TODO - is async = false correct?
-                            invokeChain(errorResolution.handler, filterHandlers, new ServletRequestWrapper(request, errorResolution.handler.getContext(), requestInfo, this.serviceId, false), this);
+                            invokeChain(errorResolution, filterHandlers, new ServletRequestWrapper(request, errorResolution.getContext(), requestInfo, errorResolution.getContextServiceId(), false), this);
 
                             invokeSuper = false;
                         }
@@ -236,10 +234,10 @@
         private final DispatcherType type;
         private final RequestInfo requestInfo;
         private final ExtServletContext servletContext;
-        private final Long contextId;
+        private final long contextId;
         private final boolean asyncSupported;
 
-        public ServletRequestWrapper(HttpServletRequest req, ExtServletContext servletContext, RequestInfo requestInfo, final Long contextId,
+        public ServletRequestWrapper(HttpServletRequest req, ExtServletContext servletContext, RequestInfo requestInfo, final long contextId,
                 final boolean asyncSupported)
         {
             this(req, servletContext, requestInfo, null /* type */, contextId, asyncSupported);
@@ -370,10 +368,6 @@
         @Override
         public RequestDispatcher getRequestDispatcher(String path)
         {
-            if ( this.contextId == null )
-            {
-                return null;
-            }
             // See section 9.1 of Servlet 3.0 specification...
             if (path == null)
             {
@@ -592,8 +586,9 @@
         // Determine which servlet we should forward the request to...
         final PathResolution pr = this.handlerRegistry.resolveServlet(requestURI);
 
-        final HttpServletResponse wrappedResponse = new ServletResponseWrapper(req, res,
-                pr == null ? null : pr.handler);
+        final PerContextHandlerRegistry errorRegistry = (pr != null ? pr.handlerRegistry : this.handlerRegistry.getBestMatchingRegistry(requestURI));
+        final String servletName = (pr != null ? pr.handler.getName() : null);
+        final HttpServletResponse wrappedResponse = new ServletResponseWrapper(req, res, servletName, errorRegistry);
         if ( pr == null )
         {
             wrappedResponse.sendError(404);
@@ -634,14 +629,14 @@
     }
 
     @Override
-    public RequestDispatcher getNamedDispatcher(final Long contextId, final String name)
+    public RequestDispatcher getNamedDispatcher(final long contextId, final String name)
     {
         final ServletResolution resolution = this.handlerRegistry.resolveServletByName(contextId, name);
         return resolution != null ? new RequestDispatcherImpl(resolution, null) : null;
     }
 
     @Override
-    public RequestDispatcher getRequestDispatcher(final Long contextId, String path)
+    public RequestDispatcher getRequestDispatcher(final long contextId, String path)
     {
         // See section 9.1 of Servlet 3.x specification...
         if (path == null || (!path.startsWith("/") && !"".equals(path)))
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java
index abbc165..45fab9f 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java
@@ -27,10 +27,10 @@
     /**
      * @see ServletContext#getNamedDispatcher(String)
      */
-    RequestDispatcher getNamedDispatcher(Long contextId, String name);
+    RequestDispatcher getNamedDispatcher(long contextId, String name);
 
     /**
      * @see ServletContext#getRequestDispatcher(String)
      */
-    RequestDispatcher getRequestDispatcher(Long contextId, String path);
+    RequestDispatcher getRequestDispatcher(long contextId, String path);
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java
index b47ece9..882e102 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java
@@ -28,12 +28,12 @@
 {
     private final RequestDispatcherProvider provider;
 
-    private final Long contextId;
+    private final long contextId;
 
     /**
      * Creates a new {@link ServletContextWrapper} instance.
      */
-    public ServletContextWrapper(final Long contextId, final ExtServletContext delegate, final RequestDispatcherProvider provider)
+    public ServletContextWrapper(final long contextId, final ExtServletContext delegate, final RequestDispatcherProvider provider)
     {
         super(delegate);
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ContextHandler.java
deleted file mode 100644
index 15c77a8..0000000
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ContextHandler.java
+++ /dev/null
@@ -1,28 +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.handler;
-
-import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
-import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
-
-public interface ContextHandler
-{
-
-    ServletContextHelperInfo getContextInfo();
-
-    PerContextHandlerRegistry getRegistry();
-}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
index 3b58884..9761f56 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
@@ -35,7 +35,6 @@
 import javax.servlet.http.HttpSessionEvent;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
-import org.apache.felix.http.base.internal.service.HttpServiceFactory;
 
 /**
  * The session wrapper keeps track of the internal session, manages their attributes
@@ -87,9 +86,9 @@
      */
     private final boolean isNew;
 
-    public static boolean hasSession(final Long contextId, final HttpSession session)
+    public static boolean hasSession(final long contextId, final HttpSession session)
     {
-        final String sessionId = contextId == null ? String.valueOf(HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID) : String.valueOf(contextId);
+        final String sessionId = String.valueOf(contextId);
         return session.getAttribute(ATTR_CREATED + sessionId) != null;
     }
 
@@ -136,15 +135,15 @@
     /**
      * Creates a new {@link HttpSessionWrapper} instance.
      */
-    public HttpSessionWrapper(final Long contextId,
+    public HttpSessionWrapper(final long contextId,
             final HttpSession session,
             final ExtServletContext context,
             final boolean terminate)
     {
         this.delegate = session;
         this.context = context;
-        this.sessionId = contextId == null ? String.valueOf(HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID) : String.valueOf(contextId);
-        this.keyPrefix = contextId == null ? null : ATTR_PREFIX + this.sessionId + ".";
+        this.sessionId = String.valueOf(contextId);
+        this.keyPrefix = ATTR_PREFIX + this.sessionId + ".";
 
         if ( this.keyPrefix != null )
         {
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 e419cac..237855e 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
@@ -21,6 +21,7 @@
 import java.util.Iterator;
 import java.util.List;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.servlet.DispatcherType;
 
@@ -123,7 +124,10 @@
         return null;
     }
 
-    public ServletResolution getErrorHandler(String requestURI, Long serviceId, int code, Throwable exception)
+    public @CheckForNull ServletResolution getErrorHandler(@Nonnull final String requestURI,
+            final Long serviceId,
+            final int code,
+            final Throwable exception)
     {
         final PerContextHandlerRegistry reg;
         if ( serviceId == null )
@@ -229,4 +233,21 @@
         }
         return false;
     }
+
+    public PerContextHandlerRegistry getBestMatchingRegistry(String requestURI)
+    {
+        // if the context is unknown, we use the first matching one!
+        PerContextHandlerRegistry found = null;
+        final List<PerContextHandlerRegistry> regs = this.registrations;
+        for(final PerContextHandlerRegistry r : regs)
+        {
+            final String path = r.isMatching(requestURI);
+            if ( path != null )
+            {
+                found = r;
+                break;
+            }
+        }
+        return found;
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java
index 2766c61..8bcd270 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextHelperInfo.java
@@ -21,6 +21,7 @@
 import java.util.Collections;
 import java.util.Map;
 
+import org.apache.felix.http.base.internal.service.HttpServiceFactory;
 import org.apache.felix.http.base.internal.util.PatternUtil;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.context.ServletContextHelper;
@@ -88,6 +89,7 @@
     {
         return super.isValid()
                 && PatternUtil.isValidSymbolicName(this.name)
+                && !HttpServiceFactory.HTTP_SERVICE_CONTEXT_NAME.equals(this.name)
                 && isValidPath();
     }
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
index 5870c09..b2734d5 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
@@ -286,7 +286,7 @@
         }
     }
 
-    private ExtServletContext getServletContext(HttpContext context)
+    public ExtServletContext getServletContext(HttpContext context)
     {
         if (context == null)
         {
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpServiceContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpServiceContextHandler.java
index 526e4ac..11b5d1f 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpServiceContextHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpServiceContextHandler.java
@@ -16,45 +16,41 @@
  */
 package org.apache.felix.http.base.internal.whiteboard;
 
+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.handler.ContextHandler;
 import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+import org.apache.felix.http.base.internal.service.HttpServiceFactory;
+import org.apache.felix.http.base.internal.service.PerBundleHttpServiceImpl;
 import org.osgi.framework.Bundle;
 
-public class HttpServiceContextHandler implements ContextHandler, Comparable<ContextHandler>
+public class HttpServiceContextHandler extends WhiteboardContextHandler
 {
-    /** The info object for the context. */
-    private final ServletContextHelperInfo info;
-
     private final PerContextHandlerRegistry registry;
 
-    private final ExtServletContext webContext;
+    private final HttpServiceFactory httpServiceFactory;
 
-    /** The http bundle. */
-    private final Bundle httpBundle;
+    /** 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 ServletContext sharedContext;
 
     public HttpServiceContextHandler(final ServletContextHelperInfo info,
             final PerContextHandlerRegistry registry,
-            final ExtServletContext webContext,
+            final HttpServiceFactory httpServiceFactory,
+            final ServletContext webContext,
             final Bundle httpBundle)
     {
-        this.info = info;
+        super(info, webContext, httpBundle);
         this.registry = registry;
-        this.webContext = webContext;
-        this.httpBundle = httpBundle;
-    }
-
-    @Override
-    public ServletContextHelperInfo getContextInfo()
-    {
-        return this.info;
-    }
-
-    @Override
-    public int compareTo(final ContextHandler o)
-    {
-        return this.info.compareTo(o.getContextInfo());
+        this.httpServiceFactory = httpServiceFactory;
+        this.sharedContext = webContext;
     }
 
     @Override
@@ -62,4 +58,61 @@
     {
         return this.registry;
     }
+
+    @Override
+    public ServletContext getSharedContext()
+    {
+        return this.sharedContext;
+    }
+
+    @Override
+    public @CheckForNull ExtServletContext getServletContext(@CheckForNull final Bundle bundle)
+    {
+        if ( bundle == null )
+        {
+            return null;
+        }
+        final Long key = bundle.getBundleId();
+        synchronized ( this.perBundleContextMap )
+        {
+            ContextHolder holder = this.perBundleContextMap.get(key);
+            if ( holder == null )
+            {
+                holder = new ContextHolder();
+                final PerBundleHttpServiceImpl service = (PerBundleHttpServiceImpl)this.httpServiceFactory.getService(bundle, null);
+                holder.servletContext = service.getServletContext(service.createDefaultHttpContext());
+                holder.httpService = service;
+                this.perBundleContextMap.put(key, holder);
+            }
+            holder.counter++;
+
+            return holder.servletContext;
+        }
+    }
+
+    @Override
+    public void ungetServletContext(@Nonnull final Bundle bundle)
+    {
+        final Long key = bundle.getBundleId();
+        synchronized ( this.perBundleContextMap )
+        {
+            ContextHolder holder = this.perBundleContextMap.get(key);
+            if ( holder != null )
+            {
+                holder.counter--;
+                if ( holder.counter == 0 )
+                {
+                    this.perBundleContextMap.remove(key);
+                    holder.httpService.unregisterAll();
+                }
+            }
+        }
+    }
+
+    private static final class ContextHolder
+    {
+        public long counter;
+        public ExtServletContext servletContext;
+        public PerBundleHttpServiceImpl httpService;
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
index 5bedf51..30400a6 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
@@ -24,28 +24,16 @@
 import javax.servlet.ServletContext;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
-import org.apache.felix.http.base.internal.handler.ContextHandler;
-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.ListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
-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.service.ResourceServlet;
+import org.apache.felix.http.base.internal.service.HttpServiceFactory;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceObjects;
 import org.osgi.service.http.context.ServletContextHelper;
 
-public final class WhiteboardContextHandler implements ContextHandler, Comparable<ContextHandler>
+public class WhiteboardContextHandler implements Comparable<WhiteboardContextHandler>
 {
     /** The info object for the context. */
     private final ServletContextHelperInfo info;
@@ -77,15 +65,26 @@
         return this.httpBundle.getBundleContext();
     }
 
-    @Override
     public ServletContextHelperInfo getContextInfo()
     {
         return this.info;
     }
 
     @Override
-    public int compareTo(final ContextHandler o)
+    public int compareTo(final WhiteboardContextHandler o)
     {
+        if ( this.info.getName().equals(HttpServiceFactory.HTTP_SERVICE_CONTEXT_NAME) )
+        {
+            if ( o.info.getName().equals(HttpServiceFactory.HTTP_SERVICE_CONTEXT_NAME) )
+            {
+                return 0;
+            }
+            return -1;
+        }
+        if ( o.info.getName().equals(HttpServiceFactory.HTTP_SERVICE_CONTEXT_NAME) )
+        {
+            return 1;
+        }
         return this.info.compareTo(o.getContextInfo());
     }
 
@@ -196,81 +195,9 @@
         }
     }
 
-    /**
-     * Create a servlet handler
-     * @param servletInfo The servlet info
-     * @return {@code null} if the servlet context could not be created, a handler otherwise
-     */
-    public ServletHandler getServletContextAndCreateServletHandler(@Nonnull final ServletInfo servletInfo)
+    public PerContextHandlerRegistry getRegistry()
     {
-        final ExtServletContext servletContext = this.getServletContext(servletInfo.getServiceReference().getBundle());
-        if ( servletContext == null )
-        {
-            return null;
-        }
-        final ServletHandler handler;
-        if ( servletInfo.isResource() )
-        {
-            handler = new HttpServiceServletHandler(
-                    this.info.getServiceId(),
-                    servletContext,
-                    servletInfo,
-                    new ResourceServlet(servletInfo.getPrefix()));
-        }
-        else
-        {
-            handler = new WhiteboardServletHandler(
-                this.info.getServiceId(),
-                servletContext,
-                servletInfo,
-                this.httpBundle.getBundleContext());
-        }
-        return handler;
-    }
-
-    /**
-     * Create a filter handler
-     * @param info The filter info
-     * @return {@code null} if the servlet context could not be created, a handler otherwise
-     */
-    public FilterHandler getServletContextAndCreateFilterHandler(@Nonnull final FilterInfo info)
-    {
-        final ExtServletContext servletContext = this.getServletContext(info.getServiceReference().getBundle());
-        if ( servletContext == null )
-        {
-            return null;
-        }
-        final FilterHandler handler = new WhiteboardFilterHandler(
-                this.info.getServiceId(),
-                servletContext,
-                info,
-                this.httpBundle.getBundleContext());
-        return handler;
-    }
-
-    /**
-     * Create a listener handler
-     * @param info The listener info
-     * @return {@code null} if the servlet context could not be created, a handler otherwise
-     */
-    public ListenerHandler getServletContextAndCreateListenerHandler(@Nonnull final ListenerInfo info)
-    {
-        final ExtServletContext servletContext = this.getServletContext(info.getServiceReference().getBundle());
-        if ( servletContext == null )
-        {
-            return null;
-        }
-        final ListenerHandler handler = new WhiteboardListenerHandler(
-                this.info.getServiceId(),
-                servletContext,
-                info,
-                this.httpBundle.getBundleContext());
-        return handler;
-    }
-
-    public void ungetServletContext(@Nonnull final WhiteboardServiceInfo<?> info)
-    {
-        this.ungetServletContext(info.getServiceReference().getBundle());
+        return this.registry;
     }
 
     private static final class ContextHolder
@@ -279,10 +206,4 @@
         public ExtServletContext servletContext;
         public ServletContextHelper servletContextHelper;
     }
-
-    @Override
-    public PerContextHandlerRegistry getRegistry()
-    {
-        return this.registry;
-    }
 }
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 4f9ee7d..20f3e40 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
@@ -42,9 +42,13 @@
 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.FilterHandler;
+import org.apache.felix.http.base.internal.handler.HttpServiceServletHandler;
 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.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.logger.SystemLogger;
 import org.apache.felix.http.base.internal.registry.HandlerRegistry;
 import org.apache.felix.http.base.internal.runtime.AbstractInfo;
@@ -59,6 +63,7 @@
 import org.apache.felix.http.base.internal.runtime.dto.ServletContextDTOBuilder;
 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.service.ResourceServlet;
 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.ListenersTracker;
@@ -142,6 +147,15 @@
         props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, "/");
         props.put(Constants.SERVICE_RANKING, Integer.MIN_VALUE);
 
+        // add context for http service
+        final List<WhiteboardContextHandler> list = new ArrayList<WhiteboardContextHandler>();
+        final ServletContextHelperInfo info = new ServletContextHelperInfo(Integer.MAX_VALUE,
+                HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID,
+                HttpServiceFactory.HTTP_SERVICE_CONTEXT_NAME, "/", null);
+        list.add(new HttpServiceContextHandler(info, registry.getRegistry(HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID),
+                httpServiceFactory, webContext, this.httpBundleContext.getBundle()));
+        this.contextMap.put(HttpServiceFactory.HTTP_SERVICE_CONTEXT_NAME, list);
+
         this.defaultContextRegistration = httpBundleContext.registerService(
                 ServletContextHelper.class,
                 new ServiceFactory<ServletContextHelper>()
@@ -521,9 +535,25 @@
                     // we ignore this and treat it as an invisible service
                 }
             }
-            if ( visible && info.getContextSelectionFilter().match(h.getContextInfo().getServiceReference()) )
+            if ( visible )
             {
-                result.add(h);
+                if ( h.getContextInfo().getServiceReference() != null )
+                {
+                    if ( info.getContextSelectionFilter().match(h.getContextInfo().getServiceReference()) )
+                    {
+                        result.add(h);
+                    }
+                }
+                else
+                {
+                    final Map<String, String> props = new HashMap<String, String>();
+                    props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, h.getContextInfo().getName());
+                    props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, h.getContextInfo().getPath());
+                    if ( info.getContextSelectionFilter().matches(props) )
+                    {
+                        result.add(h);
+                    }
+                }
             }
         }
         return result;
@@ -635,52 +665,71 @@
             int failureCode = -1;
             if ( info instanceof ServletInfo )
             {
-                final ServletHandler servletHandler = handler.getServletContextAndCreateServletHandler((ServletInfo)info);
-                if ( servletHandler == null )
+                final ExtServletContext servletContext = handler.getServletContext(info.getServiceReference().getBundle());
+                if ( servletContext == null )
                 {
                     failureCode = DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
                 }
                 else
                 {
+                    final ServletHandler servletHandler = new WhiteboardServletHandler(
+                        handler.getContextInfo().getServiceId(),
+                        servletContext,
+                        (ServletInfo)info,
+                        handler.getBundleContext());
                     handler.getRegistry().registerServlet(servletHandler);
                 }
             }
             else if ( info instanceof FilterInfo )
             {
-                final FilterHandler filterHandler = handler.getServletContextAndCreateFilterHandler((FilterInfo)info);
-                if ( filterHandler == null )
+                final ExtServletContext servletContext = handler.getServletContext(info.getServiceReference().getBundle());
+                if ( servletContext == null )
                 {
                     failureCode = DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
                 }
                 else
                 {
+                    final FilterHandler filterHandler = new WhiteboardFilterHandler(
+                            handler.getContextInfo().getServiceId(),
+                            servletContext,
+                            (FilterInfo)info,
+                            handler.getBundleContext());
                     handler.getRegistry().registerFilter(filterHandler);
                 }
             }
             else if ( info instanceof ResourceInfo )
             {
                 final ServletInfo servletInfo = new ServletInfo((ResourceInfo)info);
-
-                final ServletHandler servleHandler = handler.getServletContextAndCreateServletHandler(servletInfo);
-                if ( servleHandler == null )
+                final ExtServletContext servletContext = handler.getServletContext(info.getServiceReference().getBundle());
+                if ( servletContext == null )
                 {
                     failureCode = DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
                 }
                 else
                 {
+                    final ServletHandler servleHandler = new HttpServiceServletHandler(
+                            handler.getContextInfo().getServiceId(),
+                            servletContext,
+                            servletInfo,
+                            new ResourceServlet(servletInfo.getPrefix()));
                     handler.getRegistry().registerServlet(servleHandler);
                 }
             }
 
             else if ( info instanceof ListenerInfo )
             {
-                final ListenerHandler listenerHandler = handler.getServletContextAndCreateListenerHandler((ListenerInfo)info);
-                if ( listenerHandler == null )
+                final ExtServletContext servletContext = handler.getServletContext(info.getServiceReference().getBundle());
+                if ( servletContext == null )
                 {
                     failureCode = DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
                 }
                 else
                 {
+                    final ListenerHandler listenerHandler = new WhiteboardListenerHandler(
+                            handler.getContextInfo().getServiceId(),
+                            servletContext,
+                            (ListenerInfo)info,
+                            handler.getBundleContext());
                     handler.getRegistry().registerListeners(listenerHandler);
                 }
             }
@@ -715,23 +764,23 @@
             if ( info instanceof ServletInfo )
             {
                 handler.getRegistry().unregisterServlet((ServletInfo)info, true);
-                handler.ungetServletContext(info);
+                handler.ungetServletContext(info.getServiceReference().getBundle());
             }
             else if ( info instanceof FilterInfo )
             {
                 handler.getRegistry().unregisterFilter((FilterInfo)info, true);
-                handler.ungetServletContext(info);
+                handler.ungetServletContext(info.getServiceReference().getBundle());
             }
             else if ( info instanceof ResourceInfo )
             {
                 handler.getRegistry().unregisterServlet(new ServletInfo((ResourceInfo)info), true);
-                handler.ungetServletContext(info);
+                handler.ungetServletContext(info.getServiceReference().getBundle());
             }
 
             else if ( info instanceof ListenerInfo )
             {
                 handler.getRegistry().unregisterListeners((ListenerInfo) info);
-                handler.ungetServletContext(info);
+                handler.ungetServletContext(info.getServiceReference().getBundle());
             }
         }
         catch (final Exception e)
@@ -786,6 +835,7 @@
         final FailedDTOHolder failedDTOHolder = new FailedDTOHolder();
 
         final Collection<ServletContextDTO> contextDTOs = new ArrayList<ServletContextDTO>();
+/*
         // add the context for the http service
         final ServletContextHelperInfo info = new ServletContextHelperInfo(Integer.MAX_VALUE,
                 HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID,
@@ -795,7 +845,7 @@
         {
             contextDTOs.add(dto);
         }
-
+*/
         // get sort list of context handlers
         final List<WhiteboardContextHandler> contextHandlerList = new ArrayList<WhiteboardContextHandler>();
         synchronized ( this.contextMap )