FELIX-4888 : ServletHandler's are not sorted by longest matching path. Implement new servlet and filter registry (WiP)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1679892 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 efbf91f..19d8f86 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
@@ -51,10 +51,11 @@
 import javax.servlet.http.HttpSession;
 
 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.HandlerRegistry;
 import org.apache.felix.http.base.internal.handler.HttpSessionWrapper;
-import org.apache.felix.http.base.internal.handler.ServletHandler;
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
+import org.apache.felix.http.base.internal.registry.PathResolution;
 import org.apache.felix.http.base.internal.util.UriUtils;
 import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.service.http.HttpContext;
@@ -68,11 +69,11 @@
     final class RequestDispatcherImpl implements RequestDispatcher
     {
         private final RequestInfo requestInfo;
-        private final ServletHandler handler;
+        private final ServletHolder holder;
 
-        public RequestDispatcherImpl(ServletHandler handler, RequestInfo requestInfo)
+        public RequestDispatcherImpl(ServletHolder holder, RequestInfo requestInfo)
         {
-            this.handler = handler;
+            this.holder = holder;
             this.requestInfo = requestInfo;
         }
 
@@ -91,9 +92,9 @@
 
             try
             {
-                ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request, this.handler.getContext(), this.requestInfo, DispatcherType.FORWARD, this.handler.getContextServiceId(),
-                        handler.getServletInfo().isAsyncSupported());
-                Dispatcher.this.forward(this.handler, req, (HttpServletResponse) response);
+                ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request, this.holder.getContext(), this.requestInfo, DispatcherType.FORWARD, this.holder.getContextServiceId(),
+                        this.holder.getServletInfo().isAsyncSupported());
+                Dispatcher.this.forward(this.holder, req, (HttpServletResponse) response);
             }
             finally
             {
@@ -110,9 +111,9 @@
         @Override
         public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException
         {
-            ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request, this.handler.getContext(), this.requestInfo, DispatcherType.INCLUDE,
-                    this.handler.getContextServiceId(), handler.getServletInfo().isAsyncSupported());
-            Dispatcher.this.include(this.handler, req, (HttpServletResponse) response);
+            ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request, this.holder.getContext(), this.requestInfo, DispatcherType.INCLUDE,
+                    this.holder.getContextServiceId(), holder.getServletInfo().isAsyncSupported());
+            Dispatcher.this.include(this.holder, req, (HttpServletResponse) response);
         }
     }
 
@@ -127,14 +128,15 @@
 
         private final String servletName;
 
-        public ServletResponseWrapper(final HttpServletRequest req, final HttpServletResponse res, final ServletHandler servletHandler)
+        public ServletResponseWrapper(final HttpServletRequest req, final HttpServletResponse res,
+                final ServletHolder servletHolder)
         {
             super(res);
             this.request = req;
-            if ( servletHandler != null )
+            if ( servletHolder != null )
             {
-                this.serviceId = servletHandler.getContextServiceId();
-                this.servletName = servletHandler.getName();
+                this.serviceId = servletHolder.getContextServiceId();
+                this.servletName = servletHolder.getName();
             }
             else
             {
@@ -167,7 +169,7 @@
                     code >= SC_OK)
                 {
                     final Throwable exception = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
-                    final ServletHandler errorHandler = handlerRegistry.getErrorsHandler(request.getRequestURI(), this.serviceId, code, exception);
+                    final ServletHolder errorHandler = handlerRegistry.getErrorHandler(request.getRequestURI(), this.serviceId, code, exception);
 
                     if ( errorHandler != null )
                     {
@@ -190,10 +192,10 @@
 
                             final RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString);
 
-                            final FilterHandler[] filterHandlers = handlerRegistry.getFilterHandlers(errorHandler, DispatcherType.ERROR, request.getRequestURI());
+                            final FilterHolder[] filterHolders = handlerRegistry.getFilters(errorHandler, DispatcherType.ERROR, request.getRequestURI());
 
                             // TODO - is async = false correct?
-                            invokeChain(filterHandlers, errorHandler, new ServletRequestWrapper(request, errorHandler.getContext(), requestInfo, this.serviceId, false), this);
+                            invokeChain(errorHandler, filterHolders, new ServletRequestWrapper(request, errorHandler.getContext(), requestInfo, this.serviceId, false), this);
 
                             invokeSuper = false;
                         }
@@ -578,29 +580,25 @@
             requestURI = "";
         }
 
-        // Determine which servlets we should forward the request to...
-        final ServletHandler servletHandler = this.handlerRegistry.getServletHandler(requestURI);
+        // Determine which servlet we should forward the request to...
+        final PathResolution pr = this.handlerRegistry.resolveServlet(requestURI);
 
-        final HttpServletResponse wrappedResponse = new ServletResponseWrapper(req, res, servletHandler);
-        if ( servletHandler == null )
+        final HttpServletResponse wrappedResponse = new ServletResponseWrapper(req, res,
+                pr == null ? null : pr.holder);
+        if ( pr == null )
         {
             wrappedResponse.sendError(404);
             return;
         }
 
-        // strip of context path
-        requestURI = requestURI.substring(servletHandler.getContext().getContextPath().length() - req.getContextPath().length());
 
-        final String servletPath = servletHandler.determineServletPath(requestURI);
-        String pathInfo = UriUtils.compactPath(UriUtils.relativePath(servletPath, requestURI));
-        String queryString = null; // XXX
+        final ExtServletContext servletContext = pr.holder.getContext();
+        final RequestInfo requestInfo = new RequestInfo(pr.servletPath, pr.pathInfo, null);
 
-        final ExtServletContext servletContext = servletHandler.getContext();
-        final RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString);
-
-        final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo, servletHandler.getContextServiceId(),
-                servletHandler.getServletInfo().isAsyncSupported());
-        final FilterHandler[] filterHandlers = this.handlerRegistry.getFilterHandlers(servletHandler, req.getDispatcherType(), requestURI);
+        final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo,
+                pr.holder.getContextServiceId(),
+                pr.holder.getServletInfo().isAsyncSupported());
+        final FilterHolder[] filterHolders = this.handlerRegistry.getFilters(pr.holder, req.getDispatcherType(), pr.requestURI);
 
         try
         {
@@ -608,7 +606,7 @@
             {
                 servletContext.getServletRequestListener().requestInitialized(new ServletRequestEvent(servletContext, wrappedRequest));
             }
-            invokeChain(filterHandlers, servletHandler, wrappedRequest, wrappedResponse);
+            invokeChain(pr.holder, filterHolders, wrappedRequest, wrappedResponse);
         }
         catch ( final Exception e)
         {
@@ -629,8 +627,8 @@
     @Override
     public RequestDispatcher getNamedDispatcher(final Long contextId, final String name)
     {
-        ServletHandler handler = this.handlerRegistry.getServletHandlerByName(contextId, name);
-        return handler != null ? new RequestDispatcherImpl(handler, null) : null;
+        ServletHolder holder = this.handlerRegistry.resolveServletByName(contextId, name);
+        return holder != null ? new RequestDispatcherImpl(holder, null) : null;
     }
 
     @Override
@@ -656,17 +654,14 @@
             requestURI = "";
         }
 
-        ServletHandler handler = this.handlerRegistry.getServletHandler(requestURI);
-        if (handler == null)
+        final PathResolution pr = this.handlerRegistry.resolveServlet(requestURI);
+        if (pr == null)
         {
             return null;
         }
 
-        String servletPath = handler.determineServletPath(requestURI);
-        String pathInfo = UriUtils.relativePath(servletPath, path);
-
-        RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, query);
-        return new RequestDispatcherImpl(handler, requestInfo);
+        final RequestInfo requestInfo = new RequestInfo(pr.servletPath, pr.pathInfo, query);
+        return new RequestDispatcherImpl(pr.holder, requestInfo);
     }
 
     /**
@@ -674,12 +669,12 @@
      * @param request the {@link HttpServletRequest};
      * @param response the {@link HttpServletResponse};
      */
