You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cz...@apache.org on 2015/02/02 14:44:01 UTC

svn commit: r1656459 - in /felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal: ./ dispatch/ handler/ runtime/ service/ util/ whiteboard/

Author: cziegeler
Date: Mon Feb  2 13:44:01 2015
New Revision: 1656459

URL: http://svn.apache.org/r1656459
Log:
FELIX-4780 : [RFC189] Revisit error page implementation

Added:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java   (with props)
Modified:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/DispatcherServlet.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/DispatcherServlet.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/DispatcherServlet.java?rev=1656459&r1=1656458&r2=1656459&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/DispatcherServlet.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/DispatcherServlet.java Mon Feb  2 13:44:01 2015
@@ -54,11 +54,6 @@ public final class DispatcherServlet ext
         super.destroy();
     }
 
-    public boolean handleError(HttpServletRequest request, HttpServletResponse response, int errorCode, String exceptionType) throws IOException
-    {
-        return this.controller.getDispatcher().handleError(request, response, errorCode, exceptionType);
-    }
-
     @Override
     protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
     {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java?rev=1656459&r1=1656458&r2=1656459&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java Mon Feb  2 13:44:01 2015
@@ -24,6 +24,7 @@ import org.apache.felix.http.api.ExtHttp
 import org.apache.felix.http.base.internal.dispatch.Dispatcher;
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
 import org.apache.felix.http.base.internal.handler.HttpServicePlugin;
+import org.apache.felix.http.base.internal.handler.PerContextHandlerRegistry;
 import org.apache.felix.http.base.internal.listener.HttpSessionAttributeListenerManager;
 import org.apache.felix.http.base.internal.listener.HttpSessionListenerManager;
 import org.apache.felix.http.base.internal.listener.ServletContextAttributeListenerManager;
@@ -78,6 +79,7 @@ public final class HttpServiceController
     {
         this.bundleContext = bundleContext;
         this.registry = new HandlerRegistry();
+        this.registry.add(new PerContextHandlerRegistry());
         this.dispatcher = new Dispatcher(this.registry);
         this.serviceProps = new Hashtable<String, Object>();
         this.contextAttributeListener = new ServletContextAttributeListenerManager(bundleContext);

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java?rev=1656459&r1=1656458&r2=1656459&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java Mon Feb  2 13:44:01 2015
@@ -31,6 +31,7 @@ import static org.apache.felix.http.base
 import static org.apache.felix.http.base.internal.util.UriUtils.removeDotSegments;
 
 import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.servlet.DispatcherType;
 import javax.servlet.FilterChain;
@@ -42,6 +43,7 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
 import javax.servlet.http.HttpSession;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
@@ -108,6 +110,125 @@ public final class Dispatcher implements
         }
     }
 
