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

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1681788 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java b/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
index 6b74a77..d0aa361 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
@@ -18,6 +18,7 @@
 
 import java.util.Hashtable;
 
+import javax.annotation.Nonnull;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpSessionAttributeListener;
 import javax.servlet.http.HttpSessionEvent;
@@ -106,12 +107,12 @@
         this.whiteboardManager.setProperties(props);
     }
 
-    public void register(final ServletContext servletContext)
+    public void register(@Nonnull final ServletContext containerContext)
     {
         this.registry.init();
 
-        this.httpServiceFactory.start(servletContext);
-        this.whiteboardManager.start(servletContext);
+        this.httpServiceFactory.start(containerContext);
+        this.whiteboardManager.start(containerContext);
 
         this.dispatcher.setWhiteboardManager(this.whiteboardManager);
     }
@@ -120,15 +121,8 @@
     {
         this.dispatcher.setWhiteboardManager(null);
 
-        if ( this.whiteboardManager != null )
-        {
-            this.whiteboardManager.stop();
-        }
-
-        if ( this.httpServiceFactory != null )
-        {
-            this.httpServiceFactory.stop();
-        }
+        this.httpServiceFactory.stop();
+        this.whiteboardManager.stop();
 
         this.registry.shutdown();
         this.httpSessionListener = null;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ContextHandler.java
new file mode 100644
index 0000000..0dcfe5c
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ContextHandler.java
@@ -0,0 +1,57 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
+import org.apache.felix.http.base.internal.runtime.ListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
+
+public interface ContextHandler
+{
+
+    ServletContextHelperInfo getContextInfo();
+
+    /**
+     * Create a servlet handler
+     * @param servletInfo The servlet info
+     * @return {@code null} if the servlet context could not be created, a handler otherwise
+     */
+    ServletHandler getServletContextAndCreateServletHandler(@Nonnull final ServletInfo servletInfo);
+
+    /**
+     * Create a filter handler
+     * @param info The filter info
+     * @return {@code null} if the servlet context could not be created, a handler otherwise
+     */
+    FilterHandler getServletContextAndCreateFilterHandler(@Nonnull final FilterInfo info);
+
+    /**
+     * Create a listener handler
+     * @param info The listener info
+     * @return {@code null} if the servlet context could not be created, a handler otherwise
+     */
+    ListenerHandler getServletContextAndCreateListenerHandler(@Nonnull final ListenerInfo info);
+
+    void ungetServletContext(@Nonnull final WhiteboardServiceInfo<?> info);
+
+    PerContextHandlerRegistry getRegistry();
+}
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 cf9d624..037cf8e 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
@@ -20,14 +20,10 @@
 import javax.annotation.Nonnull;
 import javax.servlet.DispatcherType;
 
-import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.handler.ContextHandler;
 import org.apache.felix.http.base.internal.handler.FilterHandler;
-import org.apache.felix.http.base.internal.handler.HttpServiceServletHandler;
 import org.apache.felix.http.base.internal.handler.ListenerHandler;
 import org.apache.felix.http.base.internal.handler.ServletHandler;
-import org.apache.felix.http.base.internal.handler.WhiteboardFilterHandler;
-import org.apache.felix.http.base.internal.handler.WhiteboardListenerHandler;
-import org.apache.felix.http.base.internal.handler.WhiteboardServletHandler;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.ListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ResourceInfo;
@@ -35,8 +31,6 @@
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.apache.felix.http.base.internal.runtime.dto.FailedDTOHolder;
 import org.apache.felix.http.base.internal.service.HttpServiceFactory;
-import org.apache.felix.http.base.internal.service.ResourceServlet;
-import org.apache.felix.http.base.internal.whiteboard.ContextHandler;
 import org.osgi.service.http.runtime.dto.DTOConstants;
 import org.osgi.service.http.runtime.dto.ServletContextDTO;
 
@@ -163,15 +157,11 @@
     public int registerServlet(@Nonnull final ContextHandler contextHandler,
             @Nonnull final ServletInfo servletInfo)
     {
-        final ExtServletContext context = contextHandler.getServletContext(servletInfo.getServiceReference().getBundle());
-        if ( context == null )
+        final ServletHandler handler = contextHandler.getServletContextAndCreateServletHandler(servletInfo);
+        if ( handler == null )
         {
             return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
         }
-        final ServletHandler handler = new WhiteboardServletHandler(
-                contextHandler.getContextInfo().getServiceId(),
-                context,
-                servletInfo, contextHandler.getBundleContext());
         this.servletRegistry.addServlet(handler);
         this.errorPageRegistry.addServlet(handler);
         return -1;
@@ -186,7 +176,7 @@
     {
         this.servletRegistry.removeServlet(servletInfo, true);
         this.errorPageRegistry.removeServlet(servletInfo, true);
-        contextHandler.ungetServletContext(servletInfo.getServiceReference().getBundle());
+        contextHandler.ungetServletContext(servletInfo);
     }
 
     /**
@@ -197,15 +187,11 @@
     public int registerFilter(@Nonnull  final ContextHandler contextHandler,
             @Nonnull final FilterInfo filterInfo)
     {
-        final ExtServletContext context = contextHandler.getServletContext(filterInfo.getServiceReference().getBundle());
-        if ( context == null )
+        final FilterHandler handler = contextHandler.getServletContextAndCreateFilterHandler(filterInfo);
+        if ( handler == null )
         {
             return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
         }
-        final FilterHandler handler = new WhiteboardFilterHandler(
-                contextHandler.getContextInfo().getServiceId(),
-                context,
-                filterInfo, contextHandler.getBundleContext());
         this.filterRegistry.addFilter(handler);
         return -1;
     }
@@ -218,7 +204,7 @@
     public void unregisterFilter(@Nonnull final ContextHandler contextHandler, @Nonnull final FilterInfo filterInfo)
     {
         this.filterRegistry.removeFilter(filterInfo, true);
-        contextHandler.ungetServletContext(filterInfo.getServiceReference().getBundle());
+        contextHandler.ungetServletContext(filterInfo);
     }
 
     /**
@@ -231,16 +217,11 @@
     public int registerListeners(@Nonnull final ContextHandler contextHandler,
             @Nonnull final ListenerInfo info)
     {
-        final ExtServletContext context = contextHandler.getServletContext(info.getServiceReference().getBundle());
-        if ( context == null )
+        final ListenerHandler handler = contextHandler.getServletContextAndCreateListenerHandler(info);
+        if ( handler == null )
         {
             return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
         }
-        final ListenerHandler handler = new WhiteboardListenerHandler(
-                contextHandler.getContextInfo().getServiceId(),
-                context,
-                info,
-                contextHandler.getBundleContext());
         this.eventListenerRegistry.addListeners(handler);
         return -1;
     }
@@ -254,7 +235,7 @@
     public void unregisterListeners(@Nonnull final ContextHandler contextHandler, @Nonnull final ListenerInfo info)
     {
         this.eventListenerRegistry.removeListeners(info);
-        contextHandler.ungetServletContext(info.getServiceReference().getBundle());
+        contextHandler.ungetServletContext(info);
     }
 
     /**
@@ -267,17 +248,11 @@
     {
         final ServletInfo servletInfo = new ServletInfo(resourceInfo);
 
-        final ExtServletContext context = contextHandler.getServletContext(servletInfo.getServiceReference().getBundle());
-        if ( context == null )
+        final ServletHandler handler = contextHandler.getServletContextAndCreateServletHandler(servletInfo);
+        if ( handler == null )
         {
             return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
         }
-
-        final ServletHandler handler = new HttpServiceServletHandler(
-                contextHandler.getContextInfo().getServiceId(),
-                context,
-                servletInfo, new ResourceServlet(resourceInfo.getPrefix()));
-
         this.servletRegistry.addServlet(handler);
         return -1;
     }
@@ -289,19 +264,31 @@
      */
     public void unregisterResource(@Nonnull final ContextHandler contextHandler, @Nonnull final ResourceInfo resourceInfo)
     {
-        final ServletInfo servletInfo = new ServletInfo(resourceInfo);
-        this.servletRegistry.removeServlet(servletInfo, true);
-        contextHandler.ungetServletContext(servletInfo.getServiceReference().getBundle());
+        this.servletRegistry.removeServlet(new ServletInfo(resourceInfo), true);
+        contextHandler.ungetServletContext(resourceInfo);
     }
 
-    public FilterHandler[] getFilterHandlers(@CheckForNull final ServletHandler servletHandler,
+    /**
+     * Get filter handlers for the request uri
+     * @param servletHandler The servlet handler (might be null)
+     * @param dispatcherType The dispatcher type
+     * @param requestURI The request uri
+     * @return The array of filter handlers, the array might be empty.
+     */
+    public @Nonnull FilterHandler[] getFilterHandlers(@CheckForNull final ServletHandler servletHandler,
             @Nonnull final DispatcherType dispatcherType,
             @Nonnull final String requestURI)
     {
         return this.filterRegistry.getFilterHandlers(servletHandler, dispatcherType, requestURI);
     }
 
-    public ServletHandler getErrorHandler(int code, Throwable exception)
+    /**
+     * Get the servlet handling the error.
+     * @param code The error code
+     * @param exception The optional exception
+     * @return The servlet handler or {@code null}.
+     */
+    public @CheckForNull ServletHandler getErrorHandler(final int code, @CheckForNull final Throwable exception)
     {
         return this.errorPageRegistry.get(exception, code);
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
index d78fedb..682ad36 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
@@ -114,10 +114,9 @@
      */
     public ServletInfo(final String name,
             final String pattern,
-            final int serviceRanking,
             final Map<String, String> initParams)
     {
-        super(serviceRanking);
+        super(Integer.MAX_VALUE);
         this.name = name;
         this.patterns = new String[] {pattern};
         this.initParams = Collections.unmodifiableMap(initParams);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
index 5551159..47fbd94 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
@@ -40,7 +40,7 @@
 public final class HttpServiceFactory
     implements ServiceFactory<HttpService>
 {
-    public static final String HTTP_SERVICE_CONTEXT_NAME = "Http Service context";
+    public static final String HTTP_SERVICE_CONTEXT_NAME = "org.osgi.service.http";
 
     public static final long HTTP_SERVICE_CONTEXT_SERVICE_ID = -1;
 
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 266b65c..5870c09 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
@@ -202,7 +202,7 @@
             this.localServlets.add(servlet);
         }
 
-        final ServletInfo servletInfo = new ServletInfo(String.format("%s_%d", servlet.getClass(), this.hashCode()), alias, 0, paramMap);
+        final ServletInfo servletInfo = new ServletInfo(String.format("%s_%d", servlet.getClass(), this.hashCode()), alias, paramMap);
         final ExtServletContext httpContext = getServletContext(context);
 
         boolean success = false;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
deleted file mode 100644
index 604bc2c..0000000
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.felix.http.base.internal.whiteboard;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import javax.servlet.ServletContext;
-
-import org.apache.felix.http.base.internal.context.ExtServletContext;
-import org.apache.felix.http.base.internal.registry.HandlerRegistry;
-import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
-import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceObjects;
-import org.osgi.service.http.context.ServletContextHelper;
-
-public final class ContextHandler implements Comparable<ContextHandler>
-{
-    /** The info object for the context. */
-    private final ServletContextHelperInfo info;
-
-    private final ServletContext webContext;
-
-    /** The shared part of the servlet context. */
-    private volatile ServletContext sharedContext;
-
-    /** The http bundle. */
-    private final Bundle bundle;
-
-    /** A map of all created servlet contexts. Each bundle gets it's own instance. */
-    private final Map<Long, ContextHolder> perBundleContextMap = new HashMap<Long, ContextHolder>();
-
-    private volatile PerContextHandlerRegistry registry;
-
-    public ContextHandler(final ServletContextHelperInfo info,
-            final ServletContext webContext,
-            final Bundle bundle)
-    {
-        this.webContext = webContext;
-        this.info = info;
-        this.bundle = bundle;
-    }
-
-    public BundleContext getBundleContext()
-    {
-        return this.bundle.getBundleContext();
-    }
-
-    public ServletContextHelperInfo getContextInfo()
-    {
-        return this.info;
-    }
-
-    @Override
-    public int compareTo(final ContextHandler o)
-    {
-        return this.info.compareTo(o.info);
-    }
-
-    /**
-     * Activate this context.
-     * @return {@code true} if it succeeded.
-     */
-    public boolean activate(final HandlerRegistry registry)
-    {
-        this.registry = new PerContextHandlerRegistry(this.info);
-        this.sharedContext = new SharedServletContextImpl(webContext,
-                info.getName(),
-                info.getPath(),
-                info.getInitParameters(),
-                this.registry.getEventListenerRegistry());
-        final boolean activate = getServletContext(bundle) != null;
-        if ( !activate )
-        {
-            this.registry = null;
-            this.sharedContext = null;
-        }
-        else
-        {
-            registry.add(this.registry);
-        }
-        return activate;
-    }
-
-    /**
-     * Deactivate this context.
-     */
-    public void deactivate(final HandlerRegistry registry)
-    {
-        registry.remove(this.info);
-        this.registry = null;
-        this.sharedContext = null;
-        this.ungetServletContext(bundle);
-        // TODO we should clear all state
-    }
-
-    public ServletContext getSharedContext()
-    {
-        return sharedContext;
-    }
-
-    public ExtServletContext getServletContext(@CheckForNull final Bundle bundle)
-    {
-        if ( bundle == null )
-        {
-            return null;
-        }
-        final Long key = bundle.getBundleId();
-        synchronized ( this.perBundleContextMap )
-        {
-            ContextHolder holder = this.perBundleContextMap.get(key);
-            if ( holder == null )
-            {
-                final BundleContext ctx = bundle.getBundleContext();
-                final ServiceObjects<ServletContextHelper> so = (ctx == null ? null : ctx.getServiceObjects(this.info.getServiceReference()));
-                if ( so != null )
-                {
-                    final ServletContextHelper service = so.getService();
-                    if ( service != null )
-                    {
-                        holder = new ContextHolder();
-                        holder.servletContextHelper = service;
-                        holder.servletContext = new PerBundleServletContextImpl(bundle,
-                                this.sharedContext,
-                                service,
-                                this.registry.getEventListenerRegistry());
-                        this.perBundleContextMap.put(key, holder);
-                    }
-                }
-            }
-            if ( holder != null )
-            {
-                holder.counter++;
-
-                return holder.servletContext;
-            }
-        }
-        return null;
-    }
-
-    public void ungetServletContext(@Nonnull final Bundle bundle)
-    {
-        final Long key = bundle.getBundleId();
-        synchronized ( this.perBundleContextMap )
-        {
-            ContextHolder holder = this.perBundleContextMap.get(key);
-            if ( holder != null )
-            {
-                holder.counter--;
-                if ( holder.counter == 0 )
-                {
-                    this.perBundleContextMap.remove(key);
-                    if ( holder.servletContextHelper != null )
-                    {
-                        final BundleContext ctx = bundle.getBundleContext();
-                        final ServiceObjects<ServletContextHelper> so = (ctx == null ? null : ctx.getServiceObjects(this.info.getServiceReference()));
-                        if ( so != null )
-                        {
-                            so.ungetService(holder.servletContextHelper);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private static final class ContextHolder
-    {
-        public long counter;
-        public ExtServletContext servletContext;
-        public ServletContextHelper servletContextHelper;
-    }
-
-    public PerContextHandlerRegistry getRegistry()
-    {
-        return this.registry;
-    }
-}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
new file mode 100644
index 0000000..d98fecf
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
@@ -0,0 +1,292 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.whiteboard;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.servlet.ServletContext;
+
+import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.handler.ContextHandler;
+import org.apache.felix.http.base.internal.handler.FilterHandler;
+import org.apache.felix.http.base.internal.handler.HttpServiceServletHandler;
+import org.apache.felix.http.base.internal.handler.ListenerHandler;
+import org.apache.felix.http.base.internal.handler.ServletHandler;
+import org.apache.felix.http.base.internal.handler.WhiteboardFilterHandler;
+import org.apache.felix.http.base.internal.handler.WhiteboardListenerHandler;
+import org.apache.felix.http.base.internal.handler.WhiteboardServletHandler;
+import org.apache.felix.http.base.internal.registry.HandlerRegistry;
+import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
+import org.apache.felix.http.base.internal.runtime.ListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
+import org.apache.felix.http.base.internal.service.ResourceServlet;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.service.http.context.ServletContextHelper;
+
+public final class WhiteboardContextHandler implements ContextHandler, Comparable<ContextHandler>
+{
+    /** The info object for the context. */
+    private final ServletContextHelperInfo info;
+
+    private final ServletContext webContext;
+
+    /** The http bundle. */
+    private final Bundle httpBundle;
+
+    /** A map of all created servlet contexts. Each bundle gets it's own instance. */
+    private final Map<Long, ContextHolder> perBundleContextMap = new HashMap<Long, ContextHolder>();
+
+    private volatile PerContextHandlerRegistry registry;
+
+    /** The shared part of the servlet context. */
+    private volatile ServletContext sharedContext;
+
+    public WhiteboardContextHandler(final ServletContextHelperInfo info,
+            final ServletContext webContext,
+            final Bundle httpBundle)
+    {
+        this.webContext = webContext;
+        this.info = info;
+        this.httpBundle = httpBundle;
+    }
+
+    public BundleContext getBundleContext()
+    {
+        return this.httpBundle.getBundleContext();
+    }
+
+    @Override
+    public ServletContextHelperInfo getContextInfo()
+    {
+        return this.info;
+    }
+
+    @Override
+    public int compareTo(final ContextHandler o)
+    {
+        return this.info.compareTo(o.getContextInfo());
+    }
+
+    /**
+     * Activate this context.
+     * @return {@code true} if it succeeded.
+     */
+    public boolean activate(final HandlerRegistry registry)
+    {
+        this.registry = new PerContextHandlerRegistry(this.info);
+        this.sharedContext = new SharedServletContextImpl(webContext,
+                info.getName(),
+                info.getPath(),
+                info.getInitParameters(),
+                this.registry.getEventListenerRegistry());
+        final boolean activate = getServletContext(httpBundle) != null;
+        if ( !activate )
+        {
+            this.registry = null;
+            this.sharedContext = null;
+        }
+        else
+        {
+            registry.add(this.registry);
+        }
+        return activate;
+    }
+
+    /**
+     * Deactivate this context.
+     */
+    public void deactivate(final HandlerRegistry registry)
+    {
+        registry.remove(this.info);
+        this.registry = null;
+        this.sharedContext = null;
+        this.ungetServletContext(httpBundle);
+        this.perBundleContextMap.clear();
+    }
+
+    public ServletContext getSharedContext()
+    {
+        return sharedContext;
+    }
+
+    public ExtServletContext getServletContext(@CheckForNull final Bundle bundle)
+    {
+        if ( bundle == null )
+        {
+            return null;
+        }
+        final Long key = bundle.getBundleId();
+        synchronized ( this.perBundleContextMap )
+        {
+            ContextHolder holder = this.perBundleContextMap.get(key);
+            if ( holder == null )
+            {
+                final BundleContext ctx = bundle.getBundleContext();
+                final ServiceObjects<ServletContextHelper> so = (ctx == null ? null : ctx.getServiceObjects(this.info.getServiceReference()));
+                if ( so != null )
+                {
+                    final ServletContextHelper service = so.getService();
+                    if ( service != null )
+                    {
+                        holder = new ContextHolder();
+                        holder.servletContextHelper = service;
+                        holder.servletContext = new PerBundleServletContextImpl(bundle,
+                                this.sharedContext,
+                                service,
+                                this.registry.getEventListenerRegistry());
+                        this.perBundleContextMap.put(key, holder);
+                    }
+                }
+            }
+            if ( holder != null )
+            {
+                holder.counter++;
+
+                return holder.servletContext;
+            }
+        }
+        return null;
+    }
+
+    public void ungetServletContext(@Nonnull final Bundle bundle)
+    {
+        final Long key = bundle.getBundleId();
+        synchronized ( this.perBundleContextMap )
+        {
+            ContextHolder holder = this.perBundleContextMap.get(key);
+            if ( holder != null )
+            {
+                holder.counter--;
+                if ( holder.counter == 0 )
+                {
+                    this.perBundleContextMap.remove(key);
+                    if ( holder.servletContextHelper != null )
+                    {
+                        final BundleContext ctx = bundle.getBundleContext();
+                        final ServiceObjects<ServletContextHelper> so = (ctx == null ? null : ctx.getServiceObjects(this.info.getServiceReference()));
+                        if ( so != null )
+                        {
+                            so.ungetService(holder.servletContextHelper);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a servlet handler
+     * @param servletInfo The servlet info
+     * @return {@code null} if the servlet context could not be created, a handler otherwise
+     */
+    @Override
+    public ServletHandler getServletContextAndCreateServletHandler(@Nonnull final ServletInfo servletInfo)
+    {
+        final ExtServletContext servletContext = this.getServletContext(servletInfo.getServiceReference().getBundle());
+        if ( servletContext == null )
+        {
+            return null;
+        }
+        final ServletHandler handler;
+        if ( servletInfo.isResource() )
+        {
+            handler = new HttpServiceServletHandler(
+                    this.info.getServiceId(),
+                    servletContext,
+                    servletInfo,
+                    new ResourceServlet(servletInfo.getPrefix()));
+        }
+        else
+        {
+            handler = new WhiteboardServletHandler(
+                this.info.getServiceId(),
+                servletContext,
+                servletInfo,
+                this.httpBundle.getBundleContext());
+        }
+        return handler;
+    }
+
+    /**
+     * Create a filter handler
+     * @param info The filter info
+     * @return {@code null} if the servlet context could not be created, a handler otherwise
+     */
+    @Override
+    public FilterHandler getServletContextAndCreateFilterHandler(@Nonnull final FilterInfo info)
+    {
+        final ExtServletContext servletContext = this.getServletContext(info.getServiceReference().getBundle());
+        if ( servletContext == null )
+        {
+            return null;
+        }
+        final FilterHandler handler = new WhiteboardFilterHandler(
+                this.info.getServiceId(),
+                servletContext,
+                info,
+                this.httpBundle.getBundleContext());
+        return handler;
+    }
+
+    /**
+     * Create a listener handler
+     * @param info The listener info
+     * @return {@code null} if the servlet context could not be created, a handler otherwise
+     */
+    @Override
+    public ListenerHandler getServletContextAndCreateListenerHandler(@Nonnull final ListenerInfo info)
+    {
+        final ExtServletContext servletContext = this.getServletContext(info.getServiceReference().getBundle());
+        if ( servletContext == null )
+        {
+            return null;
+        }
+        final ListenerHandler handler = new WhiteboardListenerHandler(
+                this.info.getServiceId(),
+                servletContext,
+                info,
+                this.httpBundle.getBundleContext());
+        return handler;
+    }
+
+    @Override
+    public void ungetServletContext(@Nonnull final WhiteboardServiceInfo<?> info)
+    {
+        this.ungetServletContext(info.getServiceReference().getBundle());
+    }
+
+    private static final class ContextHolder
+    {
+        public long counter;
+        public ExtServletContext servletContext;
+        public ServletContextHelper servletContextHelper;
+    }
+
+    @Override
+    public PerContextHandlerRegistry getRegistry()
+    {
+        return this.registry;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
index 844fb5d..ecabd93 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
@@ -41,6 +41,7 @@
 
 import org.apache.felix.http.base.internal.console.HttpServicePlugin;
 import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.handler.ContextHandler;
 import org.apache.felix.http.base.internal.handler.HttpSessionWrapper;
 import org.apache.felix.http.base.internal.handler.ListenerHandler;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
@@ -81,17 +82,17 @@
 
 public final class WhiteboardManager
 {
-    private final BundleContext bundleContext;
+    private final BundleContext httpBundleContext;
 
     private final HttpServiceFactory httpServiceFactory;
 
     private final HttpServiceRuntimeImpl serviceRuntime;
 
     /** A map containing all servlet context registrations. Mapped by context name */
-    private final Map<String, List<ContextHandler>> contextMap = new HashMap<String, List<ContextHandler>>();
+    private final Map<String, List<WhiteboardContextHandler>> contextMap = new HashMap<String, List<WhiteboardContextHandler>>();
 
     /** A map with all servlet/filter registrations, mapped by abstract info. */
-    private final Map<WhiteboardServiceInfo<?>, List<ContextHandler>> servicesMap = new HashMap<WhiteboardServiceInfo<?>, List<ContextHandler>>();
+    private final Map<WhiteboardServiceInfo<?>, List<WhiteboardContextHandler>> servicesMap = new HashMap<WhiteboardServiceInfo<?>, List<WhiteboardContextHandler>>();
 
     private final HandlerRegistry registry;
 
@@ -117,30 +118,30 @@
             final HttpServiceFactory httpServiceFactory,
             final HandlerRegistry registry)
     {
-        this.bundleContext = bundleContext;
+        this.httpBundleContext = bundleContext;
         this.httpServiceFactory = httpServiceFactory;
         this.registry = registry;
         this.serviceRuntime = new HttpServiceRuntimeImpl(registry, this);
         this.plugin = new HttpServicePlugin(bundleContext, this.serviceRuntime);
     }
 
-    public void start(final ServletContext context)
+    public void start(final ServletContext containerContext)
     {
         this.serviceRuntime.setAttribute(HttpServiceRuntimeConstants.HTTP_SERVICE_ID,
                 Collections.singletonList(this.httpServiceFactory.getHttpServiceServiceId()));
-        this.runtimeServiceReg = this.bundleContext.registerService(HttpServiceRuntime.class,
+        this.runtimeServiceReg = this.httpBundleContext.registerService(HttpServiceRuntime.class,
                 serviceRuntime,
                 this.serviceRuntime.getAttributes());
         this.serviceRuntime.setServiceReference(this.runtimeServiceReg.getReference());
 
-        this.webContext = context;
+        this.webContext = containerContext;
 
         final Dictionary<String, Object> props = new Hashtable<String, Object>();
         props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, HttpWhiteboardConstants.HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME);
         props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH, "/");
         props.put(Constants.SERVICE_RANKING, Integer.MIN_VALUE);
 
-        this.defaultContextRegistration = bundleContext.registerService(
+        this.defaultContextRegistration = httpBundleContext.registerService(
                 ServletContextHelper.class,
                 new ServiceFactory<ServletContextHelper>()
                 {
@@ -170,11 +171,11 @@
                         // nothing to do
                     }
                 }, props);
-        addTracker(new FilterTracker(this.bundleContext, this));
-        addTracker(new ListenersTracker(this.bundleContext, this));
-        addTracker(new ResourceTracker(this.bundleContext, this));
-        addTracker(new ServletContextHelperTracker(this.bundleContext, this));
-        addTracker(new ServletTracker(this.bundleContext, this));
+        addTracker(new FilterTracker(this.httpBundleContext, this));
+        addTracker(new ListenersTracker(this.httpBundleContext, this));
+        addTracker(new ResourceTracker(this.httpBundleContext, this));
+        addTracker(new ServletContextHelperTracker(this.httpBundleContext, this));
+        addTracker(new ServletTracker(this.httpBundleContext, this));
 
         this.plugin.register();
     }
@@ -230,12 +231,12 @@
     {
         for(final Long contextId : contextIds)
         {
-            final ContextHandler handler = this.getContextHandler(contextId);
+            final WhiteboardContextHandler handler = this.getContextHandler(contextId);
             if ( handler != null )
             {
-                final ExtServletContext context = handler.getServletContext(this.bundleContext.getBundle());
+                final ExtServletContext context = handler.getServletContext(this.httpBundleContext.getBundle());
                 new HttpSessionWrapper(contextId, session, context, true).invalidate();
-                handler.ungetServletContext(this.bundleContext.getBundle());
+                handler.ungetServletContext(this.httpBundleContext.getBundle());
             }
         }
     }
@@ -250,7 +251,7 @@
     {
         for(final Long contextId : contextIds)
         {
-            final ContextHandler handler = this.getContextHandler(contextId);
+            final WhiteboardContextHandler handler = this.getContextHandler(contextId);
             if ( handler != null )
             {
                 handler.getRegistry().getEventListenerRegistry().sessionIdChanged(event, oldSessionId);
@@ -264,7 +265,7 @@
      * @param handler The context handler
      * @return {@code true} if activation succeeded.
      */
-    private boolean activate(final ContextHandler handler)
+    private boolean activate(final WhiteboardContextHandler handler)
     {
         if ( !handler.activate(this.registry) )
         {
@@ -272,7 +273,7 @@
         }
 
         final List<WhiteboardServiceInfo<?>> services = new ArrayList<WhiteboardServiceInfo<?>>();
-        for(final Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>> entry : this.servicesMap.entrySet())
+        for(final Map.Entry<WhiteboardServiceInfo<?>, List<WhiteboardContextHandler>> entry : this.servicesMap.entrySet())
         {
             if ( entry.getKey().getContextSelectionFilter().match(handler.getContextInfo().getServiceReference()) )
             {
@@ -310,14 +311,14 @@
      *
      * @param handler A context handler
      */
-    private void deactivate(final ContextHandler handler)
+    private void deactivate(final WhiteboardContextHandler handler)
     {
         // services except context listeners first
         final List<WhiteboardServiceInfo<?>> listeners = new ArrayList<WhiteboardServiceInfo<?>>();
-        final Iterator<Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>>> i = this.servicesMap.entrySet().iterator();
+        final Iterator<Map.Entry<WhiteboardServiceInfo<?>, List<WhiteboardContextHandler>>> i = this.servicesMap.entrySet().iterator();
         while ( i.hasNext() )
         {
-            final Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>> entry = i.next();
+            final Map.Entry<WhiteboardServiceInfo<?>, List<WhiteboardContextHandler>> entry = i.next();
             if ( entry.getValue().remove(handler) )
             {
                 if ( !this.failureStateHandler.remove(entry.getKey(), handler.getContextInfo().getServiceId()) )
@@ -364,15 +365,15 @@
             {
                 synchronized ( this.contextMap )
                 {
-                    final ContextHandler handler = new ContextHandler(info,
+                    final WhiteboardContextHandler handler = new WhiteboardContextHandler(info,
                             this.webContext,
-                            this.bundleContext.getBundle());
+                            this.httpBundleContext.getBundle());
 
                     // check for activate/deactivate
-                    List<ContextHandler> handlerList = this.contextMap.get(info.getName());
+                    List<WhiteboardContextHandler> handlerList = this.contextMap.get(info.getName());
                     if ( handlerList == null )
                     {
-                        handlerList = new ArrayList<ContextHandler>();
+                        handlerList = new ArrayList<WhiteboardContextHandler>();
                     }
                     final boolean activate = handlerList.isEmpty() || handlerList.get(0).compareTo(handler) > 0;
                     if ( activate )
@@ -387,7 +388,7 @@
                             // check for deactivate
                             if ( handlerList.size() > 1 )
                             {
-                                ContextHandler oldHead = handlerList.get(1);
+                                final WhiteboardContextHandler oldHead = handlerList.get(1);
                                 this.deactivate(oldHead);
 
                                 final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
@@ -436,15 +437,15 @@
         {
             synchronized ( this.contextMap )
             {
-                final List<ContextHandler> handlerList = this.contextMap.get(info.getName());
+                final List<WhiteboardContextHandler> handlerList = this.contextMap.get(info.getName());
                 if ( handlerList != null )
                 {
-                    final Iterator<ContextHandler> i = handlerList.iterator();
+                    final Iterator<WhiteboardContextHandler> i = handlerList.iterator();
                     boolean first = true;
                     boolean activateNext = false;
                     while ( i.hasNext() )
                     {
-                        final ContextHandler handler = i.next();
+                        final WhiteboardContextHandler handler = i.next();
                         if ( handler.getContextInfo().equals(info) )
                         {
                             i.remove();
@@ -468,7 +469,7 @@
                         boolean done = false;
                         while ( !handlerList.isEmpty() && !done)
                         {
-                            final ContextHandler newHead = handlerList.get(0);
+                            final WhiteboardContextHandler newHead = handlerList.get(0);
                             this.failureStateHandler.removeAll(newHead.getContextInfo());
 
                             if ( this.activate(newHead) )
@@ -494,12 +495,12 @@
     /**
      * Find the list of matching contexts for the whiteboard service
      */
-    private List<ContextHandler> getMatchingContexts(final WhiteboardServiceInfo<?> info)
+    private List<WhiteboardContextHandler> getMatchingContexts(final WhiteboardServiceInfo<?> info)
     {
-        final List<ContextHandler> result = new ArrayList<ContextHandler>();
-        for(final List<ContextHandler> handlerList : this.contextMap.values())
+        final List<WhiteboardContextHandler> result = new ArrayList<WhiteboardContextHandler>();
+        for(final List<WhiteboardContextHandler> handlerList : this.contextMap.values())
         {
-            final ContextHandler h = handlerList.get(0);
+            final WhiteboardContextHandler h = handlerList.get(0);
             // check whether the servlet context helper is visible to the whiteboard bundle
             // see chapter 140.2
             boolean visible = h.getContextInfo().getServiceId() < 0; // internal ones are always visible
@@ -542,7 +543,7 @@
             {
                 synchronized ( this.contextMap )
                 {
-                    final List<ContextHandler> handlerList = this.getMatchingContexts(info);
+                    final List<WhiteboardContextHandler> handlerList = this.getMatchingContexts(info);
                     this.servicesMap.put(info, handlerList);
                     if (handlerList.isEmpty())
                     {
@@ -593,10 +594,10 @@
         {
             if ( !failureStateHandler.remove(info) )
             {
-                final List<ContextHandler> handlerList = this.servicesMap.remove(info);
+                final List<WhiteboardContextHandler> handlerList = this.servicesMap.remove(info);
                 if ( handlerList != null )
                 {
-                    for(final ContextHandler h : handlerList)
+                    for(final WhiteboardContextHandler h : handlerList)
                     {
                         if ( !failureStateHandler.remove(info, h.getContextInfo().getServiceId()) )
                         {
@@ -672,7 +673,7 @@
      * @param handler Context handler
      * @param info Whiteboard service info
      */
-    private void unregisterWhiteboardService(final ContextHandler handler, final WhiteboardServiceInfo<?> info)
+    private void unregisterWhiteboardService(final WhiteboardContextHandler handler, final WhiteboardServiceInfo<?> info)
     {
         try
         {
@@ -712,7 +713,7 @@
         {
             try
             {
-                final Filter f = this.bundleContext.createFilter(target);
+                final Filter f = this.httpBundleContext.createFilter(target);
                 return f.match(this.runtimeServiceReg.getReference());
             }
             catch ( final InvalidSyntaxException ise)
@@ -725,13 +726,13 @@
         return true;
     }
 
-    private ContextHandler getContextHandler(final Long contextId)
+    private WhiteboardContextHandler getContextHandler(final Long contextId)
     {
         synchronized ( this.contextMap )
         {
-            for(final List<ContextHandler> handlerList : this.contextMap.values())
+            for(final List<WhiteboardContextHandler> handlerList : this.contextMap.values())
             {
-                final ContextHandler h = handlerList.get(0);
+                final WhiteboardContextHandler h = handlerList.get(0);
                 if ( h.getContextInfo().getServiceId() == contextId )
                 {
                     return h;
@@ -757,10 +758,10 @@
         }
 
         // get sort list of context handlers
-        final List<ContextHandler> contextHandlerList = new ArrayList<ContextHandler>();
+        final List<WhiteboardContextHandler> contextHandlerList = new ArrayList<WhiteboardContextHandler>();
         synchronized ( this.contextMap )
         {
-            for (final List<ContextHandler> list : this.contextMap.values())
+            for (final List<WhiteboardContextHandler> list : this.contextMap.values())
             {
                 if ( !list.isEmpty() )
                 {
@@ -771,7 +772,7 @@
         }
         Collections.sort(contextHandlerList);
 
-        for (final ContextHandler handler : contextHandlerList)
+        for (final WhiteboardContextHandler handler : contextHandlerList)
         {
             final ServletContextDTO scDTO = ServletContextDTOBuilder.build(handler.getContextInfo(), handler.getSharedContext(), -1);
 
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandlerTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandlerTest.java
index afe7b87..9400377 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandlerTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/HttpServiceServletHandlerTest.java
@@ -220,7 +220,7 @@
         {
             map = Collections.emptyMap();
         }
-        final ServletInfo info = new ServletInfo(null, alias, 0, map);
+        final ServletInfo info = new ServletInfo(null, alias, map);
         return new HttpServiceServletHandler(this.context, info, this.servlet);
     }
 }
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java
index ba24f25..3dbe4c1 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/registry/HandlerRegistryTest.java
@@ -67,7 +67,7 @@
         dto.servletDTOs = new ServletDTO[0];
 
         Servlet servlet = Mockito.mock(Servlet.class);
-        final ServletInfo info = new ServletInfo("foo", "/foo", 0, Collections.<String, String> emptyMap());
+        final ServletInfo info = new ServletInfo("foo", "/foo", Collections.<String, String> emptyMap());
         ServletHandler handler = new HttpServiceServletHandler(null, info, servlet);
 
         assertTrue(registry.getRuntimeInfo(dto, holder));
@@ -79,13 +79,13 @@
         assertEquals(1, dto.servletDTOs.length);
         assertEquals(info.getServiceId(), dto.servletDTOs[0].serviceId);
 
-        final ServletInfo info2 = new ServletInfo("bar", "/bar", 0, Collections.<String, String> emptyMap());
+        final ServletInfo info2 = new ServletInfo("bar", "/bar", Collections.<String, String> emptyMap());
         ServletHandler handler2 = new HttpServiceServletHandler(null, info2, Mockito.mock(Servlet.class));
         registry.getRegistry(handler.getContextServiceId()).registerServlet(handler2);
         assertTrue(registry.getRuntimeInfo(dto, holder));
         assertEquals(2, dto.servletDTOs.length);
 
-        final ServletInfo info3 = new ServletInfo("zar", "/foo", 0, Collections.<String, String> emptyMap());
+        final ServletInfo info3 = new ServletInfo("zar", "/foo", Collections.<String, String> emptyMap());
         ServletHandler handler3 = new HttpServiceServletHandler(null,info3, Mockito.mock(Servlet.class));
         registry.getRegistry(handler.getContextServiceId()).registerServlet(handler3);
         assertTrue(registry.getRuntimeInfo(dto, holder));
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java
index 09eaa06..3597f6d 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java
@@ -48,7 +48,7 @@
 
     @Test public void testAddRemoveNoContext()
     {
-        final ServletInfo info = new ServletInfo("test", "/test", 3, Collections.<String, String> emptyMap());
+        final ServletInfo info = new ServletInfo("test", "/test", Collections.<String, String> emptyMap());
 
         final FailureStateHandler handler = new FailureStateHandler();
         handler.add(info, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
@@ -69,8 +69,8 @@
 
     @Test public void testAddRemoveContext()
     {
-        final ServletInfo info1 = new ServletInfo("test", "/test", 3, Collections.<String, String> emptyMap());
-        final ServletInfo info2 = new ServletInfo("test", "/test", 4, Collections.<String, String> emptyMap());
+        final ServletInfo info1 = new ServletInfo("test", "/test", Collections.<String, String> emptyMap());
+        final ServletInfo info2 = new ServletInfo("test", "/test", Collections.<String, String> emptyMap());
 
         final FailureStateHandler handler = new FailureStateHandler();
         handler.add(info1, 1L, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);