-    void forward(ServletHandler servletHandler, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    void forward(ServletHolder servletHolder, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
     {
         String requestURI = getRequestURI(request);
-        FilterHandler[] filterHandlers = this.handlerRegistry.getFilterHandlers(servletHandler, DispatcherType.FORWARD, requestURI);
+        FilterHolder[] filterHolders = this.handlerRegistry.getFilters(servletHolder, DispatcherType.FORWARD, requestURI);
 
-        invokeChain(filterHandlers, servletHandler, request, response);
+        invokeChain(servletHolder, filterHolders, request, response);
     }
 
     /**
@@ -687,12 +682,12 @@
      * @param request the {@link HttpServletRequest};
      * @param response the {@link HttpServletResponse};
      */
-    void include(ServletHandler servletHandler, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+    void include(ServletHolder servletHolder, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
     {
         String requestURI = getRequestURI(request);
-        FilterHandler[] filterHandlers = this.handlerRegistry.getFilterHandlers(servletHandler, DispatcherType.INCLUDE, requestURI);
+        FilterHolder[] filterHolders = this.handlerRegistry.getFilters(servletHolder, DispatcherType.INCLUDE, requestURI);
 
-        invokeChain(filterHandlers, servletHandler, request, response);
+        invokeChain(servletHolder, filterHolders, request, response);
     }
 
     private String getRequestURI(HttpServletRequest req)
@@ -700,9 +695,13 @@
         return UriUtils.relativePath(req.getContextPath(), req.getRequestURI());
     }
 
-    private void invokeChain(FilterHandler[] filterHandlers, ServletHandler servletHandler, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+    private void invokeChain(final ServletHolder servletHolder,
+            final FilterHolder[] filterHolders,
+            final HttpServletRequest request,
+            final HttpServletResponse response)
+    throws IOException, ServletException
     {
-        final FilterChain filterChain = new InvocationChain(servletHandler, filterHandlers);
+        final FilterChain filterChain = new InvocationChain(servletHolder, filterHolders);
         filterChain.doFilter(request, response);
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java
index eda9509..991b276 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/InvocationChain.java
@@ -29,20 +29,20 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.felix.http.base.internal.handler.FilterHandler;
-import org.apache.felix.http.base.internal.handler.ServletHandler;
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
 
 public class InvocationChain implements FilterChain
 {
-    private final ServletHandler servletHandler;
-    private final FilterHandler[] filterHandlers;
+    private final ServletHolder servletHolder;
+    private final FilterHolder[] filterHolders;
 
     private int index = -1;
 
-    public InvocationChain(@Nonnull final ServletHandler servletHandler, @Nonnull final FilterHandler[] filterHandlers)
+    public InvocationChain(@Nonnull final ServletHolder servletHolder, @Nonnull final FilterHolder[] filterHolders)
     {
-        this.filterHandlers = filterHandlers;
-        this.servletHandler = servletHandler;
+        this.filterHolders = filterHolders;
+        this.servletHolder = servletHolder;
     }
 
     @Override
@@ -54,7 +54,7 @@
             final HttpServletResponse hRes = (HttpServletResponse) res;
 
             // invoke security
-            if ( !servletHandler.getContext().handleSecurity(hReq, hRes))
+            if ( !servletHolder.getContext().handleSecurity(hReq, hRes))
             {
                 // FELIX-3988: If the response is not yet committed and still has the default
                 // status, we're going to override this and send an error instead.
@@ -69,14 +69,14 @@
         }
         this.index++;
 
-        if (this.index < this.filterHandlers.length)
+        if (this.index < this.filterHolders.length)
         {
-            this.filterHandlers[this.index].handle(req, res, this);
+            this.filterHolders[this.index].handle(req, res, this);
         }
         else
         {
             // Last entry in the chain...
-            this.servletHandler.handle(req, res);
+            this.servletHolder.handle(req, res);
         }
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
index f3c020d..7c12b03 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
@@ -16,29 +16,25 @@
  */
 package org.apache.felix.http.base.internal.handler;
 
-import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-import java.util.regex.Pattern;
 
 import javax.annotation.Nonnull;
 import javax.servlet.DispatcherType;
-import javax.servlet.Filter;
-import javax.servlet.Servlet;
-import javax.servlet.ServletException;
 
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
+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.runtime.FilterInfo;
 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.runtime.dto.ContextRuntime;
 import org.apache.felix.http.base.internal.runtime.dto.FailureRuntime;
 import org.apache.felix.http.base.internal.runtime.dto.HandlerRegistryRuntime;
 import org.apache.felix.http.base.internal.runtime.dto.ServletRegistryRuntime;
-import org.apache.felix.http.base.internal.whiteboard.RegistrationFailureException;
 
 /**
  * Registry for all services.
@@ -48,7 +44,7 @@
  */
 public final class HandlerRegistry
 {
-    private static FilterHandler[] EMPTY_FILTER_HANDLER = new FilterHandler[0];
+    private static FilterHolder[] EMPTY_FILTER_HOLDER = new FilterHolder[0];
 
     /** Current list of context registrations. */
     private volatile List<PerContextHandlerRegistry> registrations = Collections.emptyList();
@@ -138,54 +134,26 @@
         }
     }
 
-    public void addFilter(FilterHandler handler) throws ServletException
+    public void addFilter(@Nonnull final FilterHolder holder)
     {
-        getRegistryChecked(null, null).addFilter(handler);
-    }
-
-    public void addFilter(ServletContextHelperInfo contextInfo, FilterHandler handler) throws ServletException
-    {
-        getRegistryChecked(contextInfo, handler.getFilterInfo()).addFilter(handler);
-    }
-
-    public void removeFilter(Filter filter, boolean destroy)
-    {
-        try
+        final PerContextHandlerRegistry reg = this.getRegistry(holder.getContextServiceId());
+        // TODO - check whether we need to handle the null case as well
+        //        it shouldn't be required as we only get here if the context exists
+        if ( reg != null )
         {
-            getRegistryChecked(null, null).removeFilter(filter, destroy);
-        }
-        catch (RegistrationFailureException e)
-        {
-            // TODO
+            reg.addFilter(holder);
         }
     }
 
-    public Filter removeFilter(ServletContextHelperInfo contextInfo, FilterInfo filterInfo)
+    public void removeFilter(final long contextId, @Nonnull final FilterInfo info, final boolean destroy)
     {
-        return getRegistry(contextInfo).removeFilter(filterInfo, true);
-    }
-
-    private PerContextHandlerRegistry getRegistryChecked(ServletContextHelperInfo info, WhiteboardServiceInfo<?> serviceInfo)
-        throws RegistrationFailureException
-    {
-        PerContextHandlerRegistry registry = getRegistry(info);
-        if (registry == null)
+        final PerContextHandlerRegistry reg = this.getRegistry(contextId);
+        // TODO - check whether we need to handle the null case as well
+        //        it shouldn't be required as we only get here if the context exists
+        if ( reg != null )
         {
-            throw new RegistrationFailureException(serviceInfo, FAILURE_REASON_SERVLET_CONTEXT_FAILURE);
+            reg.removeFilter(info, destroy);
         }
-        return registry;
-    }
-
-    /**
-     * Get the per context registry.
-     * @param info The servlet context helper info or {@code null} for the Http Service context.
-     * @return A per context registry or {@code null}
-     */
-    private PerContextHandlerRegistry getRegistry(final ServletContextHelperInfo info)
-    {
-        final long key = (info == null ? 0 : info.getServiceId());
-
-        return getRegistry(key);
     }
 
     private PerContextHandlerRegistry getRegistry(final long key)
@@ -203,7 +171,7 @@
         return null;
     }
 
-    public ServletHandler getErrorsHandler(String requestURI, Long serviceId, int code, Throwable exception)
+    public ServletHolder getErrorHandler(String requestURI, Long serviceId, int code, Throwable exception)
     {
         ErrorsMapping errorsMapping = getErrorsMapping(requestURI, serviceId);
         if (errorsMapping == null)
@@ -211,7 +179,9 @@
             return null;
         }
 
-        return errorsMapping.get(exception, code);
+        // TODO
+        return null;
+        //return errorsMapping.get(exception, code);
     }
 
     private ErrorsMapping getErrorsMapping(final String requestURI, final Long serviceId)
@@ -232,73 +202,77 @@
         return null;
     }
 
-    public FilterHandler[] getFilterHandlers(@Nonnull final ServletHandler servletHandler,
+    public FilterHolder[] getFilters(@Nonnull final ServletHolder servletHolder,
             final DispatcherType dispatcherType,
             @Nonnull final String requestURI)
     {
-        final long key = servletHandler.getContextServiceId();
+        final long key = servletHolder.getContextServiceId();
+        final PerContextHandlerRegistry reg = this.getRegistry(key);
+        if ( reg != null )
+        {
+            return reg.getFilterHolders(servletHolder, dispatcherType, requestURI);
+        }
+        return EMPTY_FILTER_HOLDER;
+    }
+
+    public void addServlet(final ServletHolder holder)
+    {
+        final PerContextHandlerRegistry reg = this.getRegistry(holder.getContextServiceId());
+        // TODO - check whether we need to handle the null case as well
+        //        it shouldn't be required as we only get here if the context exists
+        if ( reg != null )
+        {
+            reg.addServlet(holder);
+        }
+    }
+
+    public void removeServlet(final long contextId, final ServletInfo info, final boolean destroy)
+    {
+        final PerContextHandlerRegistry reg = this.getRegistry(contextId);
+        // TODO - check whether we need to handle the null case as well
+        //        it shouldn't be required as we only get here if the context exists
+        if ( reg != null )
+        {
+            reg.removeServlet(info, destroy);
+        }
+
+    }
+
+    public PathResolution resolveServlet(final String requestURI)
+    {
         final List<PerContextHandlerRegistry> regs = this.registrations;
         for(final PerContextHandlerRegistry r : regs)
         {
-            if ( key == r.getContextServiceId() )
+            final String path = r.isMatching(requestURI);
+            if ( path != null )
             {
-                return r.getFilterHandlers(servletHandler, dispatcherType, requestURI);
+                final PathResolution ps = r.resolve(path);
+                if ( ps != null )
+                {
+                    // remove context path from request URI
+                    ps.requestURI = path;
+                    return ps;
+                }
             }
         }
-        return EMPTY_FILTER_HANDLER;
-    }
 
-    public synchronized void addServlet(ServletHandler handler) throws RegistrationFailureException
-    {
-        Pattern[] patterns = handler.getPatterns();
-        String[] errorPages = handler.getServletInfo().getErrorPage();
-        if (patterns != null && patterns.length > 0)
-        {
-            servletRegistry.addServlet(handler);
-        }
-        if (errorPages != null && errorPages.length > 0)
-        {
-            getRegistry(handler.getContextServiceId()).addErrorPage(handler, errorPages);
-        }
-    }
-
-    public synchronized void removeServlet(Servlet servlet, boolean destroy)
-    {
-        servletRegistry.removeServlet(servlet, destroy);
-    }
-
-    public synchronized Servlet removeServlet(ServletInfo servletInfo)
-    {
-        return servletRegistry.removeServlet(servletInfo);
-    }
-
-    public synchronized void removeServlet(long contextId, ServletInfo servletInfo)
-    {
-        String[] patterns = servletInfo.getPatterns();
-        if (patterns != null && patterns.length > 0)
-        {
-            servletRegistry.removeServlet(contextId, servletInfo);
-        }
-        else
-        {
-            getRegistry(contextId).removeErrorPage(servletInfo);
-        }
-    }
-
-    public ServletHandler getServletHandler(String requestURI)
-    {
-        return servletRegistry.getServletHandler(requestURI);
+        return null;
     }
 
     /**
-     * Get the servlet handler for a servlet by name
+     * Get the servlet holder for a servlet by name
      * @param contextId The context id or {@code null}
      * @param name The servlet name
-     * @return The servlet handler or {@code null}
+     * @return The servlet holder or {@code null}
      */
-    public ServletHandler getServletHandlerByName(final Long contextId, @Nonnull final String name)
+    public ServletHolder resolveServletByName(final Long contextId, @Nonnull final String name)
     {
-        return servletRegistry.getServletHandlerByName(contextId, name);
+        final PerContextHandlerRegistry reg = (contextId == null ? null : this.getRegistry(contextId));
+        if ( reg != null )
+        {
+            return reg.resolveServletByName(name);
+        }
+        return null;
     }
 
     public synchronized HandlerRegistryRuntime getRuntime(FailureRuntime.Builder failureRuntimeBuilder)
@@ -306,7 +280,8 @@
         List<ContextRuntime> handlerRuntimes = new ArrayList<ContextRuntime>();
         for (PerContextHandlerRegistry contextRegistry : this.registrations)
         {
-            handlerRuntimes.add(contextRegistry.getRuntime(failureRuntimeBuilder));
+            // TODO
+            // handlerRuntimes.add(contextRegistry.getRuntime(failureRuntimeBuilder));
         }
         ServletRegistryRuntime servletRegistryRuntime = servletRegistry.getRuntime(failureRuntimeBuilder);
         return new HandlerRegistryRuntime(handlerRuntimes, servletRegistryRuntime);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java
index e7e478c..e673dd5 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java
@@ -16,33 +16,81 @@
  */
 package org.apache.felix.http.base.internal.handler.holder;
 
-import javax.servlet.Filter;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
 
+import javax.annotation.Nonnull;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.FilterConfigImpl;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
+import org.apache.felix.http.base.internal.util.PatternUtil;
 import org.osgi.service.http.runtime.dto.DTOConstants;
 
 /**
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public abstract class FilterHolder implements Comparable<FilterHolder>
+public class FilterHolder implements Comparable<FilterHolder>
 {
+    private final long contextServiceId;
+
     private final FilterInfo filterInfo;
 
-    private final ServletContext context;
+    private final ExtServletContext context;
 
     private volatile Filter filter;
 
     protected volatile int useCount;
 
-    public FilterHolder(final ServletContext context,
+    private final Pattern[] patterns;
+
+    public FilterHolder(final long contextServiceId,
+            final ExtServletContext context,
             final FilterInfo filterInfo)
     {
+        this.contextServiceId = contextServiceId;
         this.context = context;
         this.filterInfo = filterInfo;
+        // Compose a single array of all patterns & regexs the filter must represent...
+        String[] patterns = getFilterPatterns(filterInfo);
+
+        this.patterns = new Pattern[patterns.length];
+        for (int i = 0; i < patterns.length; i++)
+        {
+            this.patterns[i] = Pattern.compile(patterns[i]);
+        }
+    }
+
+    private static String[] getFilterPatterns(FilterInfo filterInfo)
+    {
+        List<String> result = new ArrayList<String>();
+        if (filterInfo.getPatterns() != null)
+        {
+            for (int i = 0; i < filterInfo.getPatterns().length; i++)
+            {
+                result.add(PatternUtil.convertToRegEx(filterInfo.getPatterns()[i]));
+            }
+        }
+        if (filterInfo.getRegexs() != null)
+        {
+            for (int i = 0; i < filterInfo.getRegexs().length; i++)
+            {
+                result.add(filterInfo.getRegexs()[i]);
+            }
+        }
+        return result.toArray(new String[result.size()]);
+    }
+
+    public Pattern[] getPatterns() {
+        return this.patterns;
     }
 
     @Override
@@ -51,12 +99,17 @@
         return this.filterInfo.compareTo(other.filterInfo);
     }
 
-    protected ServletContext getContext()
+    public long getContextServiceId()
+    {
+        return this.contextServiceId;
+    }
+
+    public ExtServletContext getContext()
     {
         return this.context;
     }
 
-    protected Filter getFilter()
+    public Filter getFilter()
     {
         return filter;
     }
@@ -71,7 +124,7 @@
         return this.filterInfo;
     }
 
-    protected String getName()
+    public String getName()
     {
         String name = this.filterInfo.getName();
         if (name == null)
@@ -89,6 +142,7 @@
     {
         if ( this.useCount > 0 )
         {
+            this.useCount++;
             return -1;
         }
 
@@ -112,6 +166,12 @@
         return -1;
     }
 
+    public void handle(@Nonnull final ServletRequest req,
+            @Nonnull final ServletResponse res,
+            @Nonnull final FilterChain chain) throws ServletException, IOException
+    {
+        this.filter.doFilter(req, res, chain);
+    }
 
     public boolean destroy()
     {
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java
index 3bde5ae..68b1a38 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java
@@ -17,8 +17,8 @@
 package org.apache.felix.http.base.internal.handler.holder;
 
 import javax.servlet.Filter;
-import javax.servlet.ServletContext;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 
 /**
@@ -26,11 +26,12 @@
  */
 public final class HttpServiceFilterHolder extends FilterHolder
 {
-    public HttpServiceFilterHolder(final ServletContext context,
+    public HttpServiceFilterHolder(final long contextServiceId,
+            final ExtServletContext context,
             final FilterInfo filterInfo,
             final Filter filter)
     {
-        super(context, filterInfo);
+        super(contextServiceId, context, filterInfo);
         this.setFilter(filter);
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceServletHolder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceServletHolder.java
index 445929b..8c3cdd1 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceServletHolder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceServletHolder.java
@@ -17,8 +17,8 @@
 package org.apache.felix.http.base.internal.handler.holder;
 
 import javax.servlet.Servlet;
-import javax.servlet.ServletContext;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 
 /**
@@ -26,11 +26,12 @@
  */
 public final class HttpServiceServletHolder extends ServletHolder
 {
-    public HttpServiceServletHolder(final ServletContext context,
+    public HttpServiceServletHolder(final long contextServiceId,
+            final ExtServletContext context,
             final ServletInfo servletInfo,
             final Servlet servlet)
     {
-        super(context, servletInfo);
+        super(contextServiceId, context, servletInfo);
         this.setServlet(servlet);
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/ServletHolder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/ServletHolder.java
index a939298..ea9e1f9 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/ServletHolder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/ServletHolder.java
@@ -19,11 +19,11 @@
 import java.io.IOException;
 
 import javax.servlet.Servlet;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.ServletConfigImpl;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
@@ -34,17 +34,21 @@
  */
 public abstract class ServletHolder implements Comparable<ServletHolder>
 {
+    private final long contextServiceId;
+
     private final ServletInfo servletInfo;
 
-    private final ServletContext context;
+    private final ExtServletContext context;
 
     private volatile Servlet servlet;
 
     protected volatile int useCount;
 
-    public ServletHolder(final ServletContext context,
+    public ServletHolder(final long contextServiceId,
+            final ExtServletContext context,
             final ServletInfo servletInfo)
     {
+        this.contextServiceId = contextServiceId;
         this.context = context;
         this.servletInfo = servletInfo;
     }
@@ -55,12 +59,17 @@
         return this.servletInfo.compareTo(other.servletInfo);
     }
 
-    protected ServletContext getContext()
+    public long getContextServiceId()
+    {
+        return this.contextServiceId;
+    }
+
+    public ExtServletContext getContext()
     {
         return this.context;
     }
 
-    protected Servlet getServlet()
+    public Servlet getServlet()
     {
         return servlet;
     }
@@ -81,7 +90,7 @@
         return this.servletInfo;
     }
 
-    protected String getName()
+    public String getName()
     {
         String name = this.servletInfo.getName();
         if (name == null)
@@ -99,6 +108,7 @@
     {
         if ( this.useCount > 0 )
         {
+            this.useCount++;
             return -1;
         }
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java
index c1d2d2f..cc794c8 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java
@@ -17,8 +17,8 @@
 package org.apache.felix.http.base.internal.handler.holder;
 
 import javax.servlet.Filter;
-import javax.servlet.ServletContext;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceObjects;
@@ -31,11 +31,12 @@
 {
     private final BundleContext bundleContext;
 
-    public WhiteboardFilterHolder(final ServletContext context,
+    public WhiteboardFilterHolder(final long contextServiceId,
+            final ExtServletContext context,
             final FilterInfo filterInfo,
             final BundleContext bundleContext)
     {
-        super(context, filterInfo);
+        super(contextServiceId, context, filterInfo);
         this.bundleContext = bundleContext;
     }
 
@@ -44,6 +45,7 @@
     {
         if ( this.useCount > 0 )
         {
+            this.useCount++;
             return -1;
         }
 
@@ -58,7 +60,7 @@
             so.ungetService(this.getFilter());
             this.setFilter(null);
         }
-        return -reason;
+        return reason;
     }
 
     @Override
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardServletHolder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardServletHolder.java
index 6758639..8aea9b0 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardServletHolder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardServletHolder.java
@@ -17,8 +17,8 @@
 package org.apache.felix.http.base.internal.handler.holder;
 
 import javax.servlet.Servlet;
-import javax.servlet.ServletContext;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceObjects;
@@ -31,11 +31,12 @@
 {
     private final BundleContext bundleContext;
 
-    public WhiteboardServletHolder(final ServletContext context,
+    public WhiteboardServletHolder(final long contextServiceId,
+            final ExtServletContext context,
             final ServletInfo servletInfo,
             final BundleContext bundleContext)
     {
-        super(context, servletInfo);
+        super(contextServiceId, context, servletInfo);
         this.bundleContext = bundleContext;
     }
 
@@ -44,6 +45,7 @@
     {
         if ( this.useCount > 0 )
         {
+            this.useCount++;
             return -1;
         }
 
@@ -58,7 +60,7 @@
             so.ungetService(this.getServlet());
             this.setServlet(null);
         }
-        return -reason;
+        return reason;
     }
 
     @Override
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
new file mode 100644
index 0000000..df7036c
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.servlet.DispatcherType;
+
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
+
+public final class FilterRegistry
+{
+    private volatile HandlerMapping filterMapping = new HandlerMapping();
+
+    private final Map<FilterInfo, FilterRegistrationStatus> statusMapping = new ConcurrentHashMap<FilterInfo, FilterRegistrationStatus>();
+
+    private static final class FilterRegistrationStatus
+    {
+        public int result;
+        public FilterHolder holder;
+    }
+
+    public void addFilter(@Nonnull final FilterHolder holder)
+    {
+        final int result = holder.init();
+        if ( result == -1 )
+        {
+            this.filterMapping = this.filterMapping.add(holder);
+        }
+        final FilterRegistrationStatus status = new FilterRegistrationStatus();
+        status.result = result;
+        status.holder = holder;
+
+        statusMapping.put(holder.getFilterInfo(), status);
+    }
+
+    public void removeFilter(@Nonnull final FilterInfo filterInfo, final boolean destroy)
+    {
+        final FilterRegistrationStatus status = statusMapping.remove(filterInfo);
+        if ( status != null )
+        {
+            if ( status.result == -1 )
+            {
+                this.filterMapping = this.filterMapping.remove(status.holder);
+                if (destroy)
+                {
+                    status.holder.dispose();
+                }
+            }
+        }
+    }
+
+    public FilterHolder[] getFilterHolders(@CheckForNull final ServletHolder holder,
+            @CheckForNull DispatcherType dispatcherType,
+            @Nonnull String requestURI)
+    {
+        // See Servlet 3.0 specification, section 6.2.4...
+        final List<FilterHolder> result = new ArrayList<FilterHolder>();
+        result.addAll(this.filterMapping.getAllMatches(requestURI));
+
+        // TODO this is not the most efficient/fastest way of doing this...
+        Iterator<FilterHolder> iter = result.iterator();
+        while (iter.hasNext())
+        {
+            if (!referencesDispatcherType(iter.next(), dispatcherType))
+            {
+                iter.remove();
+            }
+        }
+
+        final String servletName = (holder != null) ? holder.getName() : null;
+        // TODO this is not the most efficient/fastest way of doing this...
+        for (FilterHolder filterHandler : this.filterMapping.values())
+        {
+            if (referencesServletByName(filterHandler, servletName))
+            {
+                result.add(filterHandler);
+            }
+        }
+
+        return result.toArray(new FilterHolder[result.size()]);
+    }
+
+    private boolean referencesDispatcherType(FilterHolder holder, DispatcherType dispatcherType)
+    {
+        if (dispatcherType == null)
+        {
+            return true;
+        }
+        return Arrays.asList(holder.getFilterInfo().getDispatcher()).contains(dispatcherType);
+    }
+
+    private boolean referencesServletByName(FilterHolder handler, String servletName)
+    {
+        if (servletName == null)
+        {
+            return false;
+        }
+        String[] names = handler.getFilterInfo().getServletNames();
+        if (names != null && names.length > 0)
+        {
+            return Arrays.asList(names).contains(servletName);
+        }
+        return false;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/HandlerMapping.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/HandlerMapping.java
new file mode 100644
index 0000000..db3d367
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/HandlerMapping.java
@@ -0,0 +1,342 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.http.base.internal.registry;
+
+import static java.util.Collections.unmodifiableCollection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nonnull;
+
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.util.PatternUtil;
+import org.apache.felix.http.base.internal.util.PatternUtil.PatternComparator;
+
+/**
+ * Represents a Map-like structure that can map path-patterns to servlet/filter handlers, allowing
+ * for easy access to those handlers, based on the match rules defined in section 12.1 of Servlet
+ * 3.0 specification.
+ * <p>
+ * {@link HandlerMapping} instances are immutable.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class HandlerMapping
+{
+    private final SortedMap<Pattern, Set<FilterHolder>> exactMap;
+    private final SortedMap<Pattern, Set<FilterHolder>> wildcardMap;
+    private final Set<FilterHolder> mappedHandlers;
+
+    /**
+     * Creates a new, empty, {@link HandlerMapping} instance.
+     */
+    public HandlerMapping()
+    {
+        this(Collections.<Pattern, Collection<FilterHolder>>emptyMap());
+    }
+
+    /**
+     * Creates a new {@link HandlerMapping} instance for the given elements.
+     *
+     * @param mappings the elements to map.
+     */
+    private HandlerMapping(@Nonnull final Map<Pattern, Collection<FilterHolder>> mappings)
+    {
+        this.exactMap = new TreeMap<Pattern, Set<FilterHolder>>(PatternComparator.INSTANCE);
+        this.wildcardMap = new TreeMap<Pattern, Set<FilterHolder>>(PatternComparator.INSTANCE);
+        this.mappedHandlers = new TreeSet<FilterHolder>();
+
+        for (Map.Entry<Pattern, Collection<FilterHolder>> mapping : mappings.entrySet())
+        {
+            Pattern pattern = mapping.getKey();
+            Collection<FilterHolder> handlers = mapping.getValue();
+
+            mappedHandlers.addAll(handlers);
+
+            if (PatternUtil.isWildcardPattern(pattern))
+            {
+                Set<FilterHolder> vs = this.wildcardMap.get(pattern);
+                if (vs == null)
+                {
+                    vs = new TreeSet<FilterHolder>();
+                    this.wildcardMap.put(pattern, vs);
+                }
+                vs.addAll(handlers);
+            }
+            else
+            {
+                Set<FilterHolder> vs = this.exactMap.get(pattern);
+                if (vs == null)
+                {
+                    vs = new TreeSet<FilterHolder>();
+                    this.exactMap.put(pattern, vs);
+                }
+                vs.addAll(handlers);
+            }
+        }
+    }
+
+    /**
+     * Returns a new {@link HandlerMapping} instance with a mapping for the
+     * given handler.
+     *
+     * @param handler the handler to be added to the mapping.
+     * @return a new {@link HandlerMapping} instance with a mapping for the
+     *         given handler.
+     */
+    public HandlerMapping add(@Nonnull final FilterHolder handler)
+    {
+        final Map<Pattern, FilterHolder> mappings = new TreeMap<Pattern, FilterHolder>(PatternComparator.INSTANCE);
+        for (final Pattern pattern : handler.getPatterns())
+        {
+            mappings.put(pattern, handler);
+        }
+        return add(mappings);
+    }
+
+    HandlerMapping add(@Nonnull final Map<Pattern, FilterHolder> mappings)
+    {
+        final Map<Pattern, Collection<FilterHolder>> newMappings = getAllMappings();
+        addMappings(mappings, newMappings);
+        return new HandlerMapping(newMappings);
+    }
+
+    /**
+     * Returns a new {@link HandlerMapping} instance without a mapping for the
+     * given handler.
+     *
+     * @param subject the handled element to be removed from the mapping
+     * @return a new {@link HandlerMapping} instance without a mapping for the
+     *         given handler.
+     */
+    public HandlerMapping remove(FilterHolder handler)
+    {
+        Map<Pattern, FilterHolder> mappings = new TreeMap<Pattern, FilterHolder>(PatternComparator.INSTANCE);
+        for (Pattern pattern : handler.getPatterns())
+        {
+            mappings.put(pattern, handler);
+        }
+        return remove(mappings);
+    }
+
+    HandlerMapping remove(Map<Pattern, FilterHolder> mappings)
+    {
+        Map<Pattern, Collection<FilterHolder>> newMappings = getAllMappings();
+        removeMappings(mappings, newMappings);
+        return new HandlerMapping(newMappings);
+    }
+
+    HandlerMapping update(Map<Pattern, FilterHolder> add, Map<Pattern, FilterHolder> remove)
+    {
+        Map<Pattern, Collection<FilterHolder>> newMappings = getAllMappings();
+        removeMappings(remove, newMappings);
+        addMappings(add, newMappings);
+        return new HandlerMapping(newMappings);
+    }
+
+    private void addMappings(Map<Pattern, FilterHolder> mappings, Map<Pattern, Collection<FilterHolder>> target)
+    {
+        for (Map.Entry<Pattern, FilterHolder> mapping : mappings.entrySet())
+        {
+            if (!target.containsKey(mapping.getKey()))
+            {
+                target.put(mapping.getKey(), new TreeSet<FilterHolder>());
+            }
+            target.get(mapping.getKey()).add(mapping.getValue());
+        }
+    }
+
+    private void removeMappings(Map<Pattern, FilterHolder> mappings, Map<Pattern, Collection<FilterHolder>> target)
+    {
+        for (Map.Entry<Pattern, FilterHolder> mapping : mappings.entrySet())
+        {
+            Collection<FilterHolder> mappedHandlers = target.get(mapping.getKey());
+            if (mappedHandlers == null)
+            {
+                continue;
+            }
+            mappedHandlers.remove(mapping.getValue());
+            if (mappedHandlers.isEmpty())
+            {
+                target.remove(mapping.getKey());
+            }
+        }
+    }
+
+    private Map<Pattern, Collection<FilterHolder>> getAllMappings()
+    {
+        Map<Pattern, Collection<FilterHolder>> newMappings = new TreeMap<Pattern, Collection<FilterHolder>>(PatternComparator.INSTANCE);
+        newMappings.putAll(exactMap);
+        newMappings.putAll(wildcardMap);
+        return newMappings;
+    }
+
+    /**
+     * Returns all mapped handlers.
+     *
+     * @return the handlers contained in this mapping. The returned
+     *         <code>Collection</code> is unmodifiable and never
+     *         <code>null</code>.
+     */
+    public Collection<FilterHolder> values()
+    {
+        return unmodifiableCollection(mappedHandlers);
+    }
+
+    /**
+     * Returns whether this mapping contains the specified handler.
+     *
+     * @return <code>true</code> if the handlers contains the specified handler,
+     *         <code>false</code> otherwise
+     */
+    public boolean contains(FilterHolder handler)
+    {
+        return mappedHandlers.contains(handler);
+    }
+
+    /**
+     * Returns all matching handlers for the given path.
+     *
+     * @param path the path that should match, cannot be <code>null</code>.
+     * @return a {@link Collection} of all matching handlers, never <code>null</code>.
+     */
+    public List<FilterHolder> getAllMatches(String path)
+    {
+        return getAllMatches(path, false /* firstOnly */);
+    }
+
+    /**
+     * Returns the best matching handler for the given path, according to the rules defined in section 12.1 of Servlet 3.0 specification:
+     * <ul>
+     * <li>find an exact match of the path of the request to the path of the handler. A successful match selects the handler;</li>
+     * <li>recursively try to match the longest path-prefix. This is done by stepping down the path tree a directory at a time, using the
+     *     '/' character as a path separator. The longest match determines the servlet selected;</li>
+     * <li>if the last segment in the URL path contains an extension (e.g. .jsp), the servlet container will try to match a servlet that
+     *     handles requests for the extension. An extension is defined as the part of the last segment after the last '.' character.</li>
+     * </ul>
+     *
+     * @param path the path that should match, cannot be <code>null</code>.
+     * @return the best matching handler for the given path, or <code>null</code> in case no handler matched.
+     */
+    FilterHolder getBestMatch(String path)
+    {
+        List<FilterHolder> allMatches = getAllMatches(path, true /* firstOnly */);
+        return allMatches.isEmpty() ? null : allMatches.get(0);
+    }
+
+    /**
+     * Returns the (first) handler identified by the given name.
+     *
+     * @param name the name of the handler to return, can be <code>null</code> in which case this method will return <code>null</code>.
+     * @return the element with the given name, or <code>null</code> if not found, or the given argument was <code>null</code>.
+     */
+    FilterHolder getByName(String name)
+    {
+        if (name == null)
+        {
+            return null;
+        }
+
+        for (FilterHolder element : this.mappedHandlers)
+        {
+            if (name.equals(element.getName()))
+            {
+                return element;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Provides information on whether there are elements mapped or not.
+     *
+     * @return <code>false</code> if there is at least one element mapped, <code>true</code> otherwise.
+     */
+    boolean isEmpty()
+    {
+        return this.mappedHandlers.isEmpty();
+    }
+
+    /**
+     * Performs the actual matching, yielding a list of either the first or all matching patterns.
+     *
+     * @param path the path to match, can be <code>null</code> in which case an empty string is
+     *        used;
+     * @param firstOnly <code>true</code> if only the first matching pattern should be returned,
+     *        <code>false</code> if all matching patterns should be returned.
+     * @return a list with matching elements, never <code>null</code>.
+     */
+    private List<FilterHolder> getAllMatches(String path, boolean firstOnly)
+    {
+        path = (path == null) ? "" : path.trim();
+
+        Set<FilterHolder> result = new TreeSet<FilterHolder>();
+        // Look for exact matches only, that is, those patterns without wildcards...
+        for (Entry<Pattern, Set<FilterHolder>> entry : this.exactMap.entrySet())
+        {
+            Matcher matcher = entry.getKey().matcher(path);
+            // !!! we should always match the *entire* pattern, instead of the longest prefix...
+            if (matcher.matches())
+            {
+                Set<FilterHolder> vs = entry.getValue();
+                for (FilterHolder v : vs)
+                {
+                    result.add(v);
+                    if (firstOnly)
+                    {
+                        return new ArrayList<FilterHolder>(result);
+                    }
+                }
+            }
+        }
+
+        // Try to apply the wildcard patterns...
+        for (Entry<Pattern, Set<FilterHolder>> entry : this.wildcardMap.entrySet())
+        {
+            Matcher matcher = entry.getKey().matcher(path);
+            if (matcher.find(0))
+            {
+                Set<FilterHolder> vs = entry.getValue();
+                for (FilterHolder v : vs)
+                {
+                    result.add(v);
+
+                    if (firstOnly)
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+
+        return new ArrayList<FilterHolder>(result);
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
index 9810a78..feb9398 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PathResolution.java
@@ -25,4 +25,6 @@
     public String pathInfo;
 
     public ServletHolder holder;
+
+    public String requestURI;
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
index 8c55c2e..34c1c71 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
@@ -17,8 +17,13 @@
 package org.apache.felix.http.base.internal.registry;
 
 import javax.annotation.Nonnull;
+import javax.servlet.DispatcherType;
 
+import org.apache.felix.http.base.internal.handler.ErrorsMapping;
+import org.apache.felix.http.base.internal.handler.ServletHandler;
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
 import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 
@@ -44,6 +49,8 @@
 
     private final ServletRegistry servletRegistry = new ServletRegistry();
 
+    private final FilterRegistry filterRegistry = new FilterRegistry();
+
     /**
      * Default http service registry
      */
@@ -74,15 +81,19 @@
         }
     }
 
+    public long getContextServiceId()
+    {
+        return this.serviceId;
+    }
+
+    public void removeAll()
+    {
+        // TODO - implement
+    }
+
     @Override
     public int compareTo(@Nonnull final PerContextHandlerRegistry other)
     {
-        // the context of the HttpService is the least element
-        if (this.serviceId == 0 ^ other.serviceId == 0)
-        {
-            return this.serviceId == 0 ? -1 : 1;
-        }
-
         final int result = Integer.compare(other.path.length(), this.path.length());
         if ( result == 0 ) {
             if (this.ranking == other.ranking)
@@ -119,6 +130,11 @@
         return this.servletRegistry.resolve(relativeRequestURI);
     }
 
+    public ServletHolder resolveServletByName(final String name)
+    {
+        return this.servletRegistry.resolveByName(name);
+    }
+
     /**
      * Add a servlet
      * @param holder The servlet holder
@@ -133,8 +149,39 @@
      * Remove a servlet
      * @param info The servlet info
      */
-    public void removeServlet(@Nonnull final ServletInfo info)
+    public void removeServlet(@Nonnull final ServletInfo info, final boolean destroy)
     {
-        this.servletRegistry.removeServlet(info);
+        this.servletRegistry.removeServlet(info, destroy);
     }
+
+    public void addFilter(@Nonnull final FilterHolder holder)
+    {
+        this.filterRegistry.addFilter(holder);
+    }
+
+    public void removeFilter(@Nonnull final FilterInfo info, final boolean destroy)
+    {
+        this.filterRegistry.removeFilter(info, destroy);
+    }
+
+    public FilterHolder[] getFilterHolders(final ServletHolder servletHolder,
+            DispatcherType dispatcherType, String requestURI) {
+        return this.filterRegistry.getFilterHolders(servletHolder, dispatcherType, requestURI);
+    }
+
+    public void removeErrorPage(ServletInfo servletInfo) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void addErrorPage(ServletHandler handler, String[] errorPages) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public ErrorsMapping getErrorsMapping()
+    {
+        return new ErrorsMapping();
+    }
+
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletHandler.java
index fbdbfcf..cf88e06 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletHandler.java
@@ -52,6 +52,8 @@
             pr.servletPath = matcher.groupCount() > 0 ? matcher.group(1) : matcher.group();
             pr.pathInfo = UriUtils.compactPath(UriUtils.relativePath(pr.servletPath, requestURI));
             pr.holder = this.holder;
+
+            return pr;
         }
 
         return null;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
index 9154e04..80a2fd1 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
@@ -35,15 +35,38 @@
 /**
  * The servlet registry keeps the mappings for all servlets (by using their pattern)
  * for a single servlet context.
+ *
+ * TODO - servlet name handling
+ *
+ * TODO - sort active servlet mappings by pattern length, longest first (avoids looping over all)
  */
 public final class ServletRegistry
 {
-    private final Map<String, ServletHandler> activateServletMapping = new ConcurrentHashMap<String, ServletHandler>();
+    private final Map<String, ServletHandler> activeServletMappings = new ConcurrentHashMap<String, ServletHandler>();
 
-    private final Map<String, List<ServletHolder>> inactivateServletMapping = new HashMap<String, List<ServletHolder>>();
+    private final Map<String, List<ServletHolder>> inactiveServletMappings = new HashMap<String, List<ServletHolder>>();
 
     private final Map<ServletInfo, ServletRegistrationStatus> statusMapping = new ConcurrentHashMap<ServletInfo, ServletRegistry.ServletRegistrationStatus>();
 
+    private final Map<String, List<ServletNameStatus>> servletsByName = new ConcurrentHashMap<String, List<ServletNameStatus>>();
+
+    private static final class ServletNameStatus implements Comparable<ServletNameStatus>
+    {
+        public volatile boolean isActive = false;
+        public final ServletHolder holder;
+
+        public ServletNameStatus(final ServletHolder h)
+        {
+            this.holder = h;
+        }
+
+        @Override
+        public int compareTo(final ServletNameStatus o)
+        {
+            return holder.compareTo(o.holder);
+        }
+    }
+
     public static final class ServletRegistrationStatus
     {
         public final Map<String, Integer> pathToStatus = new ConcurrentHashMap<String, Integer>();
@@ -53,7 +76,7 @@
     {
         int len = -1;
         PathResolution candidate = null;
-        for(final Map.Entry<String, ServletHandler> entry : this.activateServletMapping.entrySet())
+        for(final Map.Entry<String, ServletHandler> entry : this.activeServletMappings.entrySet())
         {
             final PathResolution pr = entry.getValue().resolve(relativeRequestURI);
             if ( pr != null && entry.getKey().length() > len )
@@ -66,7 +89,8 @@
     }
 
     /**
-     * Add a servlet
+     * Add a servlet.
+     *
      * @param holder The servlet holder
      */
     public void addServlet(@Nonnull final ServletHolder holder)
@@ -79,7 +103,7 @@
         {
             for(final String pattern : holder.getServletInfo().getPatterns())
             {
-                final ServletHandler regHandler = this.activateServletMapping.get(pattern);
+                final ServletHandler regHandler = this.activeServletMappings.get(pattern);
                 if ( regHandler != null )
                 {
                     if ( regHandler.getServletHolder().getServletInfo().getServiceReference().compareTo(holder.getServletInfo().getServiceReference()) < 0 )
@@ -87,6 +111,7 @@
                         // replace if no error with new servlet
                         if ( this.tryToActivate(pattern, holder, status) )
                         {
+//                            nameStatus.isActive = true;
                             regHandler.getServletHolder().destroy();
 
                             this.addToInactiveList(pattern, regHandler.getServletHolder(), this.statusMapping.get(regHandler.getServletHolder().getServletInfo()));
@@ -101,7 +126,10 @@
                 else
                 {
                     // add to active
-                    this.tryToActivate(pattern, holder, status);
+                    if ( this.tryToActivate(pattern, holder, status) )
+                    {
+//                        nameStatus.isActive = true;
+                    }
                 }
             }
             this.statusMapping.put(holder.getServletInfo(), status);
@@ -112,7 +140,7 @@
      * Remove a servlet
      * @param info The servlet info
      */
-    public void removeServlet(@Nonnull final ServletInfo info)
+    public void removeServlet(@Nonnull final ServletInfo info, final boolean destroy)
     {
         if ( info.getPatterns() != null )
         {
@@ -122,14 +150,14 @@
             for(final String pattern : info.getPatterns())
             {
 
-                final ServletHandler regHandler = this.activateServletMapping.get(pattern);
+                final ServletHandler regHandler = this.activeServletMappings.get(pattern);
                 if ( regHandler != null && regHandler.getServletHolder().getServletInfo().equals(info) )
                 {
                     cleanupHolder = regHandler.getServletHolder();
-                    final List<ServletHolder> inactiveList = this.inactivateServletMapping.get(pattern);
+                    final List<ServletHolder> inactiveList = this.inactiveServletMappings.get(pattern);
                     if ( inactiveList == null )
                     {
-                        this.activateServletMapping.remove(pattern);
+                        this.activeServletMappings.remove(pattern);
                     }
                     else
                     {
@@ -145,13 +173,13 @@
                         }
                         if ( inactiveList.isEmpty() )
                         {
-                            this.inactivateServletMapping.remove(pattern);
+                            this.inactiveServletMappings.remove(pattern);
                         }
                     }
                 }
                 else
                 {
-                    final List<ServletHolder> inactiveList = this.inactivateServletMapping.get(pattern);
+                    final List<ServletHolder> inactiveList = this.inactiveServletMappings.get(pattern);
                     if ( inactiveList != null )
                     {
                         final Iterator<ServletHolder> i = inactiveList.iterator();
@@ -167,7 +195,7 @@
                         }
                         if ( inactiveList.isEmpty() )
                         {
-                            this.inactivateServletMapping.remove(pattern);
+                            this.inactiveServletMappings.remove(pattern);
                         }
                     }
                 }
@@ -182,11 +210,11 @@
 
     private void addToInactiveList(final String pattern, final ServletHolder holder, final ServletRegistrationStatus status)
     {
-        List<ServletHolder> inactiveList = this.inactivateServletMapping.get(pattern);
+        List<ServletHolder> inactiveList = this.inactiveServletMappings.get(pattern);
         if ( inactiveList == null )
         {
             inactiveList = new ArrayList<ServletHolder>();
-            this.inactivateServletMapping.put(pattern, inactiveList);
+            this.inactiveServletMappings.put(pattern, inactiveList);
         }
         inactiveList.add(holder);
         Collections.sort(inactiveList);
@@ -201,7 +229,7 @@
         {
             final Pattern p = Pattern.compile(PatternUtil.convertToRegEx(pattern));
             final ServletHandler handler = new ServletHandler(holder, p);
-            this.activateServletMapping.put(pattern, handler);
+            this.activeServletMappings.put(pattern, handler);
 
             // add ok
             status.pathToStatus.put(pattern, result);
@@ -219,4 +247,18 @@
     {
         return this.statusMapping;
     }
+
+    public ServletHolder resolveByName(@Nonnull String name)
+    {
+        final List<ServletNameStatus> holderList = this.servletsByName.get(name);
+        if ( holderList != null )
+        {
+            final ServletNameStatus status = holderList.get(0);
+            if ( status != null && status.isActive )
+            {
+                return status.holder;
+            }
+        }
+        return null;
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java
index 9c1a9be..3e4af26 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java
@@ -16,11 +16,9 @@
  */
 package org.apache.felix.http.base.internal.runtime.dto;
 
-import static java.util.Arrays.asList;
-
-import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
-import org.apache.felix.http.base.internal.handler.ServletHandler;
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.registry.PathResolution;
 import org.osgi.service.http.runtime.dto.FilterDTO;
 import org.osgi.service.http.runtime.dto.RequestInfoDTO;
 
@@ -39,19 +37,24 @@
 
     public RequestInfoDTO build()
     {
-        ServletHandler servletHandler = registry.getServletHandler(path);
-        FilterHandler[] filterHandlers = registry.getFilterHandlers(servletHandler, null, path);
-        Long contextServiceId = servletHandler.getContextServiceId();
+        PathResolution pr = registry.resolveServlet(path);
+        if ( pr == null )
+        {
+            // TODO what do we return?
+            return null;
+        }
+        FilterHolder[] filterHolders = registry.getFilters(pr.holder, null, path);
+        Long contextServiceId = pr.holder.getContextServiceId();
 
         RequestInfoDTO requestInfoDTO = new RequestInfoDTO();
         requestInfoDTO.path = path;
         requestInfoDTO.servletContextId = contextServiceId;
 
+        /* TODO
         requestInfoDTO.filterDTOs = FilterDTOBuilder.create()
-                .build(asList(filterHandlers), contextServiceId)
+                .build(asList(filterHolders), contextServiceId)
                 .toArray(FILTER_DTO_ARRAY);
-
-        if (servletHandler.getServletInfo().isResource())
+        if (pr.holder.getServletInfo().isResource())
         {
             requestInfoDTO.resourceDTO = ResourceDTOBuilder.create()
                     .buildDTO(servletHandler, contextServiceId);
@@ -61,6 +64,7 @@
             requestInfoDTO.servletDTO = ServletDTOBuilder.create()
                     .buildDTO(servletHandler, contextServiceId);
         }
+        */
         return requestInfoDTO;
     }
 }
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 7634f39..0fea14c 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
@@ -20,6 +20,7 @@
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -33,6 +34,8 @@
 
 import org.apache.felix.http.api.ExtHttpService;
 import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.HttpServiceFilterHolder;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
@@ -49,7 +52,7 @@
 {
     private final Bundle bundle;
     private final Set<Servlet> localServlets = new HashSet<Servlet>();
-    private final Set<Filter> localFilters = new HashSet<Filter>();
+    private final Set<FilterHolder> localFilters = new HashSet<FilterHolder>();
     private final ServletContextManager contextManager;
     private final SharedHttpServiceImpl sharedHttpService;
 
@@ -120,12 +123,13 @@
         }
 
         final ExtServletContext httpContext = getServletContext(context);
+        final FilterHolder holder = new HttpServiceFilterHolder(0, httpContext, filterInfo, filter);
 
-        if ( this.sharedHttpService.registerFilter(httpContext, filter, filterInfo) )
+        if ( this.sharedHttpService.registerFilter(holder) )
         {
             synchronized ( this.localFilters )
             {
-                this.localFilters.add(filter);
+                this.localFilters.add(holder);
             }
         }
     }
@@ -239,10 +243,10 @@
             unregisterServlet(servlet, false);
         }
 
-        final Set<Filter> filters = new HashSet<Filter>(this.localFilters);
-        for (final Filter fiter : filters)
+        final Set<FilterHolder> filters = new HashSet<FilterHolder>(this.localFilters);
+        for (final FilterHolder holder : filters)
         {
-            unregisterFilter(fiter, false);
+            this.sharedHttpService.unregisterFilter(holder, false);
         }
     }
 
@@ -288,15 +292,24 @@
         return this.contextManager.getServletContext(context);
     }
 
-    private void unregisterFilter(Filter filter, final boolean destroy)
+    private void unregisterFilter(final Filter filter, final boolean destroy)
     {
         if (filter != null)
         {
             synchronized ( this.localFilters )
             {
-                this.localFilters.remove(filter);
+                final Iterator<FilterHolder> i = this.localFilters.iterator();
+                while ( i.hasNext() )
+                {
+                    final FilterHolder h = i.next();
+                    if ( h.getFilter() == filter )
+                    {
+                        this.sharedHttpService.unregisterFilter(h, destroy);
+                        i.remove();
+                        break;
+                    }
+                }
             }
-            this.sharedHttpService.unregisterFilter(filter, destroy);
         }
     }
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
index ce12148..bd478f4 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
@@ -21,16 +21,14 @@
 import java.util.Map;
 
 import javax.annotation.Nonnull;
-import javax.servlet.Filter;
 import javax.servlet.Servlet;
 import javax.servlet.ServletException;
 
 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.HandlerRegistry;
-import org.apache.felix.http.base.internal.handler.ServletHandler;
-import org.apache.felix.http.base.internal.handler.SimpleServletHandler;
-import org.apache.felix.http.base.internal.runtime.FilterInfo;
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.HttpServiceServletHolder;
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.osgi.service.http.NamespaceException;
 
@@ -38,7 +36,7 @@
 {
     private final HandlerRegistry handlerRegistry;
 
-    private final Map<String, ServletHandler> aliasMap = new HashMap<String, ServletHandler>();
+    private final Map<String, ServletHolder> aliasMap = new HashMap<String, ServletHolder>();
 
     public SharedHttpServiceImpl(final HandlerRegistry handlerRegistry)
     {
@@ -53,21 +51,10 @@
     /**
      * Register a filter
      */
-    public boolean registerFilter(@Nonnull final ExtServletContext httpContext,
-            @Nonnull final Filter filter,
-            @Nonnull final FilterInfo filterInfo)
+    public boolean registerFilter(@Nonnull final FilterHolder holder)
     {
-        final FilterHandler handler = new FilterHandler(null, httpContext, filter, filterInfo);
-        try
-        {
-            this.handlerRegistry.addFilter(handler);
-            return true;
-        }
-        catch (final ServletException e)
-        {
-            // TODO create failure DTO
-        }
-        return false;
+        this.handlerRegistry.addFilter(holder);
+        return true;
     }
 
     /**
@@ -78,7 +65,7 @@
             @Nonnull final Servlet servlet,
             @Nonnull final ServletInfo servletInfo) throws ServletException, NamespaceException
     {
-        final ServletHandler handler = new SimpleServletHandler(httpContext, servletInfo, servlet);
+        final ServletHolder holder = new HttpServiceServletHolder(0, httpContext, servletInfo, servlet);
 
         synchronized (this.aliasMap)
         {
@@ -86,9 +73,9 @@
             {
                 throw new NamespaceException("Alias " + alias + " is already in use.");
             }
-            this.handlerRegistry.addServlet(handler);
+            this.handlerRegistry.addServlet(holder);
 
-            this.aliasMap.put(alias, handler);
+            this.aliasMap.put(alias, holder);
         }
     }
 
@@ -99,13 +86,15 @@
     {
         synchronized (this.aliasMap)
         {
-            final ServletHandler handler = this.aliasMap.remove(alias);
-            if (handler == null)
+            final ServletHolder holder = this.aliasMap.remove(alias);
+            if (holder == null)
             {
                 throw new IllegalArgumentException("Nothing registered at " + alias);
             }
 
-            return this.handlerRegistry.removeServlet(handler.getServletInfo());
+            final Servlet s = holder.getServlet();
+            this.handlerRegistry.removeServlet(0, holder.getServletInfo(), true);
+            return s;
         }
     }
 
@@ -113,16 +102,16 @@
     {
         if (servlet != null)
         {
-            this.handlerRegistry.removeServlet(servlet, destroy);
-
             synchronized (this.aliasMap)
             {
-                final Iterator<Map.Entry<String, ServletHandler>> i = this.aliasMap.entrySet().iterator();
+                final Iterator<Map.Entry<String, ServletHolder>> i = this.aliasMap.entrySet().iterator();
                 while (i.hasNext())
                 {
-                    final Map.Entry<String, ServletHandler> entry = i.next();
+                    final Map.Entry<String, ServletHolder> entry = i.next();
                     if (entry.getValue().getServlet() == servlet)
                     {
+                        this.handlerRegistry.removeServlet(0, entry.getValue().getServletInfo(), destroy);
+
                         i.remove();
                         break;
                     }
@@ -132,11 +121,11 @@
         }
     }
 
-    public void unregisterFilter(final Filter filter, final boolean destroy)
+    public void unregisterFilter(final FilterHolder filter, final boolean destroy)
     {
         if (filter != null)
         {
-            this.handlerRegistry.removeFilter(filter, destroy);
+            this.handlerRegistry.removeFilter(filter.getContextServiceId(), filter.getFilterInfo(), destroy);
         }
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
index 7ff0f45..d14f591 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
@@ -16,18 +16,14 @@
  */
 package org.apache.felix.http.base.internal.whiteboard;
 
-import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT;
-import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
-
 import javax.annotation.Nonnull;
-import javax.servlet.Filter;
-import javax.servlet.ServletException;
 
-import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
-import org.apache.felix.http.base.internal.handler.ResourceServletHandler;
-import org.apache.felix.http.base.internal.handler.ServletHandler;
-import org.apache.felix.http.base.internal.handler.WhiteboardServletHandler;
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.HttpServiceServletHolder;
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
+import org.apache.felix.http.base.internal.handler.holder.WhiteboardFilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.WhiteboardServletHolder;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.ResourceInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
@@ -59,28 +55,12 @@
      */
     public void registerServlet(@Nonnull final ContextHandler contextHandler,
             @Nonnull final ServletInfo servletInfo)
-            throws RegistrationFailureException
     {
-        // we need to check each and every pattern individually
-        if ( servletInfo.getPatterns() != null )
-        {
-            for(final String pattern : servletInfo.getPatterns() ) {
-
-            }
-        }
-        try
-        {
-            ServletHandler handler = new WhiteboardServletHandler(contextHandler.getContextInfo(),
+        final ServletHolder holder = new WhiteboardServletHolder(
+                contextHandler.getContextInfo().getServiceId(),
                 contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
-                servletInfo,
-                bundleContext);
-
-            handlerRegistry.addServlet(handler);
-        }
-        catch (final RegistrationFailureException e)
-        {
-            throw e;
-        }
+                servletInfo, bundleContext);
+        handlerRegistry.addServlet(holder);
     }
 
     /**
@@ -91,7 +71,7 @@
      */
     public void unregisterServlet(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletInfo servletInfo) throws RegistrationFailureException
     {
-        handlerRegistry.removeServlet(contextHandler.getContextInfo().getServiceId(), servletInfo);
+        handlerRegistry.removeServlet(contextHandler.getContextInfo().getServiceId(), servletInfo, true);
         contextHandler.ungetServletContext(servletInfo.getServiceReference().getBundle());
     }
 
@@ -99,34 +79,15 @@
      * Register a filter
      * @param contextInfo The servlet context helper info
      * @param filterInfo The filter info
-     * @throws RegistrationFailureException
      */
     public void registerFilter(@Nonnull  final ContextHandler contextHandler,
-            @Nonnull final FilterInfo filterInfo) throws RegistrationFailureException
+            @Nonnull final FilterInfo filterInfo)
     {
-        final Filter filter = this.bundleContext.getServiceObjects(filterInfo.getServiceReference()).getService();
-        if ( filter != null )
-        {
-            final FilterHandler handler = new FilterHandler(contextHandler.getContextInfo(),
-                    contextHandler.getServletContext(filterInfo.getServiceReference().getBundle()),
-                    filter,
-                    filterInfo);
-            try {
-                handlerRegistry.addFilter(contextHandler.getContextInfo(), handler);
-            }
-            catch (final RegistrationFailureException e)
-            {
-                throw e;
-            }
-            catch (final ServletException e)
-            {
-                throw new RegistrationFailureException(filterInfo, FAILURE_REASON_EXCEPTION_ON_INIT, e);
-            }
-        }
-        else
-        {
-            throw new RegistrationFailureException(filterInfo, FAILURE_REASON_SERVICE_NOT_GETTABLE);
-        }
+        final FilterHolder holder = new WhiteboardFilterHolder(
+                contextHandler.getContextInfo().getServiceId(),
+                contextHandler.getServletContext(filterInfo.getServiceReference().getBundle()),
+                filterInfo, bundleContext);
+        handlerRegistry.addFilter(holder);
     }
 
     /**
@@ -136,11 +97,7 @@
      */
     public void unregisterFilter(@Nonnull final ContextHandler contextHandler, @Nonnull final FilterInfo filterInfo)
     {
-        final Filter instance = handlerRegistry.removeFilter(contextHandler.getContextInfo(), filterInfo);
-        if ( instance != null )
-        {
-            this.bundleContext.getServiceObjects(filterInfo.getServiceReference()).ungetService(instance);
-        }
+        handlerRegistry.removeFilter(contextHandler.getContextInfo().getServiceId(), filterInfo, true);
         contextHandler.ungetServletContext(filterInfo.getServiceReference().getBundle());
     }
 
@@ -151,22 +108,16 @@
      * @throws RegistrationFailureException
      */
     public void registerResource(@Nonnull final ContextHandler contextHandler,
-            @Nonnull final ResourceInfo resourceInfo) throws RegistrationFailureException
+            @Nonnull final ResourceInfo resourceInfo)
     {
         final ServletInfo servletInfo = new ServletInfo(resourceInfo);
 
-        final ServletHandler handler = new ResourceServletHandler(contextHandler.getContextInfo(),
-            contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
-            servletInfo);
+        final ServletHolder holder = new HttpServiceServletHolder(
+                contextHandler.getContextInfo().getServiceId(),
+                contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
+                servletInfo, new ResourceServlet(resourceInfo.getPrefix()));
 
-        try
-        {
-            handlerRegistry.addServlet(handler);
-        }
-        catch (ServletException e)
-        {
-            throw new RegistrationFailureException(resourceInfo, FAILURE_REASON_EXCEPTION_ON_INIT, e);
-        }
+        handlerRegistry.addServlet(holder);
     }
 
     /**
@@ -178,7 +129,7 @@
     public void unregisterResource(@Nonnull final ContextHandler contextHandler, @Nonnull final ResourceInfo resourceInfo) throws RegistrationFailureException
     {
         final ServletInfo servletInfo = new ServletInfo(resourceInfo);
-        handlerRegistry.removeServlet(contextHandler.getContextInfo().getServiceId(), servletInfo);
+        handlerRegistry.removeServlet(contextHandler.getContextInfo().getServiceId(), servletInfo, true);
         contextHandler.ungetServletContext(servletInfo.getServiceReference().getBundle());
     }
 
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 6aa33fe..3e9321e 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
@@ -617,11 +617,6 @@
                 handler.getListenerRegistry().addListener((ServletRequestAttributeListenerInfo) info);
             }
         }
-        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);
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java
index bc555b7..f186e7b 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java
@@ -36,29 +36,35 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.dispatch.InvocationChain;
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.HttpServiceFilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 
-public class FilterHandlerTest extends AbstractHandlerTest
+public class FilterHandlerTest
 {
     private Filter filter;
 
-    @Override
+    private ExtServletContext context;
+
     @Before
     public void setUp()
     {
-        super.setUp();
+        this.context = Mockito.mock(ExtServletContext.class);
         this.filter = mock(Filter.class);
     }
 
     @Test
     public void testCompare()
     {
-        FilterHandler h1 = createHandler(0, "a");
-        FilterHandler h2 = createHandler(10, "b");
-        FilterHandler h3 = createHandler(10, "c");
+        FilterHolder h1 = createHandler(0, "a");
+        FilterHolder h2 = createHandler(10, "b");
+        FilterHolder h3 = createHandler(10, "c");
 
         assertTrue(h1.compareTo(h1) == 0);
 
@@ -73,7 +79,8 @@
     @Test
     public void testDestroy()
     {
-        FilterHandler h1 = createHandler(0, "/a");
+        FilterHolder h1 = createHandler(0, "/a");
+        h1.init();
         h1.destroy();
         verify(this.filter).destroy();
     }
@@ -81,7 +88,7 @@
     @Test
     public void testHandleFound() throws Exception
     {
-        FilterHandler h1 = createHandler(0, "/a");
+        FilterHolder h1 = createHandler(0, "/a");
         HttpServletRequest req = createServletRequest();
         HttpServletResponse res = createServletResponse();
         FilterChain chain = mock(FilterChain.class);
@@ -97,7 +104,7 @@
     @Test
     public void testHandleFoundContextRoot() throws Exception
     {
-        FilterHandler h1 = createHandler(0, "/");
+        FilterHolder h1 = createHandler(0, "/");
         HttpServletRequest req = createServletRequest();
         HttpServletResponse res = createServletResponse();
         FilterChain chain = mock(FilterChain.class);
@@ -116,10 +123,10 @@
     @Test
     public void testHandleFoundForbidden() throws Exception
     {
-        FilterHandler h1 = createHandler(0, "/a");
-        final ServletHandler sc = mock(ServletHandler.class);
+        FilterHolder h1 = createHandler(0, "/a");
+        final ServletHolder sc = mock(ServletHolder.class);
         when(sc.getContext()).thenReturn(this.context);
-        final InvocationChain ic = new InvocationChain(sc, new FilterHandler[] {h1});
+        final InvocationChain ic = new InvocationChain(sc, new FilterHolder[] {h1});
         HttpServletRequest req = createServletRequest();
         HttpServletResponse res = createServletResponse();
 
@@ -142,10 +149,10 @@
     @Test
     public void testHandleFoundForbiddenCommittedOwnResponse() throws Exception
     {
-        FilterHandler h1 = createHandler(0, "/a");
-        final ServletHandler sc = mock(ServletHandler.class);
+        FilterHolder h1 = createHandler(0, "/a");
+        final ServletHolder sc = mock(ServletHolder.class);
         when(sc.getContext()).thenReturn(this.context);
-        final InvocationChain ic = new InvocationChain(sc, new FilterHandler[] {h1});
+        final InvocationChain ic = new InvocationChain(sc, new FilterHolder[] {h1});
         HttpServletRequest req = createServletRequest();
         HttpServletResponse res = createServletResponse();
 
@@ -169,10 +176,10 @@
     @Test
     public void testHandleFoundForbiddenCustomStatusCode() throws Exception
     {
-        FilterHandler h1 = createHandler(0, "/a");
-        final ServletHandler sc = mock(ServletHandler.class);
+        FilterHolder h1 = createHandler(0, "/a");
+        final ServletHolder sc = mock(ServletHolder.class);
         when(sc.getContext()).thenReturn(this.context);
-        final InvocationChain ic = new InvocationChain(sc, new FilterHandler[] {h1});
+        final InvocationChain ic = new InvocationChain(sc, new FilterHolder[] {h1});
         HttpServletRequest req = createServletRequest();
         HttpServletResponse res = createServletResponse();
 
@@ -193,10 +200,10 @@
     @Test
     public void testHandleNotFound() throws Exception
     {
-        FilterHandler h1 = createHandler(0, "/a");
-        final ServletHandler sc = mock(ServletHandler.class);
+        FilterHolder h1 = createHandler(0, "/a");
+        final ServletHolder sc = mock(ServletHolder.class);
         when(sc.getContext()).thenReturn(this.context);
-        final InvocationChain ic = new InvocationChain(sc, new FilterHandler[] {h1});
+        final InvocationChain ic = new InvocationChain(sc, new FilterHolder[] {h1});
         HttpServletRequest req = createServletRequest();
         HttpServletResponse res = createServletResponse();
 
@@ -209,10 +216,10 @@
     @Test
     public void testHandleNotFoundContextRoot() throws Exception
     {
-        FilterHandler h1 = createHandler(0, "/a");
-        final ServletHandler sc = mock(ServletHandler.class);
+        FilterHolder h1 = createHandler(0, "/a");
+        final ServletHolder sc = mock(ServletHolder.class);
         when(sc.getContext()).thenReturn(this.context);
-        final InvocationChain ic = new InvocationChain(sc, new FilterHandler[] {h1});
+        final InvocationChain ic = new InvocationChain(sc, new FilterHolder[] {h1});
         HttpServletRequest req = createServletRequest();
         HttpServletResponse res = createServletResponse();
 
@@ -225,36 +232,24 @@
     @Test
     public void testInit() throws Exception
     {
-        FilterHandler h1 = createHandler(0, "/a");
+        FilterHolder h1 = createHandler(0, "/a");
         h1.init();
         verify(this.filter).init(any(FilterConfig.class));
     }
 
-   @Override
-    protected AbstractHandler createHandler()
-    {
-        return createHandler(0, "dummy");
-    }
-
-    @Override
-    protected AbstractHandler createHandler(final Map<String, String> initParams)
-    {
-        return createHandler("dummy", 0, initParams);
-    }
-
-    private FilterHandler createHandler(int ranking, String pattern)
+    private FilterHolder createHandler(int ranking, String pattern)
     {
         return createHandler(pattern, ranking, null);
     }
 
-    private FilterHandler createHandler(String pattern, int ranking, Map<String, String> initParams)
+    private FilterHolder createHandler(String pattern, int ranking, Map<String, String> initParams)
     {
         if ( initParams == null )
         {
             initParams = Collections.emptyMap();
         }
         final FilterInfo info = new FilterInfo(null, pattern, ranking, initParams);
-        return new FilterHandler(null, this.context, this.filter, info);
+        return new HttpServiceFilterHolder(0, this.context, info, this.filter);
     }
 
     private HttpServletRequest createServletRequest()
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/SimpleServletHandlerTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/SimpleServletHandlerTest.java
index 9ba64a1..4c7c4aa 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/SimpleServletHandlerTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/SimpleServletHandlerTest.java
@@ -34,27 +34,34 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.dispatch.InvocationChain;
+import org.apache.felix.http.base.internal.handler.holder.FilterHolder;
+import org.apache.felix.http.base.internal.handler.holder.HttpServiceServletHolder;
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 
-public class SimpleServletHandlerTest extends AbstractHandlerTest
+public class SimpleServletHandlerTest
 {
     private Servlet servlet;
 
-    @Override
+    private ExtServletContext context;
+
     @Before
     public void setUp()
     {
-        super.setUp();
+        this.context = Mockito.mock(ExtServletContext.class);
         this.servlet = mock(Servlet.class);
     }
 
     @Test
     public void testDestroy()
     {
-        ServletHandler h1 = createHandler("/a");
+        ServletHolder h1 = createHandler("/a");
+        h1.init();
         h1.destroy();
         verify(this.servlet).destroy();
     }
@@ -62,8 +69,8 @@
     @Test
     public void testHandleFound() throws Exception
     {
-        ServletHandler h1 = createHandler("/a");
-        final InvocationChain ic = new InvocationChain(h1, new FilterHandler[0]);
+        ServletHolder h1 = createHandler("/a");
+        final InvocationChain ic = new InvocationChain(h1, new FilterHolder[0]);
         HttpServletRequest req = mock(HttpServletRequest.class);
         HttpServletResponse res = mock(HttpServletResponse.class);
         when(this.context.handleSecurity(req, res)).thenReturn(true);
@@ -78,8 +85,8 @@
     @Test
     public void testHandleFoundContextRoot() throws Exception
     {
-        ServletHandler h1 = createHandler("/");
-        final InvocationChain ic = new InvocationChain(h1, new FilterHandler[0]);
+        ServletHolder h1 = createHandler("/");
+        final InvocationChain ic = new InvocationChain(h1, new FilterHolder[0]);
         HttpServletRequest req = mock(HttpServletRequest.class);
         HttpServletResponse res = mock(HttpServletResponse.class);
         when(this.context.handleSecurity(req, res)).thenReturn(true);
@@ -97,8 +104,8 @@
     @Test
     public void testHandleFoundForbidden() throws Exception
     {
-        ServletHandler h1 = createHandler("/a");
-        final InvocationChain ic = new InvocationChain(h1, new FilterHandler[0]);
+        ServletHolder h1 = createHandler("/a");
+        final InvocationChain ic = new InvocationChain(h1, new FilterHolder[0]);
         HttpServletRequest req = mock(HttpServletRequest.class);
         HttpServletResponse res = mock(HttpServletResponse.class);
 
@@ -123,8 +130,8 @@
     @Test
     public void testHandleFoundForbiddenCommittedOwnResponse() throws Exception
     {
-        ServletHandler h1 = createHandler("/a");
-        final InvocationChain ic = new InvocationChain(h1, new FilterHandler[0]);
+        ServletHolder h1 = createHandler("/a");
+        final InvocationChain ic = new InvocationChain(h1, new FilterHolder[0]);
         HttpServletRequest req = mock(HttpServletRequest.class);
         HttpServletResponse res = mock(HttpServletResponse.class);
 
@@ -149,8 +156,8 @@
     @Test
     public void testHandleFoundForbiddenCustomStatusCode() throws Exception
     {
-        ServletHandler h1 = createHandler("/a");
-        final InvocationChain ic = new InvocationChain(h1, new FilterHandler[0]);
+        ServletHolder h1 = createHandler("/a");
+        final InvocationChain ic = new InvocationChain(h1, new FilterHolder[0]);
         HttpServletRequest req = mock(HttpServletRequest.class);
         HttpServletResponse res = mock(HttpServletResponse.class);
 
@@ -172,8 +179,8 @@
     @Test
     public void testHandleNotFound() throws Exception
     {
-        ServletHandler h1 = createHandler("/a");
-        final InvocationChain ic = new InvocationChain(h1, new FilterHandler[0]);
+        ServletHolder h1 = createHandler("/a");
+        final InvocationChain ic = new InvocationChain(h1, new FilterHolder[0]);
         HttpServletRequest req = mock(HttpServletRequest.class);
         HttpServletResponse res = mock(HttpServletResponse.class);
 
@@ -186,7 +193,7 @@
     @Test
     public void testHandleNotFoundContextRoot() throws Exception
     {
-        ServletHandler h1 = createHandler("/a");
+        ServletHolder h1 = createHandler("/a");
         HttpServletRequest req = mock(HttpServletRequest.class);
         HttpServletResponse res = mock(HttpServletResponse.class);
         when(this.context.handleSecurity(req, res)).thenReturn(true);
@@ -200,35 +207,23 @@
     @Test
     public void testInit() throws Exception
     {
-        ServletHandler h1 = createHandler("/a");
+        ServletHolder h1 = createHandler("/a");
         h1.init();
         verify(this.servlet).init(any(ServletConfig.class));
     }
 
-    @Override
-    protected AbstractHandler createHandler()
-    {
-        return createHandler("/dummy", null);
-    }
-
-    @Override
-    protected AbstractHandler createHandler(Map<String, String> map)
-    {
-        return createHandler("/dummy", map);
-    }
-
-    private ServletHandler createHandler(String alias)
+    private ServletHolder createHandler(String alias)
     {
         return createHandler(alias, null);
     }
 
-    private ServletHandler createHandler(String alias, Map<String, String> map)
+    private ServletHolder createHandler(String alias, Map<String, String> map)
     {
         if ( map == null )
         {
             map = Collections.emptyMap();
         }
         final ServletInfo info = new ServletInfo(null, alias, 0, map);
-        return new SimpleServletHandler(this.context, info, this.servlet);
+        return new HttpServiceServletHolder(3, this.context, info, this.servlet);
     }
 }
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
index 9bba212..3f050e4 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
@@ -19,13 +19,17 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.util.Map;
 
 import javax.servlet.Servlet;
-import javax.servlet.ServletContext;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.holder.HttpServiceServletHolder;
 import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
@@ -43,7 +47,7 @@
 
     private final ServletRegistry reg = new ServletRegistry();
 
-    @Test public void testSingleServlet() throws InvalidSyntaxException
+    @Test public void testSingleServlet() throws InvalidSyntaxException, ServletException
     {
         final Map<ServletInfo, ServletRegistry.ServletRegistrationStatus> status = reg.getServletStatusMapping();
         // empty reg
@@ -53,6 +57,8 @@
         final ServletHolder h1 = createServletHolder(1L, 0, "/foo");
         reg.addServlet(h1);
 
+        verify(h1.getServlet()).init(Matchers.any(ServletConfig.class));
+
         // one entry in reg
         assertEquals(1, status.size());
         assertNotNull(status.get(h1.getServletInfo()));
@@ -61,13 +67,15 @@
         assertEquals(-1, code);
 
         // remove servlet
-        reg.removeServlet(h1.getServletInfo());
+        final Servlet s = h1.getServlet();
+        reg.removeServlet(h1.getServletInfo(), true);
+        verify(s).destroy();
 
         // empty again
         assertEquals(0, status.size());
     }
 
-    @Test public void testSimpleHiding() throws InvalidSyntaxException
+    @Test public void testSimpleHiding() throws InvalidSyntaxException, ServletException
     {
         final Map<ServletInfo, ServletRegistry.ServletRegistrationStatus> status = reg.getServletStatusMapping();
         // empty reg
@@ -76,9 +84,12 @@
         // register servlets
         final ServletHolder h1 = createServletHolder(1L, 10, "/foo");
         reg.addServlet(h1);
+        verify(h1.getServlet()).init(Matchers.any(ServletConfig.class));
 
         final ServletHolder h2 = createServletHolder(2L, 0, "/foo");
         reg.addServlet(h2);
+        verify(h2.getServlet(), never()).init(Matchers.any(ServletConfig.class));
+        verify(h1.getServlet(), never()).destroy();
 
         // two entries in reg
         assertEquals(2, status.size());
@@ -96,7 +107,10 @@
         assertEquals(DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, code2);
 
         // remove servlet 1
-        reg.removeServlet(h1.getServletInfo());
+        final Servlet s1 = h1.getServlet();
+        reg.removeServlet(h1.getServletInfo(), true);
+        verify(s1).destroy();
+        verify(h2.getServlet()).init(Matchers.any(ServletConfig.class));
 
         // h2 is active
         assertEquals(1, status.size());
@@ -105,7 +119,9 @@
         assertEquals(-1, code3);
 
         // remove servlet 2
-        reg.removeServlet(h2.getServletInfo());
+        final Servlet s2 = h2.getServlet();
+        reg.removeServlet(h2.getServletInfo(), true);
+        verify(s2).destroy();
 
         // empty again
         assertEquals(0, status.size());
@@ -132,9 +148,9 @@
     private static ServletHolder createServletHolder(final long id, final int ranking, final String... paths) throws InvalidSyntaxException
     {
         final ServletInfo si = createServletInfo(id, ranking, paths);
-        final ServletContext ctx = mock(ServletContext.class);
+        final ExtServletContext ctx = mock(ExtServletContext.class);
         final Servlet servlet = mock(Servlet.class);
 
-        return new HttpServiceServletHolder(ctx, si, servlet);
+        return new HttpServiceServletHolder(7, ctx, si, servlet);
     }
 }