+    final class ServletResponseWrapper extends HttpServletResponseWrapper
+    {
+
+        private final HttpServletRequest request;
+
+        private final AtomicInteger invocationCount = new AtomicInteger();
+
+        private final Long serviceId;
+
+        private final String servletName;
+
+        public ServletResponseWrapper(final HttpServletRequest req, final HttpServletResponse res, final ServletHandler servletHandler)
+        {
+            super(res);
+            this.request = req;
+            if ( servletHandler != null )
+            {
+                this.serviceId = servletHandler.getContextServiceId();
+                this.servletName = servletHandler.getName();
+            }
+            else
+            {
+                this.serviceId = null;
+                this.servletName = null;
+            }
+        }
+
+        @Override
+        public void sendError(int sc) throws IOException
+        {
+            sendError(sc, null);
+        }
+
+        @Override
+        public void sendError(final int code, final String message) throws IOException
+        {
+            resetBuffer();
+
+            setStatus(code);
+
+            boolean invokeSuper = true;
+
+            if ( invocationCount.incrementAndGet() == 1 )
+            {
+                // If we are allowed to have a body
+                if (code != SC_NO_CONTENT &&
+                    code != SC_NOT_MODIFIED &&
+                    code != SC_PARTIAL_CONTENT &&
+                    code >= SC_OK)
+                {
+
+                    final ErrorsMapping errorsMapping = handlerRegistry.getErrorsMapping(request.getRequestURI(), this.serviceId);
+                    if ( errorsMapping != null )
+                    {
+                        final String exceptionType = (String)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
+
+                        ServletHandler errorHandler = null;
+
+                        if (exceptionType != null)
+                        {
+                            errorHandler = errorsMapping.get(exceptionType);
+                        }
+
+                        if ( errorHandler == null )
+                        {
+                            errorHandler = errorsMapping.get(code);
+                        }
+
+                        if ( errorHandler != null )
+                        {
+                            try
+                            {
+                                request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, new Integer(code));
+                                if ( message != null )
+                                {
+                                    request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
+                                }
+                                request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
+                                if ( this.servletName != null )
+                                {
+                                    request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, this.servletName);
+                                }
+
+                                final String servletPath = null;
+                                final String pathInfo = request.getRequestURI();
+                                final String queryString = null; // XXX
+
+                                final RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString);
+
+                                final FilterHandler[] filterHandlers = handlerRegistry.getFilterHandlers(errorHandler, DispatcherType.ERROR, request.getRequestURI());
+
+                                invokeChain(filterHandlers, errorHandler, new ServletRequestWrapper(request, errorHandler.getContext(), requestInfo), this);
+
+                                invokeSuper = false;
+                            }
+                            catch (final ServletException e)
+                            {
+                                // ignore
+                            }
+                            finally
+                            {
+                                request.removeAttribute(RequestDispatcher.ERROR_STATUS_CODE);
+                                request.removeAttribute(RequestDispatcher.ERROR_MESSAGE);
+                                request.removeAttribute(RequestDispatcher.ERROR_REQUEST_URI);
+                                request.removeAttribute(RequestDispatcher.ERROR_SERVLET_NAME);
+                                request.removeAttribute(RequestDispatcher.ERROR_EXCEPTION);
+                                request.removeAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
+                            }
+                        }
+                    }
+                }
+            }
+            if ( invokeSuper )
+            {
+                super.sendError(code, message);
+            }
+        }
+    }
+
     final class ServletRequestWrapper extends HttpServletRequestWrapper
     {
         private final DispatcherType type;
@@ -403,11 +524,17 @@ public final class Dispatcher implements
      */
     public void dispatch(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
     {
-        String requestURI = getRequestURI(req);
+        final String requestURI = getRequestURI(req);
 
         // Determine which servlets we should forward the request to...
-        ServletHandler servletHandler = this.handlerRegistry.getServletHander(requestURI);
-        FilterHandler[] filterHandlers = this.handlerRegistry.getFilterHandlers(servletHandler, req.getDispatcherType(), requestURI);
+        final ServletHandler servletHandler = this.handlerRegistry.getServletHander(requestURI);
+
+        final HttpServletResponse wrappedResponse = new ServletResponseWrapper(req, res, servletHandler);
+        if ( servletHandler == null )
+        {
+            wrappedResponse.sendError(404);
+            return;
+        }
 
         // Provides access to the correct request dispatcher...
         req.setAttribute(REQUEST_DISPATCHER_PROVIDER, this);
@@ -421,42 +548,21 @@ public final class Dispatcher implements
 
         try
         {
-            invokeChain(filterHandlers, servletHandler, new ServletRequestWrapper(req, servletContext, requestInfo), res);
+            final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo);
+            final FilterHandler[] filterHandlers = this.handlerRegistry.getFilterHandlers(servletHandler, req.getDispatcherType(), requestURI);
+            invokeChain(filterHandlers, servletHandler, wrappedRequest, wrappedResponse);
         }
-        finally
+        catch ( final Exception e)
         {
-            req.removeAttribute(REQUEST_DISPATCHER_PROVIDER);
-        }
-    }
-
-    public boolean handleError(HttpServletRequest request, HttpServletResponse response, int errorCode, String exceptionType) throws IOException
-    {
-        ErrorsMapping errorsMapping = this.handlerRegistry.getErrorsMapping();
-        ServletHandler errorHandler = null;
+            req.setAttribute(RequestDispatcher.ERROR_EXCEPTION, e);
+            req.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, e.getClass().getName());
 
-        if (exceptionType != null)
-        {
-            errorHandler = errorsMapping.get(exceptionType);
+            wrappedResponse.sendError(500);
         }
-        else
-        {
-            errorHandler = errorsMapping.get(errorCode);
-        }
-
-        if (errorHandler != null)
+        finally
         {
-            // TODO set error attributes! See Servlet 3.0 specification, section 10.9.1...
-            try
-            {
-                return errorHandler.handle(request, response);
-            }
-            catch (ServletException e)
-            {
-                return false; // XXX
-            }
+            req.removeAttribute(REQUEST_DISPATCHER_PROVIDER);
         }
-
-        return false;
     }
 
     @Override

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java?rev=1656459&r1=1656458&r2=1656459&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java Mon Feb  2 13:44:01 2015
@@ -17,280 +17,148 @@
 package org.apache.felix.http.base.internal.handler;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
+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.runtime.ServletContextHelperInfo;
-import org.apache.felix.http.base.internal.runtime.FilterInfo;
-import org.apache.felix.http.base.internal.runtime.ServletInfo;
-import org.osgi.service.http.NamespaceException;
 
 public final class HandlerRegistry
 {
-    private final Map<Servlet, ServletHandler> servletMap = new HashMap<Servlet, ServletHandler>();
-    private final Map<Filter, FilterHandler> filterMap = new HashMap<Filter, FilterHandler>();
-    private final Map<String, Servlet> servletPatternMap= new HashMap<String, Servlet>();
-    private volatile HandlerMapping<ServletHandler> servletMapping = new HandlerMapping<ServletHandler>();
-    private volatile HandlerMapping<FilterHandler> filterMapping = new HandlerMapping<FilterHandler>();
-    private volatile ErrorsMapping errorsMapping = new ErrorsMapping();
+    private volatile List<PerContextHandlerRegistry> registrations = Collections.emptyList();
 
-    public synchronized void addFilter(FilterHandler handler) throws ServletException
+    public void add(@Nonnull PerContextHandlerRegistry registry)
     {
-        if (this.filterMap.containsKey(handler.getFilter()))
+        synchronized ( this )
         {
-            throw new ServletException("Filter instance already registered");
-        }
-
-        handler.init();
-        this.filterMap.put(handler.getFilter(), handler);
+            final List<PerContextHandlerRegistry> updatedList = new ArrayList<PerContextHandlerRegistry>(this.registrations);
+            updatedList.add(registry);
+            Collections.sort(updatedList);
 
-        updateFilterMapping();
+            this.registrations = updatedList;
+        }
     }
 
-    /**
-     * Add a new servlet.
-     */
-    public synchronized void addServlet(ServletContextHelperInfo contextInfo, ServletHandler handler) throws ServletException, NamespaceException
+    public void remove(@Nonnull PerContextHandlerRegistry registry)
     {
-        if (this.servletMap.containsKey(handler.getServlet()))
+        synchronized ( this )
         {
-            // Do not destroy the servlet as the same instance was already registered
-            throw new ServletException("Servlet instance " + handler.getName() + " already registered");
-        }
-
-        // Can be null in case of error-handling servlets...
-        String[] patterns = handler.getServletInfo().getPatterns();
-        int length = patterns == null ? 0 : patterns.length;
+            final List<PerContextHandlerRegistry> updatedList = new ArrayList<PerContextHandlerRegistry>(this.registrations);
+            updatedList.remove(registry);
 
-        for (int i = 0; i < length; i++)
-        {
-            String pattern = contextInfo != null ? contextInfo.getFullPath(patterns[i]) : patterns[i];
-            if (this.servletPatternMap.containsKey(pattern))
-            {
-                throw new ServletException("Servlet instance " + handler.getName() + " already registered");
-            }
-            this.servletPatternMap.put(pattern, handler.getServlet());
-        }
-
-        patterns = handler.getServletInfo().getErrorPage();
-        if ( patterns != null )
-        {
-            for(final String errorPage : patterns)
-            {
-                this.errorsMapping.addErrorServlet(errorPage, handler);
-            }
+            this.registrations = updatedList;
         }
-        handler.init();
-        this.servletMap.put(handler.getServlet(), handler);
-
-        updateServletMapping();
-    }
-
-    public ErrorsMapping getErrorsMapping()
-    {
-        return this.errorsMapping;
     }
 
-    public FilterHandler[] getFilterHandlers(ServletHandler servletHandler, DispatcherType dispatcherType, String requestURI)
+    public PerContextHandlerRegistry getRegistry(final ServletContextHelperInfo info)
     {
-        // See Servlet 3.0 specification, section 6.2.4...
-        List<FilterHandler> result = new ArrayList<FilterHandler>();
-        result.addAll(this.filterMapping.getAllMatches(requestURI));
-
-        // TODO this is not the most efficient/fastest way of doing this...
-        Iterator<FilterHandler> iter = result.iterator();
-        while (iter.hasNext())
+        synchronized ( this )
         {
-            if (!referencesDispatcherType(iter.next(), dispatcherType))
+            for(final PerContextHandlerRegistry r : this.registrations)
             {
-                iter.remove();
+                if ( info == null )
+                {
+                    if ( r.getContextServiceid() == -1)
+                    {
+                        return r;
+                    }
+                }
+                else
+                {
+                    if ( info.getServiceId() == r.getContextServiceid())
+                    {
+                        return r;
+                    }
+                }
             }
+            final PerContextHandlerRegistry reg = new PerContextHandlerRegistry(info);
+            this.add(reg);
+
+            return reg;
         }
+    }
 
-        String servletName = (servletHandler != null) ? servletHandler.getName() : null;
-        // TODO this is not the most efficient/fastest way of doing this...
-        for (FilterHandler filterHandler : this.filterMapping.getAllElements())
+    public ErrorsMapping getErrorsMapping(final String requestURI, final Long serviceId)
+    {
+        final List<PerContextHandlerRegistry> regs = this.registrations;
+        for(final PerContextHandlerRegistry r : regs)
         {
-            if (referencesServletByName(filterHandler, servletName))
+            if ( serviceId != null && serviceId == r.getContextServiceid() )
             {
-                result.add(filterHandler);
+                return r.getErrorsMapping();
             }
-        }
-
-        // TODO - we should already check for the context when building up the result set
-        final Iterator<FilterHandler> i = result.iterator();
-        while ( i.hasNext() )
-        {
-            final FilterHandler handler = i.next();
-            if ( handler.getContextServiceId() != servletHandler.getContextServiceId() )
+            else if ( serviceId == null && requestURI.startsWith(r.getPrefixPath()) )
             {
-                i.remove();
+                return r.getErrorsMapping();
             }
         }
-        return result.toArray(new FilterHandler[result.size()]);
-    }
-
-    public synchronized Servlet getServletByAlias(String alias)
-    {
-        return this.servletPatternMap.get(alias);
-    }
 
-    public ServletHandler getServletHandlerByName(String name)
-    {
-        return this.servletMapping.getByName(name);
+        return null;
     }
 
-    public ServletHandler getServletHander(String requestURI)
-    {
-        // TODO - take servlet context helper ranking and prefix into account (FELIX-4778)
-        return this.servletMapping.getBestMatch(requestURI);
-    }
+    private static FilterHandler[] EMPTY_FILTER_HANDLER = new FilterHandler[0];
 
-    public synchronized void removeAll()
+    public FilterHandler[] getFilterHandlers(final ServletHandler servletHandler,
+            final DispatcherType dispatcherType,
+            final String requestURI)
     {
-        for (Iterator<ServletHandler> it = servletMap.values().iterator(); it.hasNext(); )
+        final long id = servletHandler.getContextServiceId();
+        final List<PerContextHandlerRegistry> regs = this.registrations;
+        for(final PerContextHandlerRegistry r : regs)
         {
-            ServletHandler handler = it.next();
-            it.remove();
-            handler.destroy();
-        }
-
-        for (Iterator<FilterHandler> it = filterMap.values().iterator(); it.hasNext(); )
-        {
-            FilterHandler handler = it.next();
-            it.remove();
-            handler.destroy();
-        }
-
-        this.servletMap.clear();
-        this.filterMap.clear();
-        this.servletPatternMap.clear();
-        this.errorsMapping.clear();
-
-        updateServletMapping();
-        updateFilterMapping();
-    }
-
-    public synchronized void removeFilter(Filter filter, final boolean destroy)
-    {
-        FilterHandler handler = this.filterMap.remove(filter);
-        if (handler != null)
-        {
-            updateFilterMapping();
-            if (destroy)
+            if ( id == r.getContextServiceid() )
             {
-                handler.destroy();
+                return r.getFilterHandlers(servletHandler, dispatcherType, requestURI);
             }
         }
+        return EMPTY_FILTER_HANDLER;
     }
-
-    public synchronized Filter removeFilter(final FilterInfo filterInfo, final boolean destroy)
+/*
+    public synchronized Servlet getServletByAlias(String alias)
     {
-        for(final FilterHandler handler : this.filterMap.values())
-        {
-            if ( handler.getFilterInfo().compareTo(filterInfo) == 0)
-            {
-                this.filterMap.remove(handler.getFilter());
-                updateFilterMapping();
-                if (destroy)
-                {
-                    handler.destroy();
-                }
-                return handler.getFilter();
-            }
-        }
+        return this.servletPatternMap.get(alias);
+    }
+*/
+    public ServletHandler getServletHandlerByName(final String name)
+    {
+        // TODO
         return null;
     }
 
-    public synchronized Servlet removeServlet(final ServletContextHelperInfo contextInfo, ServletInfo servletInfo, final boolean destroy)
+    public ServletHandler getServletHander(final String requestURI)
     {
-        for(final ServletHandler handler : this.servletMap.values())
+        final List<PerContextHandlerRegistry> regs = this.registrations;
+        for(final PerContextHandlerRegistry r : regs)
         {
-            if ( handler.getServletInfo().compareTo(servletInfo) == 0 )
+            if ( requestURI.startsWith(r.getPrefixPath()))
             {
-                this.servletMap.remove(handler.getServlet());
-                updateServletMapping();
-
-                // Can be null in case of error-handling servlets...
-                String[] patterns = handler.getServletInfo().getPatterns();
-                int length = patterns == null ? 0 : patterns.length;
-
-                for (int i = 0; i < length; i++)
+                // TODO - we could stip of the prefix and simplify handler registration
+                final ServletHandler handler = r.getServletHander(requestURI);
+                if ( handler != null )
                 {
-                    this.servletPatternMap.remove(contextInfo.getFullPath(patterns[i]));
+                    return handler;
                 }
-
-                this.errorsMapping.removeServlet(handler.getServlet());
-
-                if (destroy)
-                {
-                    handler.destroy();
-                }
-                return handler.getServlet();
             }
         }
         return null;
     }
 
-    public synchronized void removeServlet(Servlet servlet, final boolean destroy)
+    public synchronized void removeAll()
     {
-        ServletHandler handler = this.servletMap.remove(servlet);
-        if (handler != null)
-        {
-            updateServletMapping();
-
-            // Can be null in case of error-handling servlets...
-            String[] patterns = handler.getServletInfo().getPatterns();
-            int length = patterns == null ? 0 : patterns.length;
-
-            for (int i = 0; i < length; i++)
-            {
-                this.servletPatternMap.remove(patterns[i]);
-            }
+        final List<PerContextHandlerRegistry> list;
 
-            this.errorsMapping.removeServlet(servlet);
+        synchronized ( this )
+        {
+            list = new ArrayList<PerContextHandlerRegistry>(this.registrations);
+            this.registrations = Collections.emptyList();
 
-            if (destroy)
-            {
-                handler.destroy();
-            }
         }
-    }
 
-    private boolean referencesDispatcherType(FilterHandler handler, DispatcherType dispatcherType)
-    {
-        return Arrays.asList(handler.getFilterInfo().getDispatcher()).contains(dispatcherType);
-    }
-
-    private boolean referencesServletByName(FilterHandler handler, String servletName)
-    {
-        if (servletName == null)
+        for(final PerContextHandlerRegistry r : list)
         {
-            return false;
+            r.removeAll();
         }
-        String[] names = handler.getFilterInfo().getServletNames();
-        if (names != null && names.length > 0)
-        {
-            return Arrays.asList(names).contains(servletName);
-        }
-        return false;
-    }
-
-    private void updateFilterMapping()
-    {
-        this.filterMapping = new HandlerMapping<FilterHandler>(this.filterMap.values());
-    }
-
-    private void updateServletMapping()
-    {
-        this.servletMapping = new HandlerMapping<ServletHandler>(this.servletMap.values());
     }
 }

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java?rev=1656459&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java Mon Feb  2 13:44:01 2015
@@ -0,0 +1,353 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.handler;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+
+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.osgi.service.http.NamespaceException;
+
+public final class PerContextHandlerRegistry implements Comparable<PerContextHandlerRegistry>
+{
+    private final Map<Servlet, ServletHandler> servletMap = new HashMap<Servlet, ServletHandler>();
+    private final Map<Filter, FilterHandler> filterMap = new HashMap<Filter, FilterHandler>();
+    private final Map<String, Servlet> servletPatternMap= new HashMap<String, Servlet>();
+    private volatile HandlerMapping<ServletHandler> servletMapping = new HandlerMapping<ServletHandler>();
+    private volatile HandlerMapping<FilterHandler> filterMapping = new HandlerMapping<FilterHandler>();
+    private volatile ErrorsMapping errorsMapping = new ErrorsMapping();
+
+    private final long serviceId;
+
+    private final int ranking;
+
+    private final String prefixPath;
+
+    public PerContextHandlerRegistry() {
+        this.serviceId = -1;
+        this.ranking = Integer.MIN_VALUE;
+        this.prefixPath = "/";
+    }
+
+    public PerContextHandlerRegistry(final ServletContextHelperInfo info)
+    {
+        this.serviceId = info.getServiceId();
+        this.ranking = info.getRanking();
+        this.prefixPath = info.getPath();
+    }
+
+    public synchronized void addFilter(FilterHandler handler) throws ServletException
+    {
+        if (this.filterMap.containsKey(handler.getFilter()))
+        {
+            throw new ServletException("Filter instance already registered");
+        }
+
+        handler.init();
+        this.filterMap.put(handler.getFilter(), handler);
+
+        updateFilterMapping();
+    }
+
+    @Override
+    public int compareTo(final PerContextHandlerRegistry other)
+    {
+        if (other.ranking == this.ranking)
+        {
+            if (other.serviceId == this.serviceId)
+            {
+                return 0;
+            }
+            // service id might be negative, we have to change the behavior in that case
+            if ( this.serviceId < 0 )
+            {
+                if ( other.serviceId > 0 )
+                {
+                    return -1;
+                }
+                return other.serviceId < this.serviceId ? -1 : 1;
+            }
+            if ( other.serviceId < 0 )
+            {
+                return -1;
+            }
+            return other.serviceId > this.serviceId ? -1 : 1;
+        }
+
+        return (other.ranking > this.ranking) ? 1 : -1;
+    }
+
+    /**
+     * Add a new servlet.
+     */
+    public synchronized void addServlet(ServletContextHelperInfo contextInfo, ServletHandler handler) throws ServletException, NamespaceException
+    {
+        if (this.servletMap.containsKey(handler.getServlet()))
+        {
+            // Do not destroy the servlet as the same instance was already registered
+            throw new ServletException("Servlet instance " + handler.getName() + " already registered");
+        }
+
+        // Can be null in case of error-handling servlets...
+        String[] patterns = handler.getServletInfo().getPatterns();
+        int length = patterns == null ? 0 : patterns.length;
+
+        for (int i = 0; i < length; i++)
+        {
+            String pattern = contextInfo != null ? contextInfo.getFullPath(patterns[i]) : patterns[i];
+            if (this.servletPatternMap.containsKey(pattern))
+            {
+                throw new ServletException("Servlet instance " + handler.getName() + " already registered");
+            }
+            this.servletPatternMap.put(pattern, handler.getServlet());
+        }
+
+        patterns = handler.getServletInfo().getErrorPage();
+        if ( patterns != null )
+        {
+            for(final String errorPage : patterns)
+            {
+                this.errorsMapping.addErrorServlet(errorPage, handler);
+            }
+        }
+        handler.init();
+        this.servletMap.put(handler.getServlet(), handler);
+
+        updateServletMapping();
+    }
+
+    public ErrorsMapping getErrorsMapping()
+    {
+        return this.errorsMapping;
+    }
+
+    public FilterHandler[] getFilterHandlers(ServletHandler servletHandler, DispatcherType dispatcherType, String requestURI)
+    {
+        // See Servlet 3.0 specification, section 6.2.4...
+        List<FilterHandler> result = new ArrayList<FilterHandler>();
+        result.addAll(this.filterMapping.getAllMatches(requestURI));
+
+        // TODO this is not the most efficient/fastest way of doing this...
+        Iterator<FilterHandler> iter = result.iterator();
+        while (iter.hasNext())
+        {
+            if (!referencesDispatcherType(iter.next(), dispatcherType))
+            {
+                iter.remove();
+            }
+        }
+
+        String servletName = (servletHandler != null) ? servletHandler.getName() : null;
+        // TODO this is not the most efficient/fastest way of doing this...
+        for (FilterHandler filterHandler : this.filterMapping.getAllElements())
+        {
+            if (referencesServletByName(filterHandler, servletName))
+            {
+                result.add(filterHandler);
+            }
+        }
+
+        // TODO - we should already check for the context when building up the result set
+        final Iterator<FilterHandler> i = result.iterator();
+        while ( i.hasNext() )
+        {
+            final FilterHandler handler = i.next();
+            if ( handler.getContextServiceId() != servletHandler.getContextServiceId() )
+            {
+                i.remove();
+            }
+        }
+        return result.toArray(new FilterHandler[result.size()]);
+    }
+
+    public synchronized Servlet getServletByAlias(String alias)
+    {
+        return this.servletPatternMap.get(alias);
+    }
+
+    public ServletHandler getServletHandlerByName(String name)
+    {
+        return this.servletMapping.getByName(name);
+    }
+
+    public ServletHandler getServletHander(String requestURI)
+    {
+        // TODO - take servlet context helper ranking and prefix into account (FELIX-4778)
+        return this.servletMapping.getBestMatch(requestURI);
+    }
+
+    public synchronized void removeAll()
+    {
+        for (Iterator<ServletHandler> it = servletMap.values().iterator(); it.hasNext(); )
+        {
+            ServletHandler handler = it.next();
+            it.remove();
+            handler.destroy();
+        }
+
+        for (Iterator<FilterHandler> it = filterMap.values().iterator(); it.hasNext(); )
+        {
+            FilterHandler handler = it.next();
+            it.remove();
+            handler.destroy();
+        }
+
+        this.servletMap.clear();
+        this.filterMap.clear();
+        this.servletPatternMap.clear();
+        this.errorsMapping.clear();
+
+        updateServletMapping();
+        updateFilterMapping();
+    }
+
+    public synchronized void removeFilter(Filter filter, final boolean destroy)
+    {
+        FilterHandler handler = this.filterMap.remove(filter);
+        if (handler != null)
+        {
+            updateFilterMapping();
+            if (destroy)
+            {
+                handler.destroy();
+            }
+        }
+    }
+
+    public synchronized Filter removeFilter(final FilterInfo filterInfo, final boolean destroy)
+    {
+        for(final FilterHandler handler : this.filterMap.values())
+        {
+            if ( handler.getFilterInfo().compareTo(filterInfo) == 0)
+            {
+                this.filterMap.remove(handler.getFilter());
+                updateFilterMapping();
+                if (destroy)
+                {
+                    handler.destroy();
+                }
+                return handler.getFilter();
+            }
+        }
+        return null;
+    }
+
+    public synchronized Servlet removeServlet(final ServletContextHelperInfo contextInfo, ServletInfo servletInfo, final boolean destroy)
+    {
+        for(final ServletHandler handler : this.servletMap.values())
+        {
+            if ( handler.getServletInfo().compareTo(servletInfo) == 0 )
+            {
+                this.servletMap.remove(handler.getServlet());
+                updateServletMapping();
+
+                // Can be null in case of error-handling servlets...
+                String[] patterns = handler.getServletInfo().getPatterns();
+                int length = patterns == null ? 0 : patterns.length;
+
+                for (int i = 0; i < length; i++)
+                {
+                    this.servletPatternMap.remove(contextInfo.getFullPath(patterns[i]));
+                }
+
+                this.errorsMapping.removeServlet(handler.getServlet());
+
+                if (destroy)
+                {
+                    handler.destroy();
+                }
+                return handler.getServlet();
+            }
+        }
+        return null;
+    }
+
+    public synchronized void removeServlet(Servlet servlet, final boolean destroy)
+    {
+        ServletHandler handler = this.servletMap.remove(servlet);
+        if (handler != null)
+        {
+            updateServletMapping();
+
+            // Can be null in case of error-handling servlets...
+            String[] patterns = handler.getServletInfo().getPatterns();
+            int length = patterns == null ? 0 : patterns.length;
+
+            for (int i = 0; i < length; i++)
+            {
+                this.servletPatternMap.remove(patterns[i]);
+            }
+
+            this.errorsMapping.removeServlet(servlet);
+
+            if (destroy)
+            {
+                handler.destroy();
+            }
+        }
+    }
+
+    private boolean referencesDispatcherType(FilterHandler handler, DispatcherType dispatcherType)
+    {
+        return Arrays.asList(handler.getFilterInfo().getDispatcher()).contains(dispatcherType);
+    }
+
+    private boolean referencesServletByName(FilterHandler 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;
+    }
+
+    private void updateFilterMapping()
+    {
+        this.filterMapping = new HandlerMapping<FilterHandler>(this.filterMap.values());
+    }
+
+    private void updateServletMapping()
+    {
+        this.servletMapping = new HandlerMapping<ServletHandler>(this.servletMap.values());
+    }
+
+    public String getPrefixPath()
+    {
+        return this.prefixPath;
+    }
+
+    public long getContextServiceid()
+    {
+        return this.serviceId;
+    }
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java?rev=1656459&r1=1656458&r2=1656459&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java Mon Feb  2 13:44:01 2015
@@ -79,7 +79,7 @@ public abstract class AbstractInfo<T> im
             {
                 return 0;
             }
-            // service id might be negative, we have to change the behaviour in that case
+            // service id might be negative, we have to change the behavior in that case
             if ( this.serviceId < 0 )
             {
                 if ( other.serviceId > 0 )

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java?rev=1656459&r1=1656458&r2=1656459&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java Mon Feb  2 13:44:01 2015
@@ -41,12 +41,14 @@ public final class HttpServiceFactory
         this.sharedContextAttributes = sharedContextAttributes;
     }
 
+    @Override
     public Object getService(Bundle bundle, ServiceRegistration reg)
     {
-        return new HttpServiceImpl(bundle, this.context, this.handlerRegistry, this.attributeListener,
+        return new HttpServiceImpl(bundle, this.context, this.handlerRegistry.getRegistry(null), this.attributeListener,
             this.sharedContextAttributes);
     }
 
+    @Override
     public void ungetService(Bundle bundle, ServiceRegistration reg, Object service)
     {
         ((HttpServiceImpl)service).unregisterAll();

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java?rev=1656459&r1=1656458&r2=1656459&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java Mon Feb  2 13:44:01 2015
@@ -32,7 +32,7 @@ import org.apache.felix.http.api.ExtHttp
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.context.ServletContextManager;
 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.PerContextHandlerRegistry;
 import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
@@ -44,12 +44,12 @@ import org.osgi.service.http.NamespaceEx
 public final class HttpServiceImpl implements ExtHttpService
 {
     private final Bundle bundle;
-    private final HandlerRegistry handlerRegistry;
+    private final PerContextHandlerRegistry handlerRegistry;
     private final HashSet<Servlet> localServlets;
     private final HashSet<Filter> localFilters;
     private final ServletContextManager contextManager;
 
-    public HttpServiceImpl(Bundle bundle, ServletContext context, HandlerRegistry handlerRegistry, ServletContextAttributeListener servletAttributeListener, boolean sharedContextAttributes)
+    public HttpServiceImpl(Bundle bundle, ServletContext context, PerContextHandlerRegistry handlerRegistry, ServletContextAttributeListener servletAttributeListener, boolean sharedContextAttributes)
     {
         this.bundle = bundle;
         this.handlerRegistry = handlerRegistry;

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java?rev=1656459&r1=1656458&r2=1656459&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java Mon Feb  2 13:44:01 2015
@@ -28,7 +28,7 @@ import java.nio.charset.CodingErrorActio
 
 /**
  * Some convenience methods for handling URI(-parts).
- * 
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class UriUtils
@@ -99,7 +99,7 @@ public class UriUtils
 
     /**
      * Concatenates two paths keeping their respective path-parts into consideration.
-     * 
+     *
      * @param path1 the first part of the path, can be <code>null</code>;
      * @param path2 the second part of the path, can be <code>null</code>.
      * @return the concatenated path, can be <code>null</code> in case both given arguments were <code>null</code>.
@@ -182,7 +182,7 @@ public class UriUtils
 
     /**
      * Decodes a given URL-encoded path assuming it is UTF-8 encoded.
-     *  
+     *
      * @param path the URL-encoded path, can be <code>null</code>.
      * @return the decoded path, can be <code>null</code> only if the given path was <code>null</code>.
      */
@@ -193,7 +193,7 @@ public class UriUtils
 
     /**
      * Decodes a given URL-encoded path using a given character encoding.
-     *  
+     *
      * @param path the URL-encoded path, can be <code>null</code>;
      * @param encoding the character encoding to use, cannot be <code>null</code>.
      * @return the decoded path, can be <code>null</code> only if the given path was <code>null</code>.
@@ -247,7 +247,7 @@ public class UriUtils
 
     /**
      * Removes all superfluous dot-segments using the algorithm described in RFC-3986 section 5.2.4.
-     *  
+     *
      * @param path the path to remove all dot-segments from, can be <code>null</code>.
      * @return the cleaned path, can be <code>null</code> only if the given path was <code>null</code>.
      */
@@ -420,6 +420,109 @@ public class UriUtils
         return value == null || "".equals(value.trim());
     }
 
+    public static String statusToString(final int statusCode)
+    {
+        switch (statusCode)
+        {
+            case 100:
+                return "Continue";
+            case 101:
+                return "Switching Protocols";
+            case 102:
+                return "Processing (WebDAV)";
+            case 200:
+                return "OK";
+            case 201:
+                return "Created";
+            case 202:
+                return "Accepted";
+            case 203:
+                return "Non-Authoritative Information";
+            case 204:
+                return "No Content";
+            case 205:
+                return "Reset Content";
+            case 206:
+                return "Partial Content";
+            case 207:
+                return "Multi-Status (WebDAV)";
+            case 300:
+                return "Multiple Choices";
+            case 301:
+                return "Moved Permanently";
+            case 302:
+                return "Found";
+            case 303:
+                return "See Other";
+            case 304:
+                return "Not Modified";
+            case 305:
+                return "Use Proxy";
+            case 307:
+                return "Temporary Redirect";
+            case 400:
+                return "Bad Request";
+            case 401:
+                return "Unauthorized";
+            case 402:
+                return "Payment Required";
+            case 403:
+                return "Forbidden";
+            case 404:
+                return "Not Found";
+            case 405:
+                return "Method Not Allowed";
+            case 406:
+                return "Not Acceptable";
+            case 407:
+                return "Proxy Authentication Required";
+            case 408:
+                return "Request Time-out";
+            case 409:
+                return "Conflict";
+            case 410:
+                return "Gone";
+            case 411:
+                return "Length Required";
+            case 412:
+                return "Precondition Failed";
+            case 413:
+                return "Request Entity Too Large";
+            case 414:
+                return "Request-URI Too Large";
+            case 415:
+                return "Unsupported Media Type";
+            case 416:
+                return "Requested range not satisfiable";
+            case 417:
+                return "Expectation Failed";
+            case 422:
+                return "Unprocessable Entity (WebDAV)";
+            case 423:
+                return "Locked (WebDAV)";
+            case 424:
+                return "Failed Dependency (WebDAV)";
+            case 500:
+                return "Internal Server Error";
+            case 501:
+                return "Not Implemented";
+            case 502:
+                return "Bad Gateway";
+            case 503:
+                return "Service Unavailable";
+            case 504:
+                return "Gateway Time-out";
+            case 505:
+                return "HTTP Version not supported";
+            case 507:
+                return "Insufficient Storage (WebDAV)";
+            case 510:
+                return "Not Extended";
+            default:
+                return String.valueOf(statusCode);
+        }
+    }
+
     /**
      * Creates a new {@link UriUtils} instance.
      */

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java?rev=1656459&r1=1656458&r2=1656459&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java Mon Feb  2 13:44:01 2015
@@ -103,7 +103,7 @@ public final class WhiteboardHttpService
                     servletInfo,
                     servlet);
             try {
-                this.handlerRegistry.addServlet(contextHandler.getContextInfo(), handler);
+                this.handlerRegistry.getRegistry(contextHandler.getContextInfo()).addServlet(contextHandler.getContextInfo(), handler);
             } catch (ServletException e) {
                 // TODO create failure DTO
             } catch (NamespaceException e) {
@@ -119,7 +119,7 @@ public final class WhiteboardHttpService
      */
     public void unregisterServlet(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletInfo servletInfo)
     {
-        final Servlet instance = this.handlerRegistry.removeServlet(contextHandler.getContextInfo(), servletInfo, true);
+        final Servlet instance = this.handlerRegistry.getRegistry(contextHandler.getContextInfo()).removeServlet(contextHandler.getContextInfo(), servletInfo, true);
         if ( instance != null )
         {
             this.bundleContext.getServiceObjects(servletInfo.getServiceReference()).ungetService(instance);
@@ -144,7 +144,7 @@ public final class WhiteboardHttpService
                     filter,
                     filterInfo);
             try {
-                this.handlerRegistry.addFilter(handler);
+                this.handlerRegistry.getRegistry(contextHandler.getContextInfo()).addFilter(handler);
             } catch (final ServletException e) {
                 // TODO create failure DTO
             }
@@ -158,7 +158,7 @@ public final class WhiteboardHttpService
      */
     public void unregisterFilter(@Nonnull final ContextHandler contextHandler, @Nonnull final FilterInfo filterInfo)
     {
-        final Filter instance = this.handlerRegistry.removeFilter(filterInfo, true);
+        final Filter instance = this.handlerRegistry.getRegistry(contextHandler.getContextInfo()).removeFilter(filterInfo, true);
         if ( instance != null )
         {
             this.bundleContext.getServiceObjects(filterInfo.getServiceReference()).ungetService(instance);
@@ -182,7 +182,7 @@ public final class WhiteboardHttpService
                 servletInfo,
                 servlet);
         try {
-            this.handlerRegistry.addServlet(contextHandler.getContextInfo(), handler);
+            this.handlerRegistry.getRegistry(contextHandler.getContextInfo()).addServlet(contextHandler.getContextInfo(), handler);
         } catch (ServletException e) {
             // TODO create failure DTO
         } catch (NamespaceException e) {