FELIX-4546 - Implement HttpServiceRuntime service

- applied the patch from ThomasB.



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1669088 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ErrorsMapping.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ErrorsMapping.java
index 39bfc7a..e8b545b 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ErrorsMapping.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ErrorsMapping.java
@@ -16,7 +16,7 @@
  */
 package org.apache.felix.http.base.internal.handler;
 
-import static org.apache.felix.http.base.internal.util.CollectionUtils.union;
+import static org.apache.felix.http.base.internal.util.CollectionUtils.sortedUnion;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -30,7 +30,7 @@
 import javax.servlet.Servlet;
 import javax.servlet.ServletException;
 
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.ErrorPageRuntime;
 
 public final class ErrorsMapping
 {
@@ -126,14 +126,14 @@
     @SuppressWarnings("unchecked")
     public Collection<ServletHandler> getMappedHandlers()
     {
-        return union(errorCodesMap.values(), exceptionsMap.values());
+        return sortedUnion(errorCodesMap.values(), exceptionsMap.values());
     }
 
-    public HandlerRuntime.ErrorPage getErrorPage(ServletHandler servletHandler)
+    public ErrorPageRuntime getErrorPage(ServletHandler servletHandler)
     {
         Collection<Integer> errorCodes = getCopy(servletHandler, invertedErrorCodesMap);
         Collection<String> exceptions = getCopy(servletHandler, invertedExceptionsMap);
-        return new HandlerRuntime.ErrorPage(servletHandler, errorCodes, exceptions);
+        return new ErrorPageRuntime(servletHandler, errorCodes, exceptions);
     }
 
     private static <T> List<T> getCopy(ServletHandler key, Map<Servlet, Collection<T>> map)
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
index c7b0e6c..951c2ec 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
@@ -33,9 +33,10 @@
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 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.dto.FilterRuntime;
 import org.apache.felix.http.base.internal.util.PatternUtil;
 
-public final class FilterHandler extends AbstractHandler<FilterHandler>
+public final class FilterHandler extends AbstractHandler<FilterHandler> implements FilterRuntime
 {
     private final Filter filter;
     private final FilterInfo filterInfo;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
index 58002db..e872de1 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
@@ -24,8 +24,9 @@
 import javax.annotation.Nonnull;
 import javax.servlet.DispatcherType;
 
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+import org.apache.felix.http.base.internal.runtime.dto.ContextRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.FailureRuntime;
 import org.osgi.framework.BundleContext;
 
 /**
@@ -225,12 +226,12 @@
         return null;
     }
 
-    public synchronized List<HandlerRuntime> getRuntime()
+    public synchronized List<ContextRuntime> getRuntime(FailureRuntime.Builder failureRuntimeBuilder)
     {
-        List<HandlerRuntime> handlerRuntimes = new ArrayList<HandlerRuntime>();
+        List<ContextRuntime> handlerRuntimes = new ArrayList<ContextRuntime>();
         for (PerContextHandlerRegistry contextRegistry : this.registrations)
         {
-            handlerRuntimes.add(contextRegistry.getRuntime());
+            handlerRuntimes.add(contextRegistry.getRuntime(failureRuntimeBuilder));
         }
         return handlerRuntimes;
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
index e7b3a22..3ead1b6 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
@@ -16,6 +16,10 @@
  */
 package org.apache.felix.http.base.internal.handler;
 
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SERVICE_ALREAY_USED;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -23,6 +27,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
 import java.util.TreeMap;
@@ -35,30 +40,32 @@
 import javax.servlet.Servlet;
 import javax.servlet.ServletException;
 
-import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime;
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime.ErrorPage;
 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.service.ResourceServlet;
+import org.apache.felix.http.base.internal.runtime.dto.ContextRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.ErrorPageRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.FailureRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.FilterRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.ServletRuntime;
+import org.apache.felix.http.base.internal.whiteboard.ResourceServlet;
 import org.apache.felix.http.base.internal.util.PatternUtil;
-import org.apache.felix.http.base.internal.whiteboard.ContextHandler;
+import org.apache.felix.http.base.internal.whiteboard.RegistrationFailureException;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceObjects;
 
 public final class PerContextHandlerRegistry implements Comparable<PerContextHandlerRegistry>
 {
-	private final BundleContext bundleContext;
+    private final BundleContext bundleContext;
 
     private final Map<Filter, FilterHandler> filterMap = new HashMap<Filter, FilterHandler>();
 
     private volatile HandlerMapping<ServletHandler> servletMapping = new HandlerMapping<ServletHandler>();
     private volatile HandlerMapping<FilterHandler> filterMapping = new HandlerMapping<FilterHandler>();
     private final ErrorsMapping errorsMapping = new ErrorsMapping();
-    
-    private SortedMap<Pattern, SortedSet<ServletHandler>> patternToServletHandler = new TreeMap<Pattern, SortedSet<ServletHandler>>(PatternUtil.PatternComparator.INSTANCE);
-    private Map<ServletHandler, Integer> servletHandlerToUses = new HashMap<ServletHandler, Integer>();
+
+    private final SortedMap<Pattern, SortedSet<ServletHandler>> patternToServletHandler = new TreeMap<Pattern, SortedSet<ServletHandler>>(PatternUtil.PatternComparator.INSTANCE);
+    private final Map<ServletHandler, Integer> servletHandlerToUses = new HashMap<ServletHandler, Integer>();
     private final SortedSet<ServletHandler> allServletHandlers = new TreeSet<ServletHandler>();
 
     private final long serviceId;
@@ -69,7 +76,8 @@
 
     private final String prefix;
 
-    public PerContextHandlerRegistry(BundleContext bundleContext) {
+    public PerContextHandlerRegistry(BundleContext bundleContext)
+    {
         this.serviceId = 0;
         this.ranking = Integer.MAX_VALUE;
         this.path = "/";
@@ -83,22 +91,22 @@
         this.ranking = info.getRanking();
         this.path = info.getPath();
         this.bundleContext = bundleContext;
-        if ( this.path.equals("/") )
+        if (this.path.equals("/"))
         {
-        	prefix = null;
+            prefix = null;
         }
         else
         {
-        	prefix = this.path + "/";
+            prefix = this.path + "/";
         }
     }
 
     public synchronized void addFilter(FilterHandler handler) throws ServletException
     {
-    	if(this.filterMapping.contains(handler))
-    	{
-    		throw new ServletException("Filter instance already registered");
-    	}
+        if (this.filterMapping.contains(handler))
+        {
+            throw new RegistrationFailureException(handler.getFilterInfo(), FAILURE_REASON_SERVICE_ALREAY_USED, "Filter instance " + handler.getName() + " already registered");
+        }
 
         handler.init();
         this.filterMapping = this.filterMapping.add(handler);
@@ -109,11 +117,12 @@
     public int compareTo(final PerContextHandlerRegistry other)
     {
         final int result = Integer.compare(other.path.length(), this.path.length());
-        if ( result == 0 ) {
+        if (result == 0)
+        {
             if (this.ranking == other.ranking)
             {
                 // Service id's can be negative. Negative id's follow the reverse natural ordering of integers.
-                int reverseOrder = ( this.serviceId >= 0 && other.serviceId >= 0 ) ? 1 : -1;
+                int reverseOrder = (this.serviceId >= 0 && other.serviceId >= 0) ? 1 : -1;
                 return reverseOrder * Long.compare(this.serviceId, other.serviceId);
             }
 
@@ -127,63 +136,64 @@
      */
     public synchronized void addServlet(final ServletHandler handler) throws ServletException
     {
-    	Pattern[] patterns = handler.getPatterns();
-    	String[] errorPages = handler.getServletInfo().getErrorPage();
-    	
-    	if(patterns.length > 0 && errorPages != null)
-    	{
-    		throw new ServletException("Servlet instance " + handler.getName() + " has both patterns and errorPage set");
-    	}
-    	
-    	SortedMap<Pattern, ServletHandler> toAdd = new TreeMap<Pattern, ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
-    	SortedMap<Pattern, ServletHandler> toRemove = new TreeMap<Pattern, ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
-    	
-    	this.servletHandlerToUses.put(handler, new Integer(0));
-    	
-    	for (Pattern p : patterns) 
-    	{
-    		ServletHandler prevHandler = null;
+        Pattern[] patterns = handler.getPatterns();
+        String[] errorPages = handler.getServletInfo().getErrorPage();
 
-    		if( !this.patternToServletHandler.containsKey(p))
-    		{
-    			this.patternToServletHandler.put(p, new TreeSet<ServletHandler>());
-    		}
-    		else
-    		{
-    			prevHandler = this.patternToServletHandler.get(p).first();
-    		}
-    		
-    		this.patternToServletHandler.get(p).add(handler);
-    		
-            if ( handler.equals(this.patternToServletHandler.get(p).first()))
+        if (patterns.length > 0 && errorPages != null)
+        {
+            throw new ServletException("Servlet instance " + handler.getName() + " has both patterns and errorPage set");
+        }
+
+        SortedMap<Pattern, ServletHandler> toAdd = new TreeMap<Pattern, ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
+        SortedMap<Pattern, ServletHandler> toRemove = new TreeMap<Pattern, ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
+
+        this.servletHandlerToUses.put(handler, new Integer(0));
+
+        for (Pattern p : patterns)
+        {
+            ServletHandler prevHandler = null;
+
+            if (!this.patternToServletHandler.containsKey(p))
             {
-            	useServletHandler(handler);
-            	if (!handler.isWhiteboardService())
-            	{
-            		handler.init();
-            	}
-            	increaseUseCount(handler);
-
-            	if (prevHandler != null)
-            	{
-            		decreaseUseCount(prevHandler);
-            		toRemove.put(p, prevHandler);
-            	}
-            	toAdd.put(p, handler);
+                this.patternToServletHandler.put(p, new TreeSet<ServletHandler>());
             }
-    	}
-    	
-    	this.servletMapping = this.servletMapping.remove(toRemove);
-    	this.servletMapping = this.servletMapping.add(toAdd);
-    	this.allServletHandlers.add(handler);
-    	
-    	if(errorPages != null)
-    	{
-    		for(String errorPage : errorPages)
-    		{
-    			this.errorsMapping.addErrorServlet(errorPage, handler);
-    		}
-    	}
+            else
+            {
+                prevHandler = this.patternToServletHandler.get(p).first();
+            }
+
+            this.patternToServletHandler.get(p).add(handler);
+
+            if (handler.equals(this.patternToServletHandler.get(p).first()))
+            {
+                useServletHandler(handler);
+                if (!handler.isWhiteboardService())
+                {
+                    handler.init();
+                }
+                increaseUseCount(handler);
+
+                if (prevHandler != null)
+                {
+                    decreaseUseCount(prevHandler);
+                    toRemove.put(p, prevHandler);
+                }
+                toAdd.put(p, handler);
+            }
+        }
+
+        this.servletMapping = this.servletMapping.remove(toRemove);
+        this.servletMapping = this.servletMapping.add(toAdd);
+        this.allServletHandlers.add(handler);
+
+        if (errorPages != null)
+        {
+            for (String errorPage : errorPages)
+            {
+                useServletHandler(handler);
+                this.errorsMapping.addErrorServlet(errorPage, handler);
+            }
+        }
     }
 
     /**
@@ -194,80 +204,83 @@
      * @param handler
      * @throws ServletException
      */
-    private void useServletHandler(ServletHandler handler) throws ServletException 
+    private void useServletHandler(ServletHandler handler) throws ServletException
     {
-    	if( (!handler.isWhiteboardService()) || (handler.getServlet() != null) )
-    	{
-    		return;
-    	}
-    	
-    	// isWhiteboardService && servlet == null
-    	boolean isResource = handler.getServletInfo().isResource();
-    	final ServiceObjects<Servlet> so = this.bundleContext.getServiceObjects(handler.getServletInfo().getServiceReference());
-    	
-    	Servlet servlet = getServiceObject(so, handler, isResource);
-    	handler.setServlet(servlet);
-    	
-    	try {
-			handler.init();
-		} catch (ServletException e) {
-			ungetServiceObject(so, servlet, isResource);
-			throw e;
-		}
-	}
-	
-	private Servlet getServiceObject(ServiceObjects<Servlet> so, ServletHandler handler, boolean isResource)
-	{
-		if(isResource) 
-		{
-			return new ResourceServlet(handler.getServletInfo().getPrefix());
-		}
-		if(so != null)
-		{
-			return so.getService();
-		}
-		return null;
-	}
-	
-	private void ungetServiceObject(ServiceObjects<Servlet> so, Servlet servlet, boolean isResource)
-	{
-		if(isResource || (so == null))
-		{
-			return;
-		}
-		so.ungetService(servlet);
-	}
+        if ((!handler.isWhiteboardService()) || (handler.getServlet() != null))
+        {
+            return;
+        }
 
-	private void increaseUseCount(ServletHandler handler) 
-	{
-		Integer uses = this.servletHandlerToUses.get(handler);
-		if(uses != null)
-		{
-			int newUsesValue = uses.intValue() + 1;
-			this.servletHandlerToUses.put(handler, new Integer(newUsesValue));
-		}
-	}
-	
-	private void decreaseUseCount(@Nonnull ServletHandler handler)
-	{
-		Integer uses = this.servletHandlerToUses.get(handler);
-		if(uses != null)
-		{
-			int newUsesValue = uses.intValue() - 1;
-			if(newUsesValue == 0 && handler.isWhiteboardService())
-			{		
-				// if the servlet is no longer used and it is registered as a whiteboard service
-				// call destroy, unget the service object and set the servlet in the handler to null
-				handler.destroy();
-				ServiceObjects<Servlet> so = this.bundleContext.getServiceObjects(handler.getServletInfo().getServiceReference());
-				ungetServiceObject(so, handler.getServlet(), handler.getServletInfo().isResource());
-				handler.setServlet(null);
-			}
-			this.servletHandlerToUses.put(handler, new Integer(newUsesValue));	
-		}
-	}
+        // isWhiteboardService && servlet == null
+        boolean isResource = handler.getServletInfo().isResource();
+        final ServiceObjects<Servlet> so = this.bundleContext.getServiceObjects(handler.getServletInfo().getServiceReference());
 
-	public ErrorsMapping getErrorsMapping()
+        Servlet servlet = getServiceObject(so, handler, isResource);
+        handler.setServlet(servlet);
+
+        try
+        {
+            handler.init();
+        }
+        catch (ServletException e)
+        {
+            ungetServiceObject(so, servlet, isResource);
+            throw e;
+        }
+    }
+
+    private Servlet getServiceObject(ServiceObjects<Servlet> so, ServletHandler handler, boolean isResource)
+    {
+        if (isResource)
+        {
+            return new ResourceServlet(handler.getServletInfo().getPrefix());
+        }
+        if (so != null)
+        {
+            return so.getService();
+        }
+        return null;
+    }
+
+    private void ungetServiceObject(ServiceObjects<Servlet> so, Servlet servlet, boolean isResource)
+    {
+        if (isResource || (so == null))
+        {
+            return;
+        }
+        so.ungetService(servlet);
+    }
+
+    private void increaseUseCount(ServletHandler handler)
+    {
+        Integer uses = this.servletHandlerToUses.get(handler);
+        if (uses != null)
+        {
+            int newUsesValue = uses.intValue() + 1;
+            this.servletHandlerToUses.put(handler, new Integer(newUsesValue));
+        }
+    }
+
+    private void decreaseUseCount(@Nonnull ServletHandler handler)
+    {
+        Integer uses = this.servletHandlerToUses.get(handler);
+        if (uses != null)
+        {
+            int newUsesValue = uses.intValue() - 1;
+            if (newUsesValue == 0 && handler.isWhiteboardService())
+            {
+                // if the servlet is no longer used and it is registered as a whiteboard service
+                // call destroy, unget the service object and set the servlet in the handler to null
+                handler.destroy();
+                ServiceObjects<Servlet> so = this.bundleContext.getServiceObjects(handler.getServletInfo().getServiceReference());
+                ungetServiceObject(so, handler.getServlet(), handler.getServletInfo().isResource());
+                handler.setServlet(null);
+            }
+            this.servletHandlerToUses.put(handler, new Integer(newUsesValue));
+        }
+    }
+
+    public ErrorsMapping getErrorsMapping()
     {
         return this.errorsMapping;
     }
@@ -300,10 +313,10 @@
 
         // TODO - we should already check for the context when building up the result set
         final Iterator<FilterHandler> i = result.iterator();
-        while ( i.hasNext() )
+        while (i.hasNext())
         {
             final FilterHandler handler = i.next();
-            if ( handler.getContextServiceId() != servletHandler.getContextServiceId() )
+            if (handler.getContextServiceId() != servletHandler.getContextServiceId())
             {
                 i.remove();
             }
@@ -378,105 +391,107 @@
 
     private FilterHandler getFilterHandler(final FilterInfo filterInfo)
     {
-        for(final FilterHandler handler : this.filterMap.values())
+        for (final FilterHandler handler : this.filterMap.values())
         {
-            if ( handler.getFilterInfo().compareTo(filterInfo) == 0)
+            if (handler.getFilterInfo().compareTo(filterInfo) == 0)
             {
                 return handler;
             }
         }
         return null;
     }
-    
-    public synchronized Servlet removeServlet(ServletInfo servletInfo, final boolean destroy)
+
+    public synchronized Servlet removeServlet(ServletInfo servletInfo, final boolean destroy) throws RegistrationFailureException
     {
-    	ServletHandler handler = getServletHandler(servletInfo);
-    	
-    	Pattern[] patterns = (handler == null) ? new Pattern[0] : handler.getPatterns();
-    	SortedMap<Pattern, ServletHandler> toAdd = new TreeMap<Pattern, ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
-    	SortedMap<Pattern, ServletHandler> toRemove = new TreeMap<Pattern, ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
+        ServletHandler handler = getServletHandler(servletInfo);
 
-    	for(Pattern p : patterns)
-    	{    		
-    		SortedSet<ServletHandler> handlers = this.patternToServletHandler.get(p);
-    		if(handlers != null && (!handlers.isEmpty()))
-    		{
-    			if(handlers.first().equals(handler))
-    			{
-    				toRemove.put(p, handler);
-    			}
-    			handlers.remove(handler);
-    			
-    			ServletHandler activeHandler = null;
-    			if( !handlers.isEmpty() )
-    			{
-    				activeHandler = handlers.first();
-    				
-    				try {
-    					useServletHandler(activeHandler);
-						increaseUseCount(activeHandler);
-						toAdd.put(p, activeHandler);
-					} catch (ServletException e) {
-						// TODO: next servlet handling this pattern could not be initialized, it belongs to failure DTOs
-					}
-    			}
-    			else 
-    			{
-    				this.patternToServletHandler.remove(p);
-				}
-    		}
-    	}
-    	
-    	Servlet servlet = null;
-    	if(handler != null)
-    	{
-    		servlet = handler.getServlet();
-    		if(destroy)
-    		{
-    			servlet.destroy();
-    		}
-    		if(handler.isWhiteboardService())
-    		{
-    			ServiceObjects<Servlet> so = this.bundleContext.getServiceObjects(handler.getServletInfo().getServiceReference());
-    			ungetServiceObject(so, servlet, servletInfo.isResource());
-    		}
-    	}
-    	
-    	this.servletHandlerToUses.remove(handler);
-    	
-		this.servletMapping = this.servletMapping.remove(toRemove);
-		this.servletMapping = this.servletMapping.add(toAdd);
+        Pattern[] patterns = (handler == null) ? new Pattern[0] : handler.getPatterns();
+        SortedMap<Pattern, ServletHandler> toAdd = new TreeMap<Pattern, ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
+        SortedMap<Pattern, ServletHandler> toRemove = new TreeMap<Pattern, ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
 
-		return servlet;
+        for (Pattern p : patterns)
+        {
+            SortedSet<ServletHandler> handlers = this.patternToServletHandler.get(p);
+            if (handlers != null && (!handlers.isEmpty()))
+            {
+                if (handlers.first().equals(handler))
+                {
+                    toRemove.put(p, handler);
+                }
+                handlers.remove(handler);
+
+                ServletHandler activeHandler = null;
+                if (!handlers.isEmpty())
+                {
+                    activeHandler = handlers.first();
+
+                    try
+                    {
+                        useServletHandler(activeHandler);
+                        increaseUseCount(activeHandler);
+                        toAdd.put(p, activeHandler);
+                    }
+                    catch (ServletException e)
+                    {
+                        throw new RegistrationFailureException(activeHandler.getServletInfo(), FAILURE_REASON_EXCEPTION_ON_INIT, e);
+                    }
+                }
+                else
+                {
+                    this.patternToServletHandler.remove(p);
+                }
+            }
+        }
+
+        Servlet servlet = null;
+        if (handler != null && handler.getServlet() != null)
+        {
+            servlet = handler.getServlet();
+            if (destroy)
+            {
+                servlet.destroy();
+            }
+            if (handler.isWhiteboardService())
+            {
+                ServiceObjects<Servlet> so = this.bundleContext.getServiceObjects(handler.getServletInfo().getServiceReference());
+                ungetServiceObject(so, servlet, servletInfo.isResource());
+            }
+        }
+
+        this.servletHandlerToUses.remove(handler);
+
+        this.servletMapping = this.servletMapping.remove(toRemove);
+        this.servletMapping = this.servletMapping.add(toAdd);
+
+        return servlet;
     }
 
     private ServletHandler getServletHandler(final ServletInfo servletInfo)
     {
-    	Iterator<ServletHandler> it = this.allServletHandlers.iterator();
-    	while(it.hasNext())
-    	{
-    		ServletHandler handler = it.next();
-    		if(handler.getServletInfo().compareTo(servletInfo) == 0)
-    		{
-    			return handler;
-    		}
-    	}
-    	return null;
+        Iterator<ServletHandler> it = this.allServletHandlers.iterator();
+        while (it.hasNext())
+        {
+            ServletHandler handler = it.next();
+            if (handler.getServletInfo().compareTo(servletInfo) == 0)
+            {
+                return handler;
+            }
+        }
+        return null;
     }
-    
-    public synchronized void removeServlet(Servlet servlet, final boolean destroy)
+
+    public synchronized void removeServlet(Servlet servlet, final boolean destroy) throws RegistrationFailureException
     {
-    	Iterator<ServletHandler> it = this.allServletHandlers.iterator();
-    	while(it.hasNext())
-    	{
-    		ServletHandler handler = it.next();
-    		if(handler.getServlet() == servlet) 
-    		{
-    			removeServlet(handler.getServletInfo(), destroy);
-    		}
-    	}
+        Iterator<ServletHandler> it = this.allServletHandlers.iterator();
+        while (it.hasNext())
+        {
+            ServletHandler handler = it.next();
+            if (handler.getServlet() == servlet)
+            {
+                removeServlet(handler.getServletInfo(), destroy);
+            }
+        }
     }
-    
 
     private boolean referencesDispatcherType(FilterHandler handler, DispatcherType dispatcherType)
     {
@@ -499,17 +514,17 @@
 
     public String isMatching(final String requestURI)
     {
-        if ( requestURI.equals(this.path) )
+        if (requestURI.equals(this.path))
         {
-        	return "";
+            return "";
         }
-        if ( this.prefix == null )
+        if (this.prefix == null)
         {
-        	return requestURI;
+            return requestURI;
         }
-        if ( requestURI.startsWith(this.prefix) )
+        if (requestURI.startsWith(this.prefix))
         {
-        	return requestURI.substring(this.prefix.length() - 1);
+            return requestURI.substring(this.prefix.length() - 1);
         }
         return null;
     }
@@ -519,34 +534,42 @@
         return this.serviceId;
     }
 
-    public synchronized HandlerRuntime getRuntime() {
-        Collection<ErrorPage> errorPages = new ArrayList<HandlerRuntime.ErrorPage>();
+    public synchronized ContextRuntime getRuntime(FailureRuntime.Builder failureRuntimeBuilder)
+    {
+        Collection<ErrorPageRuntime> errorPages = new TreeSet<ErrorPageRuntime>(ServletRuntime.COMPARATOR);
         Collection<ServletHandler> errorHandlers = errorsMapping.getMappedHandlers();
         for (ServletHandler servletHandler : errorHandlers)
         {
             errorPages.add(errorsMapping.getErrorPage(servletHandler));
         }
 
-        List<FilterHandler> filterHandlers = new ArrayList<FilterHandler>(filterMap.values());
-
-        List<ServletHandler> servletHandlers = new ArrayList<ServletHandler>();
-        List<ServletHandler> resourceHandlers = new ArrayList<ServletHandler>();
-        
-        Iterator<ServletHandler> it = this.allServletHandlers.iterator();
-        while(it.hasNext())
+        Collection<FilterRuntime> filterRuntimes = new TreeSet<FilterRuntime>(FilterRuntime.COMPARATOR);
+        for (FilterRuntime filterRuntime : filterMap.values())
         {
-        	ServletHandler servletHandler = it.next();
-        	
-        	if (servletHandler.getServletInfo().isResource())
+            filterRuntimes.add(filterRuntime);
+        }
+
+        Collection<ServletRuntime> servletRuntimes = new TreeSet<ServletRuntime>(ServletRuntime.COMPARATOR);
+        Collection<ServletRuntime> resourceRuntimes = new TreeSet<ServletRuntime>(ServletRuntime.COMPARATOR);
+
+        for (Set<ServletHandler> patternHandlers : patternToServletHandler.values())
+        {
+            Iterator<ServletHandler> itr = patternHandlers.iterator();
+            ServletHandler activeHandler = itr.next();
+            if (activeHandler.getServletInfo().isResource())
             {
-                resourceHandlers.add(servletHandler);
+                resourceRuntimes.add(activeHandler);
             }
-            else if (!errorHandlers.contains(servletHandler))
+            else
             {
-                servletHandlers.add(servletHandler);
+                servletRuntimes.add(activeHandler);
+            }
+            while (itr.hasNext())
+            {
+                failureRuntimeBuilder.add(itr.next().getServletInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
             }
         }
 
-        return new HandlerRuntime(servletHandlers, filterHandlers, resourceHandlers, errorPages, serviceId);
-    }    
+        return new ContextRuntime(servletRuntimes, filterRuntimes, resourceRuntimes, errorPages, serviceId);
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
index d640c0a..feeb3e7 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
@@ -31,12 +31,13 @@
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 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.dto.ServletRuntime;
 import org.apache.felix.http.base.internal.util.PatternUtil;
 
 /**
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class ServletHandler extends AbstractHandler<ServletHandler>
+public final class ServletHandler extends AbstractHandler<ServletHandler> implements ServletRuntime
 {
     private final ServletInfo servletInfo;
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
index 8f3d549..e30517a 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
@@ -49,11 +49,11 @@
 
     public AbstractInfo(final ServiceReference<T> ref)
     {
-        this.serviceId = (Long)ref.getProperty(Constants.SERVICE_ID);
+        this.serviceId = (Long) ref.getProperty(Constants.SERVICE_ID);
         final Object rankingObj = ref.getProperty(Constants.SERVICE_RANKING);
-        if ( rankingObj instanceof Integer )
+        if (rankingObj instanceof Integer)
         {
-            this.ranking = (Integer)rankingObj;
+            this.ranking = (Integer) rankingObj;
         }
         else
         {
@@ -88,7 +88,7 @@
             int reverseOrder = ( this.serviceId >= 0 && other.serviceId >= 0 ) ? 1 : -1;
             return reverseOrder * Long.compare(this.serviceId, other.serviceId);
         }
-
+        
         return Integer.compare(other.ranking, this.ranking);
     }
 
@@ -105,7 +105,7 @@
     protected String getStringProperty(final ServiceReference<T> ref, final String key)
     {
         final Object value = ref.getProperty(key);
-        return (value instanceof String) ? ((String) value).trim(): null;
+        return (value instanceof String) ? ((String) value).trim() : null;
     }
 
     protected String[] getStringArrayProperty(ServiceReference<T> ref, String key)
@@ -118,12 +118,12 @@
         }
         else if (value instanceof String[])
         {
-        	final String[] arr = (String[]) value;
-        	String[] values = new String[arr.length];
-        	
-            for(int i=0, j=0; i<arr.length; i++)
+            final String[] arr = (String[]) value;
+            String[] values = new String[arr.length];
+
+            for (int i = 0, j = 0; i < arr.length; i++)
             {
-                if ( arr[i] != null )
+                if (arr[i] != null)
                 {
                     values[j++] = arr[i].trim();
                 }
@@ -169,7 +169,7 @@
         final Map<String, String> result = new HashMap<String, String>();
         for (final String key : ref.getPropertyKeys())
         {
-            if ( key.startsWith(prefix))
+            if (key.startsWith(prefix))
             {
                 final String paramKey = key.substring(prefix.length());
                 final String paramValue = getStringProperty(ref, key);
@@ -205,10 +205,10 @@
 
     public T getService(final Bundle bundle)
     {
-        if ( this.serviceReference != null )
+        if (this.serviceReference != null)
         {
             final ServiceObjects<T> so = bundle.getBundleContext().getServiceObjects(this.serviceReference);
-            if ( so != null )
+            if (so != null)
             {
                 return so.getService();
             }
@@ -218,10 +218,10 @@
 
     public void ungetService(final Bundle bundle, final T service)
     {
-        if ( this.serviceReference != null )
+        if (this.serviceReference != null)
         {
             final ServiceObjects<T> so = bundle.getBundleContext().getServiceObjects(this.serviceReference);
-            if ( so != null )
+            if (so != null)
             {
                 so.ungetService(service);
             }
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 147e858..b9173e1 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
@@ -157,7 +157,7 @@
     @Override
     public boolean isValid()
     {
-        return super.isValid() && (!isEmpty(this.patterns) || !isEmpty(this.errorPage));
+        return super.isValid() && (isEmpty(this.patterns) ^ isEmpty(this.errorPage));
     }
 
     public String getName()
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseDTOBuilder.java
index 86fe97b..99361f8 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseDTOBuilder.java
@@ -29,7 +29,14 @@
 
 abstract class BaseDTOBuilder<T, U extends DTO>
 {
-    public Collection<U> build(Collection<T> whiteboardServices, long servletContextId)
+    private DTOFactory<U> dtoFactory;
+
+    BaseDTOBuilder(DTOFactory<U> dtoFactory)
+    {
+        this.dtoFactory = dtoFactory;
+    }
+
+    Collection<U> build(Collection<T> whiteboardServices, long servletContextId)
     {
         List<U> dtoList = new ArrayList<U>();
         for (T whiteboardService : whiteboardServices)
@@ -41,7 +48,12 @@
 
     abstract U buildDTO(T whiteboardService, long servletContextId);
 
-    protected <V> V[] copyWithDefault(V[] array, V[] defaultArray)
+    DTOFactory<U> getDTOFactory()
+    {
+        return dtoFactory;
+    }
+
+    <V> V[] copyWithDefault(V[] array, V[] defaultArray)
     {
         return array == null ? defaultArray : copyOf(array, array.length);
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseServletDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseServletDTOBuilder.java
index 34a26d4..f975e3a 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseServletDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseServletDTOBuilder.java
@@ -20,23 +20,45 @@
 
 import javax.servlet.Servlet;
 
-import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.osgi.service.http.runtime.dto.BaseServletDTO;
 
-abstract class BaseServletDTOBuilder<T, U extends BaseServletDTO> extends BaseDTOBuilder<T, U>
+abstract class BaseServletDTOBuilder<T extends ServletRuntime, U extends BaseServletDTO> extends BaseDTOBuilder<T, U>
 {
-    final U setBaseFields(U dto, ServletHandler servletHandler, long servletContextId)
+    BaseServletDTOBuilder(DTOFactory<U> servletDTOFactory)
     {
-        ServletInfo info = servletHandler.getServletInfo();
-        Servlet servlet = servletHandler.getServlet();
+        super(servletDTOFactory);
+    }
 
+    @Override
+    U buildDTO(T servletRuntime, long servletContextId)
+    {
+        ServletInfo info = servletRuntime.getServletInfo();
+        Servlet servlet = servletRuntime.getServlet();
+
+        U dto = getDTOFactory().get();
         dto.asyncSupported = info.isAsyncSupported();
         dto.initParams = info.getInitParameters();
-        dto.name = info.getName();
-        dto.serviceId = servletHandler.getServletInfo().getServiceId();
+        dto.name = getName(info, servlet);
+        dto.serviceId = servletRuntime.getServletInfo().getServiceId();
         dto.servletContextId = servletContextId;
-        dto.servletInfo = servlet.getServletInfo();
+        dto.servletInfo = servlet != null ? servlet.getServletInfo() : null;
         return dto;
     }
+
+    private String getName(ServletInfo info, Servlet servlet)
+    {
+        String name = info.getName();
+        if (name != null)
+        {
+            return name;
+        }
+
+        if (servlet != null)
+        {
+            return servlet.getServletConfig().getServletName();
+        }
+
+        return null;
+    }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BuilderConstants.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BuilderConstants.java
index ae9cb15..c6c3edb 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BuilderConstants.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BuilderConstants.java
@@ -19,6 +19,12 @@
 package org.apache.felix.http.base.internal.runtime.dto;
 
 import org.osgi.service.http.runtime.dto.ErrorPageDTO;
+import org.osgi.service.http.runtime.dto.FailedErrorPageDTO;
+import org.osgi.service.http.runtime.dto.FailedFilterDTO;
+import org.osgi.service.http.runtime.dto.FailedListenerDTO;
+import org.osgi.service.http.runtime.dto.FailedResourceDTO;
+import org.osgi.service.http.runtime.dto.FailedServletContextDTO;
+import org.osgi.service.http.runtime.dto.FailedServletDTO;
 import org.osgi.service.http.runtime.dto.FilterDTO;
 import org.osgi.service.http.runtime.dto.ListenerDTO;
 import org.osgi.service.http.runtime.dto.ResourceDTO;
@@ -37,4 +43,12 @@
     public static final FilterDTO[] FILTER_DTO_ARRAY = new FilterDTO[0];
     public static final ErrorPageDTO[] ERROR_PAGE_DTO_ARRAY = new ErrorPageDTO[0];
     public static final ListenerDTO[] LISTENER_DTO_ARRAY = new ListenerDTO[0];
+
+    public static final FailedServletContextDTO[] CONTEXT_FAILURE_DTO_ARRAY = new FailedServletContextDTO[0];
+
+    public static final FailedServletDTO[] SERVLET_FAILURE_DTO_ARRAY = new FailedServletDTO[0];
+    public static final FailedFilterDTO[] FILTER_FAILURE_DTO_ARRAY = new FailedFilterDTO[0];
+    public static final FailedResourceDTO[] RESOURCE_FAILURE_DTO_ARRAY = new FailedResourceDTO[0];
+    public static final FailedErrorPageDTO[] ERROR_PAGE_FAILURE_DTO_ARRAY = new FailedErrorPageDTO[0];
+    public static final FailedListenerDTO[] LISTENER_FAILURE_DTO_ARRAY = new FailedListenerDTO[0];
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ContextRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ContextRuntime.java
new file mode 100644
index 0000000..083dcc2
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ContextRuntime.java
@@ -0,0 +1,78 @@
+/*
+ * 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.runtime.dto;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public final class ContextRuntime
+{
+    private final Collection<ServletRuntime> servletRuntimes;
+    private final Collection<FilterRuntime> filterRuntimes;
+    private final Collection<ServletRuntime> resourceRuntimes;
+    private final Collection<ErrorPageRuntime> errorPageRuntimes;
+    private final long serviceId;
+
+    public ContextRuntime(Collection<ServletRuntime> servletRuntimes,
+            Collection<FilterRuntime> filterRuntimes,
+            Collection<ServletRuntime> resourceRuntimes,
+            Collection<ErrorPageRuntime> errorPageRuntimes,
+            long serviceId)
+    {
+        this.servletRuntimes = servletRuntimes;
+        this.filterRuntimes = filterRuntimes;
+        this.resourceRuntimes = resourceRuntimes;
+        this.errorPageRuntimes = errorPageRuntimes;
+        this.serviceId = serviceId;
+    }
+
+    public static ContextRuntime empty(long serviceId)
+    {
+        return new ContextRuntime(Collections.<ServletRuntime>emptyList(),
+                Collections.<FilterRuntime>emptyList(),
+                Collections.<ServletRuntime>emptyList(),
+                Collections.<ErrorPageRuntime> emptyList(),
+                serviceId);
+    }
+
+    public Collection<ServletRuntime> getServletRuntimes()
+    {
+        return servletRuntimes;
+    }
+
+    public Collection<FilterRuntime> getFilterRuntimes()
+    {
+        return filterRuntimes;
+    }
+
+    public Collection<ServletRuntime> getResourceRuntimes()
+    {
+        return resourceRuntimes;
+    }
+
+    public Collection<ErrorPageRuntime> getErrorPageRuntimes()
+    {
+        return errorPageRuntimes;
+    }
+
+    public long getServiceId()
+    {
+        return serviceId;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/DTOFactories.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/DTOFactories.java
new file mode 100644
index 0000000..1333f7b
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/DTOFactories.java
@@ -0,0 +1,123 @@
+/*
+ * 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.runtime.dto;
+
+import org.osgi.service.http.runtime.dto.ErrorPageDTO;
+import org.osgi.service.http.runtime.dto.FailedErrorPageDTO;
+import org.osgi.service.http.runtime.dto.FailedFilterDTO;
+import org.osgi.service.http.runtime.dto.FailedListenerDTO;
+import org.osgi.service.http.runtime.dto.FailedResourceDTO;
+import org.osgi.service.http.runtime.dto.FailedServletDTO;
+import org.osgi.service.http.runtime.dto.FilterDTO;
+import org.osgi.service.http.runtime.dto.ListenerDTO;
+import org.osgi.service.http.runtime.dto.ResourceDTO;
+import org.osgi.service.http.runtime.dto.ServletDTO;
+
+final class DTOFactories
+{
+    static final DTOFactory<ServletDTO> SERVLET = new DTOFactory<ServletDTO>()
+    {
+        @Override
+        public ServletDTO get()
+        {
+            return new ServletDTO();
+        }
+    };
+
+    static final DTOFactory<FailedServletDTO> FAILED_SERVLET = new DTOFactory<FailedServletDTO>()
+    {
+        @Override
+        public FailedServletDTO get()
+        {
+            return new FailedServletDTO();
+        }
+    };
+
+    static final DTOFactory<FilterDTO> FILTER = new DTOFactory<FilterDTO>()
+    {
+        @Override
+        public FilterDTO get()
+        {
+            return new FilterDTO();
+        }
+    };
+
+    static final DTOFactory<FailedFilterDTO> FAILED_FILTER = new DTOFactory<FailedFilterDTO>()
+    {
+        @Override
+        public FailedFilterDTO get()
+        {
+            return new FailedFilterDTO();
+        }
+    };
+
+    static final DTOFactory<ResourceDTO> RESOURCE = new DTOFactory<ResourceDTO>()
+    {
+        @Override
+        public ResourceDTO get()
+        {
+            return new ResourceDTO();
+        }
+    };
+
+    static final DTOFactory<FailedResourceDTO> FAILED_RESOURCE = new DTOFactory<FailedResourceDTO>()
+    {
+        @Override
+        public FailedResourceDTO get()
+        {
+            return new FailedResourceDTO();
+        }
+    };
+
+    static final DTOFactory<ListenerDTO> LISTENER = new DTOFactory<ListenerDTO>()
+    {
+        @Override
+        public ListenerDTO get()
+        {
+            return new ListenerDTO();
+        }
+    };
+
+    static final DTOFactory<FailedListenerDTO> FAILED_LISTENER = new DTOFactory<FailedListenerDTO>()
+    {
+        @Override
+        public FailedListenerDTO get()
+        {
+            return new FailedListenerDTO();
+        }
+    };
+
+    static final DTOFactory<ErrorPageDTO> ERROR_PAGE = new DTOFactory<ErrorPageDTO>()
+    {
+        @Override
+        public ErrorPageDTO get()
+        {
+            return new ErrorPageDTO();
+        }
+    };
+
+    static final DTOFactory<FailedErrorPageDTO> FAILED_ERROR_PAGE = new DTOFactory<FailedErrorPageDTO>()
+    {
+        @Override
+        public FailedErrorPageDTO get()
+        {
+            return new FailedErrorPageDTO();
+        }
+    };
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/DTOFactory.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/DTOFactory.java
new file mode 100644
index 0000000..011da27
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/DTOFactory.java
@@ -0,0 +1,24 @@
+/*
+ * 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.runtime.dto;
+
+interface DTOFactory<T>
+{
+    T get();
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageDTOBuilder.java
index b17d320..cbe71e7 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageDTOBuilder.java
@@ -21,16 +21,24 @@
 import java.util.Collection;
 import java.util.Iterator;
 
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime.ErrorPage;
 import org.osgi.service.http.runtime.dto.ErrorPageDTO;
 
-final class ErrorPageDTOBuilder extends BaseServletDTOBuilder<ErrorPage, ErrorPageDTO>
+final class ErrorPageDTOBuilder<T extends ErrorPageDTO> extends BaseServletDTOBuilder<ErrorPageRuntime, T>
 {
-    @Override
-    ErrorPageDTO buildDTO(ErrorPage errorPage, long servletConextId)
+    static ErrorPageDTOBuilder<ErrorPageDTO> create()
     {
-        ErrorPageDTO errorPageDTO = new ErrorPageDTO();
-        setBaseFields(errorPageDTO, errorPage.getServletHandler(), servletConextId);
+        return new ErrorPageDTOBuilder<ErrorPageDTO>(DTOFactories.ERROR_PAGE);
+    }
+
+    ErrorPageDTOBuilder(DTOFactory<T> dtoFactory)
+    {
+        super(dtoFactory);
+    }
+
+    @Override
+    T buildDTO(ErrorPageRuntime errorPage, long servletConextId)
+    {
+        T errorPageDTO = super.buildDTO(errorPage, servletConextId);
         errorPageDTO.errorCodes = getErrorCodes(errorPage.getErrorCodes());
         errorPageDTO.exceptions = errorPage.getExceptions().toArray(BuilderConstants.STRING_ARRAY);
         return errorPageDTO;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageRuntime.java
new file mode 100644
index 0000000..3155ede
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ErrorPageRuntime.java
@@ -0,0 +1,94 @@
+/*
+ * 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.runtime.dto;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.servlet.Servlet;
+
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+
+public class ErrorPageRuntime implements ServletRuntime
+{
+    private static final Pattern ERROR_CODE_PATTERN = Pattern.compile("\\d{3}");
+
+    private final ServletRuntime servletRuntime;
+    private final Collection<Integer> errorCodes;
+    private final Collection<String> exceptions;
+
+    public ErrorPageRuntime(ServletRuntime servletRuntime,
+            Collection<Integer> errorCodes,
+            Collection<String> exceptions)
+    {
+        this.servletRuntime = servletRuntime;
+        this.errorCodes = errorCodes;
+        this.exceptions = exceptions;
+    }
+
+    public static ErrorPageRuntime fromRuntime(ServletRuntime servletRuntime)
+    {
+        List<Integer> errorCodes = new ArrayList<Integer>();
+        List<String> exceptions = new ArrayList<String>();
+
+        for (String string : servletRuntime.getServletInfo().getErrorPage())
+        {
+            if (ERROR_CODE_PATTERN.matcher(string).matches())
+            {
+                errorCodes.add(Integer.valueOf(string));
+            }
+            else
+            {
+                exceptions.add(string);
+            }
+        }
+
+        return new ErrorPageRuntime(servletRuntime, errorCodes, exceptions);
+    }
+
+    public Collection<Integer> getErrorCodes()
+    {
+        return errorCodes;
+    }
+
+    public Collection<String> getExceptions()
+    {
+        return exceptions;
+    }
+
+    @Override
+    public long getContextServiceId()
+    {
+        return servletRuntime.getContextServiceId();
+    }
+
+    @Override
+    public Servlet getServlet()
+    {
+        return servletRuntime.getServlet();
+    }
+
+    @Override
+    public ServletInfo getServletInfo()
+    {
+        return servletRuntime.getServletInfo();
+    }
+}
\ No newline at end of file
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureFilterRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureFilterRuntime.java
new file mode 100644
index 0000000..52feeb3
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureFilterRuntime.java
@@ -0,0 +1,45 @@
+/*
+ * 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.runtime.dto;
+
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
+
+
+
+public class FailureFilterRuntime implements FilterRuntime
+{
+    private final FilterInfo filterInfo;
+
+    FailureFilterRuntime(FilterInfo FilterInfo)
+    {
+        this.filterInfo = FilterInfo;
+    }
+
+    @Override
+    public FilterInfo getFilterInfo()
+    {
+        return filterInfo;
+    }
+
+    @Override
+    public long getContextServiceId()
+    {
+        return 0L;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureRuntime.java
new file mode 100644
index 0000000..d156f83
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureRuntime.java
@@ -0,0 +1,318 @@
+/*
+ * 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.runtime.dto;
+
+import static org.apache.felix.http.base.internal.runtime.dto.BuilderConstants.CONTEXT_FAILURE_DTO_ARRAY;
+import static org.apache.felix.http.base.internal.runtime.dto.BuilderConstants.ERROR_PAGE_FAILURE_DTO_ARRAY;
+import static org.apache.felix.http.base.internal.runtime.dto.BuilderConstants.FILTER_FAILURE_DTO_ARRAY;
+import static org.apache.felix.http.base.internal.runtime.dto.BuilderConstants.LISTENER_FAILURE_DTO_ARRAY;
+import static org.apache.felix.http.base.internal.runtime.dto.BuilderConstants.RESOURCE_FAILURE_DTO_ARRAY;
+import static org.apache.felix.http.base.internal.runtime.dto.BuilderConstants.SERVLET_FAILURE_DTO_ARRAY;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.http.base.internal.runtime.AbstractInfo;
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
+import org.apache.felix.http.base.internal.runtime.ListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ResourceInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.runtime.dto.FailedErrorPageDTO;
+import org.osgi.service.http.runtime.dto.FailedFilterDTO;
+import org.osgi.service.http.runtime.dto.FailedListenerDTO;
+import org.osgi.service.http.runtime.dto.FailedResourceDTO;
+import org.osgi.service.http.runtime.dto.FailedServletContextDTO;
+import org.osgi.service.http.runtime.dto.FailedServletDTO;
+
+public final class FailureRuntime
+{
+    private static final FailureComparator<ErrorPageRuntime> ERROR_PAGE_COMPARATOR = FailureComparator.<ErrorPageRuntime>create(ServletRuntime.COMPARATOR);
+    private static final FailureComparator<FilterRuntime> FILTER_COMPARATOR = FailureComparator.create(FilterRuntime.COMPARATOR);
+    private static final FailureComparator<ServletContextHelperRuntime> CONTEXT_COMPARATOR = FailureComparator.create(ServletContextHelperRuntime.COMPARATOR);
+    private static final FailureComparator<ServletRuntime> SERVLET_COMPARATOR = FailureComparator.create(ServletRuntime.COMPARATOR);
+    private static final Comparator<Failure<ServiceReference<?>>> REFERENCE_COMPARATOR = new Comparator<Failure<ServiceReference<?>>>()
+    {
+        @Override
+        public int compare(Failure<ServiceReference<?>> o1, Failure<ServiceReference<?>> o2)
+        {
+            return o1.service.compareTo(o2.service);
+        }
+    };
+
+    private final List<Failure<ServletContextHelperRuntime>> contextRuntimes;
+    private final List<Failure<ServletRuntime>> servletRuntimes;
+    private final List<Failure<FilterRuntime>> filterRuntimes;
+    private final List<Failure<ServletRuntime>> resourceRuntimes;
+    private final List<Failure<ErrorPageRuntime>> errorPageRuntimes;
+    private final List<Failure<ServiceReference<?>>> listenerRuntimes;
+
+    private FailureRuntime(List<Failure<ServletContextHelperRuntime>> contextRuntimes,
+            List<Failure<ServiceReference<?>>> listenerRuntimes,
+            List<Failure<ServletRuntime>> servletRuntimes,
+            List<Failure<FilterRuntime>> filterRuntimes,
+            List<Failure<ServletRuntime>> resourceRuntimes,
+            List<Failure<ErrorPageRuntime>> errorPageRuntimes)
+    {
+        this.contextRuntimes = contextRuntimes;
+        this.servletRuntimes = servletRuntimes;
+        this.filterRuntimes = filterRuntimes;
+        this.resourceRuntimes = resourceRuntimes;
+        this.listenerRuntimes = listenerRuntimes;
+        this.errorPageRuntimes = errorPageRuntimes;
+    }
+
+    public static FailureRuntime empty()
+    {
+        return new FailureRuntime(Collections.<Failure<ServletContextHelperRuntime>>emptyList(),
+                Collections.<Failure<ServiceReference<?>>>emptyList(),
+                Collections.<Failure<ServletRuntime>>emptyList(),
+                Collections.<Failure<FilterRuntime>>emptyList(),
+                Collections.<Failure<ServletRuntime>>emptyList(),
+                Collections.<Failure<ErrorPageRuntime>>emptyList());
+    }
+
+    public static FailureRuntime.Builder builder()
+    {
+        return new Builder();
+    }
+
+    public FailedServletDTO[] getServletDTOs()
+    {
+        List<FailedServletDTO> servletDTOs = new ArrayList<FailedServletDTO>();
+        for (Failure<ServletRuntime> failure : servletRuntimes)
+        {
+            servletDTOs.add(getServletDTO(failure.service, failure.failureCode));
+        }
+        return servletDTOs.toArray(SERVLET_FAILURE_DTO_ARRAY);
+    }
+
+    private FailedServletDTO getServletDTO(ServletRuntime failedServlet, int failureCode)
+    {
+        ServletDTOBuilder<FailedServletDTO> dtoBuilder = new ServletDTOBuilder<FailedServletDTO>(DTOFactories.FAILED_SERVLET);
+        FailedServletDTO servletDTO = dtoBuilder.buildDTO(failedServlet, 0);
+        servletDTO.failureReason = failureCode;
+        return servletDTO;
+    }
+
+    public FailedFilterDTO[] getFilterDTOs()
+    {
+        List<FailedFilterDTO> filterDTOs = new ArrayList<FailedFilterDTO>();
+        for (Failure<FilterRuntime> failure : filterRuntimes)
+        {
+            filterDTOs.add(getFilterDTO(failure.service, failure.failureCode));
+        }
+        return filterDTOs.toArray(FILTER_FAILURE_DTO_ARRAY);
+    }
+
+    private FailedFilterDTO getFilterDTO(FilterRuntime failedFilter, int failureCode)
+    {
+        FilterDTOBuilder<FailedFilterDTO> dtoBuilder = new FilterDTOBuilder<FailedFilterDTO>(DTOFactories.FAILED_FILTER);
+        FailedFilterDTO filterDTO = dtoBuilder.buildDTO(failedFilter, 0);
+        filterDTO.failureReason = failureCode;
+        return filterDTO;
+    }
+
+    public FailedResourceDTO[] getResourceDTOs()
+    {
+        List<FailedResourceDTO> resourceDTOs = new ArrayList<FailedResourceDTO>();
+        for (Failure<ServletRuntime> failure : resourceRuntimes)
+        {
+            resourceDTOs.add(getResourceDTO(failure.service, failure.failureCode));
+        }
+        return resourceDTOs.toArray(RESOURCE_FAILURE_DTO_ARRAY);
+    }
+
+    private FailedResourceDTO getResourceDTO(ServletRuntime failedResource, int failureCode)
+    {
+        ResourceDTOBuilder<FailedResourceDTO> dtoBuilder = new ResourceDTOBuilder<FailedResourceDTO>(DTOFactories.FAILED_RESOURCE);
+        FailedResourceDTO resourceDTO = dtoBuilder.buildDTO(failedResource, 0);
+        resourceDTO.failureReason = failureCode;
+        return resourceDTO;
+    }
+
+    public FailedErrorPageDTO[] getErrorPageDTOs()
+    {
+        List<FailedErrorPageDTO> errorPageDTOs = new ArrayList<FailedErrorPageDTO>();
+        for (Failure<ErrorPageRuntime> failure : errorPageRuntimes)
+        {
+            errorPageDTOs.add(getErrorPageDTO(failure.service, failure.failureCode));
+        }
+        return errorPageDTOs.toArray(ERROR_PAGE_FAILURE_DTO_ARRAY);
+    }
+
+    private FailedErrorPageDTO getErrorPageDTO(ErrorPageRuntime failedErrorPage, int failureCode)
+    {
+        ErrorPageDTOBuilder<FailedErrorPageDTO> dtoBuilder = new ErrorPageDTOBuilder<FailedErrorPageDTO>(DTOFactories.FAILED_ERROR_PAGE);
+        FailedErrorPageDTO errorPageDTO = dtoBuilder.buildDTO(failedErrorPage, 0);
+        errorPageDTO.failureReason = failureCode;
+        return errorPageDTO;
+    }
+
+    public FailedListenerDTO[] getListenerDTOs()
+    {
+        List<FailedListenerDTO> listenerDTOs = new ArrayList<FailedListenerDTO>();
+        for (Failure<ServiceReference<?>> failure : listenerRuntimes)
+        {
+            listenerDTOs.add(getListenerDTO(failure.service, failure.failureCode));
+        }
+        return listenerDTOs.toArray(LISTENER_FAILURE_DTO_ARRAY);
+    }
+
+    private FailedListenerDTO getListenerDTO(ServiceReference<?> failedListener, int failureCode)
+    {
+        ListenerDTOBuilder<FailedListenerDTO> dtoBuilder = new ListenerDTOBuilder<FailedListenerDTO>(DTOFactories.FAILED_LISTENER);
+        FailedListenerDTO errorPageDTO = dtoBuilder.buildDTO(failedListener, 0);
+        errorPageDTO.failureReason = failureCode;
+        return errorPageDTO;
+    }
+
+    public FailedServletContextDTO[] getServletContextDTOs()
+    {
+        List<FailedServletContextDTO> contextDTOs = new ArrayList<FailedServletContextDTO>();
+        for (Failure<ServletContextHelperRuntime> failure : contextRuntimes)
+        {
+            contextDTOs.add(getServletContextDTO(failure.service, failure.failureCode));
+        }
+        return contextDTOs.toArray(CONTEXT_FAILURE_DTO_ARRAY);
+    }
+
+    private FailedServletContextDTO getServletContextDTO(ServletContextHelperRuntime failedContext, int failureCode)
+    {
+        ServletContextDTOBuilder dtoBuilder = new ServletContextDTOBuilder(new FailedServletContextDTO(), failedContext);
+        FailedServletContextDTO servletContextDTO = (FailedServletContextDTO) dtoBuilder.build();
+        servletContextDTO.failureReason = failureCode;
+        return servletContextDTO;
+    }
+
+    public static class Builder
+    {
+        private final List<Failure<ServletContextHelperRuntime>> contextRuntimes = new ArrayList<FailureRuntime.Failure<ServletContextHelperRuntime>>();
+        private final List<Failure<ServletRuntime>> servletRuntimes = new ArrayList<Failure<ServletRuntime>>();
+        private final List<Failure<FilterRuntime>> filterRuntimes = new ArrayList<Failure<FilterRuntime>>();
+        private final List<Failure<ServletRuntime>> resourceRuntimes = new ArrayList<Failure<ServletRuntime>>();
+        private final List<Failure<ErrorPageRuntime>> errorPageRuntimes = new ArrayList<Failure<ErrorPageRuntime>>();
+        private final List<Failure<ServiceReference<?>>> listenerRuntimes = new ArrayList<Failure<ServiceReference<?>>>();
+
+        public FailureRuntime.Builder add(Map<AbstractInfo<?>, Integer> failureInfos)
+        {
+            for (Map.Entry<AbstractInfo<?>, Integer> failureEntry : failureInfos.entrySet())
+            {
+                add(failureEntry.getKey(), failureEntry.getValue());
+            }
+            return this;
+        }
+
+        public FailureRuntime.Builder add(AbstractInfo<?> info, int failureCode)
+        {
+            if (info instanceof ServletContextHelperInfo)
+            {
+                ServletContextHelperRuntime servletRuntime = new FailureServletContextHelperRuntime((ServletContextHelperInfo) info);
+                contextRuntimes.add(new Failure<ServletContextHelperRuntime>(servletRuntime, failureCode));
+            }
+            else if (info instanceof ServletInfo && ((ServletInfo) info).getErrorPage() != null)
+            {
+                FailureServletRuntime servletRuntime = new FailureServletRuntime((ServletInfo) info);
+                ErrorPageRuntime errorPageRuntime = ErrorPageRuntime.fromRuntime(servletRuntime);
+                errorPageRuntimes.add(new Failure<ErrorPageRuntime>(errorPageRuntime, failureCode));
+            }
+            else if (info instanceof ServletInfo)
+            {
+                ServletRuntime servletRuntime = new FailureServletRuntime((ServletInfo) info);
+                servletRuntimes.add(new Failure<ServletRuntime>(servletRuntime, failureCode));
+            }
+            else if (info instanceof FilterInfo)
+            {
+                FilterRuntime filterRuntime = new FailureFilterRuntime((FilterInfo) info);
+                filterRuntimes.add(new Failure<FilterRuntime>(filterRuntime, failureCode));
+            }
+            else if (info instanceof ResourceInfo)
+            {
+                ServletRuntime servletRuntime = new FailureServletRuntime(new ServletInfo((ResourceInfo) info));
+                resourceRuntimes.add(new Failure<ServletRuntime>(servletRuntime, failureCode));
+            }
+            else if (info instanceof ListenerInfo)
+            {
+                ServiceReference<?> serviceReference = ((ListenerInfo<?>) info).getServiceReference();
+                listenerRuntimes.add(new Failure<ServiceReference<?>>(serviceReference, failureCode));
+            }
+            else
+            {
+                throw new IllegalArgumentException("Unsupported info type: " + info.getClass());
+            }
+            return this;
+        }
+
+        public FailureRuntime build()
+        {
+            Collections.sort(contextRuntimes, CONTEXT_COMPARATOR);
+            Collections.sort(listenerRuntimes, REFERENCE_COMPARATOR);
+            Collections.sort(servletRuntimes, SERVLET_COMPARATOR);
+            Collections.sort(filterRuntimes, FILTER_COMPARATOR);
+            Collections.sort(resourceRuntimes, SERVLET_COMPARATOR);
+            Collections.sort(errorPageRuntimes, ERROR_PAGE_COMPARATOR);
+
+            return new FailureRuntime(contextRuntimes,
+                    listenerRuntimes,
+                    servletRuntimes,
+                    filterRuntimes,
+                    resourceRuntimes,
+                    errorPageRuntimes);
+        }
+    }
+
+    private static class Failure<T>
+    {
+
+        final T service;
+        final int failureCode;
+
+        Failure(T service, int failureCode)
+        {
+            this.service = service;
+            this.failureCode = failureCode;
+        }
+    }
+
+    private static class FailureComparator<T> implements Comparator<Failure<T>>
+    {
+        final Comparator<? super T> serviceComparator;
+
+        FailureComparator(Comparator<? super T> serviceComparator)
+        {
+            this.serviceComparator = serviceComparator;
+        }
+
+        static <T> FailureComparator<T> create(Comparator<? super T> serviceComparator)
+        {
+            return new FailureComparator<T>(serviceComparator);
+        }
+
+        @Override
+        public int compare(Failure<T> o1, Failure<T> o2)
+        {
+            return serviceComparator.compare(o1.service, o2.service);
+        }
+    }
+}
+
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureServletContextHelperRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureServletContextHelperRuntime.java
new file mode 100644
index 0000000..11b3f75
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureServletContextHelperRuntime.java
@@ -0,0 +1,51 @@
+/*
+ * 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.runtime.dto;
+
+import javax.servlet.ServletContext;
+
+import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+
+public class FailureServletContextHelperRuntime implements ServletContextHelperRuntime, Comparable<FailureServletContextHelperRuntime>
+{
+    private final ServletContextHelperInfo info;
+
+    public FailureServletContextHelperRuntime(ServletContextHelperInfo info)
+    {
+        this.info = info;
+    }
+
+    @Override
+    public ServletContext getSharedContext()
+    {
+        return null;
+    }
+
+    @Override
+    public ServletContextHelperInfo getContextInfo()
+    {
+        return info;
+    }
+
+    @Override
+    public int compareTo(FailureServletContextHelperRuntime other)
+    {
+        return info.compareTo(other.info);
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureServletRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureServletRuntime.java
new file mode 100644
index 0000000..2f4383f
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailureServletRuntime.java
@@ -0,0 +1,53 @@
+/*
+ * 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.runtime.dto;
+
+import javax.servlet.Servlet;
+
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+
+
+
+public class FailureServletRuntime implements ServletRuntime
+{
+    private final ServletInfo servletInfo;
+
+    FailureServletRuntime(ServletInfo servletInfo)
+    {
+        this.servletInfo = servletInfo;
+    }
+
+    @Override
+    public ServletInfo getServletInfo()
+    {
+        return servletInfo;
+    }
+
+    @Override
+    public long getContextServiceId()
+    {
+        return 0L;
+    }
+
+    @Override
+    public Servlet getServlet()
+    {
+        return null;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterDTOBuilder.java
index 1023f5b..902e079 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterDTOBuilder.java
@@ -20,25 +20,34 @@
 
 import javax.servlet.DispatcherType;
 
-import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.osgi.service.http.runtime.dto.FilterDTO;
 
-final class FilterDTOBuilder extends BaseDTOBuilder<FilterHandler, FilterDTO>
+final class FilterDTOBuilder<T extends FilterDTO> extends BaseDTOBuilder<FilterRuntime, T>
 {
-    @Override
-    FilterDTO buildDTO(FilterHandler filterHandler, long servletContextId)
+    static FilterDTOBuilder<FilterDTO> create()
     {
-        FilterInfo info = filterHandler.getFilterInfo();
+        return new FilterDTOBuilder<FilterDTO>(DTOFactories.FILTER);
+    }
 
-        FilterDTO filterDTO = new FilterDTO();
+    FilterDTOBuilder(DTOFactory<T> dtoFactory)
+    {
+        super(dtoFactory);
+    }
+
+    @Override
+    T buildDTO(FilterRuntime filterRuntime, long servletContextId)
+    {
+        FilterInfo info = filterRuntime.getFilterInfo();
+
+        T filterDTO = getDTOFactory().get();
         filterDTO.asyncSupported = info.isAsyncSupported();
         filterDTO.dispatcher = getNames(info.getDispatcher());
         filterDTO.initParams = info.getInitParameters();
         filterDTO.name = info.getName();
         filterDTO.patterns = copyWithDefault(info.getPatterns(), BuilderConstants.STRING_ARRAY);
         filterDTO.regexs = copyWithDefault(info.getRegexs(), BuilderConstants.STRING_ARRAY);
-        filterDTO.serviceId = filterHandler.getFilterInfo().getServiceId();
+        filterDTO.serviceId = info.getServiceId();
         filterDTO.servletContextId = servletContextId;
         filterDTO.servletNames = copyWithDefault(info.getServletNames(), BuilderConstants.STRING_ARRAY);
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterRuntime.java
new file mode 100644
index 0000000..501402e
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FilterRuntime.java
@@ -0,0 +1,39 @@
+/*
+ * 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.runtime.dto;
+
+import java.util.Comparator;
+
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
+
+
+
+public interface FilterRuntime extends WhiteboardServiceRuntime
+{
+    static final Comparator<FilterRuntime> COMPARATOR = new Comparator<FilterRuntime>()
+    {
+        @Override
+        public int compare(FilterRuntime o1, FilterRuntime o2)
+        {
+            return o1.getFilterInfo().compareTo(o2.getFilterInfo());
+        }
+    };
+
+    FilterInfo getFilterInfo();
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java
index 34d2989..00f8bd7 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ListenerDTOBuilder.java
@@ -22,12 +22,22 @@
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.runtime.dto.ListenerDTO;
 
-final class ListenerDTOBuilder extends BaseDTOBuilder<ServiceReference<?>, ListenerDTO>
+final class ListenerDTOBuilder<T extends ListenerDTO> extends BaseDTOBuilder<ServiceReference<?>, T>
 {
-    @Override
-    ListenerDTO buildDTO(ServiceReference<?> listenerRef, long servletContextId)
+    static ListenerDTOBuilder<ListenerDTO> create()
     {
-        ListenerDTO listenerDTO = new ListenerDTO();
+        return new ListenerDTOBuilder<ListenerDTO>(DTOFactories.LISTENER);
+    }
+
+    ListenerDTOBuilder(DTOFactory<T> dtoFactory)
+    {
+        super(dtoFactory);
+    }
+
+    @Override
+    T buildDTO(ServiceReference<?> listenerRef, long servletContextId)
+    {
+        T listenerDTO = getDTOFactory().get();
         listenerDTO.serviceId = (Long) listenerRef.getProperty(Constants.SERVICE_ID);
         listenerDTO.servletContextId = servletContextId;
         // TODO Is this the desired value?
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RegistryRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RegistryRuntime.java
new file mode 100644
index 0000000..cfd2621
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RegistryRuntime.java
@@ -0,0 +1,97 @@
+/*
+ * 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.runtime.dto;
+
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.ServiceReference;
+
+public final class RegistryRuntime
+{
+    private final Collection<ServletContextHelperRuntime> contexts;
+    private final Map<Long, Collection<ServiceReference<?>>> listenerRuntimes;
+    private final Map<Long, ContextRuntime> handlerRuntimes;
+    private final FailureRuntime failureRuntime;
+
+    public RegistryRuntime(Collection<ServletContextHelperRuntime> contexts,
+            Collection<ContextRuntime> contextRuntimes,
+            Map<Long, Collection<ServiceReference<?>>> listenerRuntimes,
+            FailureRuntime failureRuntime)
+    {
+        this.contexts = contexts;
+        this.failureRuntime = failureRuntime;
+        this.handlerRuntimes = createServiceIdMap(contextRuntimes);
+        this.listenerRuntimes = listenerRuntimes;
+    }
+
+    private static Map<Long, ContextRuntime> createServiceIdMap(Collection<ContextRuntime> contextRuntimes)
+    {
+        Map<Long, ContextRuntime> runtimesMap = new HashMap<Long, ContextRuntime>();
+        for (ContextRuntime contextRuntime : contextRuntimes)
+        {
+            runtimesMap.put(contextRuntime.getServiceId(), contextRuntime);
+        }
+        return runtimesMap;
+    }
+
+    public ContextRuntime getHandlerRuntime(ServletContextHelperRuntime contextRuntime)
+    {
+        long serviceId = contextRuntime.getContextInfo().getServiceId();
+
+        if (handlerRuntimes.containsKey(serviceId) && isDefaultContext(contextRuntime))
+        {
+            // TODO Merge with the default context of the HttpService ( handlerRuntimes.get(0) )
+            return handlerRuntimes.get(serviceId);
+        }
+        else if (handlerRuntimes.containsKey(serviceId))
+        {
+            return handlerRuntimes.get(serviceId);
+        }
+        return ContextRuntime.empty(serviceId);
+    }
+
+    private boolean isDefaultContext(ServletContextHelperRuntime contextRuntime)
+    {
+        return contextRuntime.getContextInfo().getName().equals(HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME);
+    }
+
+    public Collection<ServiceReference<?>> getListenerRuntimes(ServletContextHelperRuntime contextRuntime)
+    {
+        if (listenerRuntimes.containsKey(contextRuntime.getContextInfo().getServiceId()))
+        {
+            return listenerRuntimes.get(contextRuntime.getContextInfo().getServiceId());
+        }
+        return Collections.emptyList();
+    }
+
+    public Collection<ServletContextHelperRuntime> getContexts()
+    {
+        return contexts;
+    }
+
+    public FailureRuntime getFailureRuntime()
+    {
+        return failureRuntime;
+    }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ResourceDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ResourceDTOBuilder.java
index e9b7e09..9aac097 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ResourceDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ResourceDTOBuilder.java
@@ -18,18 +18,27 @@
  */
 package org.apache.felix.http.base.internal.runtime.dto;
 
-import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.osgi.service.http.runtime.dto.ResourceDTO;
 
-final class ResourceDTOBuilder extends BaseDTOBuilder<ServletHandler, ResourceDTO>
+final class ResourceDTOBuilder<T extends ResourceDTO> extends BaseDTOBuilder<ServletRuntime, T>
 {
-    @Override
-    ResourceDTO buildDTO(ServletHandler handler, long servletContextId)
+    static ResourceDTOBuilder<ResourceDTO> create()
     {
-        ServletInfo servletInfo = handler.getServletInfo();
+        return new ResourceDTOBuilder<ResourceDTO>(DTOFactories.RESOURCE);
+    }
 
-        ResourceDTO resourceDTO = new ResourceDTO();
+    ResourceDTOBuilder(DTOFactory<T> dtoFactory)
+    {
+        super(dtoFactory);
+    }
+
+    @Override
+    T buildDTO(ServletRuntime runtime, long servletContextId)
+    {
+        ServletInfo servletInfo = runtime.getServletInfo();
+
+        T resourceDTO = getDTOFactory().get();
         resourceDTO.patterns = copyWithDefault(servletInfo.getPatterns(), BuilderConstants.STRING_ARRAY);
         resourceDTO.prefix = servletInfo.getPrefix();
         resourceDTO.serviceId = servletInfo.getServiceId();
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java
index 2e8b320..b381af6 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilder.java
@@ -20,28 +20,12 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.felix.http.base.internal.handler.FilterHandler;
-import org.apache.felix.http.base.internal.handler.ServletHandler;
-import org.apache.felix.http.base.internal.runtime.AbstractInfo;
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime;
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime.ErrorPage;
-import org.apache.felix.http.base.internal.runtime.RegistryRuntime;
-import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
-import org.apache.felix.http.base.internal.whiteboard.ContextHandler;
 import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.runtime.dto.DTOConstants;
 import org.osgi.service.http.runtime.dto.ErrorPageDTO;
-import org.osgi.service.http.runtime.dto.FailedErrorPageDTO;
-import org.osgi.service.http.runtime.dto.FailedFilterDTO;
-import org.osgi.service.http.runtime.dto.FailedListenerDTO;
-import org.osgi.service.http.runtime.dto.FailedResourceDTO;
-import org.osgi.service.http.runtime.dto.FailedServletContextDTO;
-import org.osgi.service.http.runtime.dto.FailedServletDTO;
 import org.osgi.service.http.runtime.dto.FilterDTO;
 import org.osgi.service.http.runtime.dto.ListenerDTO;
 import org.osgi.service.http.runtime.dto.ResourceDTO;
@@ -52,12 +36,6 @@
 public final class RuntimeDTOBuilder
 {
 
-    private static final ServletDTOBuilder SERVLET_DTO_BUILDER = new ServletDTOBuilder();
-    private static final ResourceDTOBuilder RESOURCE_DTO_BUILDER = new ResourceDTOBuilder();
-    private static final FilterDTOBuilder FILTER_DTO_BUILDER = new FilterDTOBuilder();
-    private static final ErrorPageDTOBuilder ERROR_PAGE_DTO_BUILDER = new ErrorPageDTOBuilder();
-    private static final ListenerDTOBuilder LISTENER_DTO_BUILDER = new ListenerDTOBuilder();
-
     private final RegistryRuntime registry;
     private final Map<String, Object> serviceProperties;
 
@@ -69,44 +47,16 @@
 
     public RuntimeDTO build()
     {
+        FailureRuntime failureRuntime = registry.getFailureRuntime();
+
         RuntimeDTO runtimeDTO = new RuntimeDTO();
         runtimeDTO.attributes = createAttributes();
-        final List<FailedErrorPageDTO> failedErrorPageDTOs = new ArrayList<FailedErrorPageDTO>();
-        final List<FailedFilterDTO> failedFilterDTOs = new ArrayList<FailedFilterDTO>();
-        final List<FailedListenerDTO> failedListenerDTOs = new ArrayList<FailedListenerDTO>();
-        final List<FailedResourceDTO> failedResourceDTOs = new ArrayList<FailedResourceDTO>();
-        final List<FailedServletContextDTO> failedServletContextDTOs = new ArrayList<FailedServletContextDTO>();
-        final List<FailedServletDTO> failedServletDTOs = new ArrayList<FailedServletDTO>();
-
-        for(final AbstractInfo<?> info : this.registry.getInvalidServices())
-        {
-            if ( info instanceof ServletContextHelperInfo )
-            {
-                final ServletContextHelperInfo sch = (ServletContextHelperInfo)info;
-                final FailedServletContextDTO dto = new FailedServletContextDTO();
-                dto.attributes = Collections.emptyMap();
-                dto.contextPath = sch.getPath();
-                dto.errorPageDTOs = BuilderConstants.ERROR_PAGE_DTO_ARRAY;
-                dto.failureReason = DTOConstants.FAILURE_REASON_VALIDATION_FAILED;
-                dto.filterDTOs = BuilderConstants.FILTER_DTO_ARRAY;
-                dto.initParams = sch.getInitParameters();
-                dto.listenerDTOs = BuilderConstants.LISTENER_DTO_ARRAY;
-                dto.name = sch.getName();
-                dto.resourceDTOs = BuilderConstants.RESOURCE_DTO_ARRAY;
-                dto.serviceId = sch.getServiceId();
-                dto.servletDTOs = BuilderConstants.SERVLET_DTO_ARRAY;
-
-                failedServletContextDTOs.add(dto);
-            }
-        }
-        //TODO <**
-        runtimeDTO.failedErrorPageDTOs = failedErrorPageDTOs.toArray(new FailedErrorPageDTO[failedErrorPageDTOs.size()]);
-        runtimeDTO.failedFilterDTOs = failedFilterDTOs.toArray(new FailedFilterDTO[failedFilterDTOs.size()]);
-        runtimeDTO.failedListenerDTOs = failedListenerDTOs.toArray(new FailedListenerDTO[failedListenerDTOs.size()]);
-        runtimeDTO.failedResourceDTOs = failedResourceDTOs.toArray(new FailedResourceDTO[failedResourceDTOs.size()]);
-        runtimeDTO.failedServletContextDTOs = failedServletContextDTOs.toArray(new FailedServletContextDTO[failedServletContextDTOs.size()]);
-        runtimeDTO.failedServletDTOs = failedServletDTOs.toArray(new FailedServletDTO[failedServletDTOs.size()]);
-        //**>
+        runtimeDTO.failedErrorPageDTOs = failureRuntime.getErrorPageDTOs();
+        runtimeDTO.failedFilterDTOs = failureRuntime.getFilterDTOs();
+        runtimeDTO.failedListenerDTOs = failureRuntime.getListenerDTOs();
+        runtimeDTO.failedResourceDTOs = failureRuntime.getResourceDTOs();
+        runtimeDTO.failedServletContextDTOs = failureRuntime.getServletContextDTOs();
+        runtimeDTO.failedServletDTOs = failureRuntime.getServletDTOs();
         runtimeDTO.servletContextDTOs = createContextDTOs();
         return runtimeDTO;
     }
@@ -124,37 +74,37 @@
     private ServletContextDTO[] createContextDTOs()
     {
         List<ServletContextDTO> contextDTOs = new ArrayList<ServletContextDTO>();
-        for (ContextHandler context : registry.getContexts())
+        for (ServletContextHelperRuntime context : registry.getContexts())
         {
             contextDTOs.add(createContextDTO(context,
                     registry.getHandlerRuntime(context),
-                    registry.getListenerRuntime(context)));
+                    registry.getListenerRuntimes(context)));
         }
         return contextDTOs.toArray(BuilderConstants.CONTEXT_DTO_ARRAY);
     }
 
-    private ServletContextDTO createContextDTO(ContextHandler context,
-            HandlerRuntime handlerRuntime,
-            Collection<ServiceReference<?>> listenerRefs)
+    private ServletContextDTO createContextDTO(ServletContextHelperRuntime context,
+            ContextRuntime contextRuntime,
+            Collection<ServiceReference<?>> listenerRuntimes)
     {
-        Collection<ServletHandler> servletHandlers = handlerRuntime.getServletHandlers();
-        Collection<ServletHandler> resourceHandlers = handlerRuntime.getResourceHandlers();
-        Collection<FilterHandler> filterHandlers = handlerRuntime.getFilterHandlers();
-        Collection<ErrorPage> errorPages = handlerRuntime.getErrorPages();
-        long servletContextId = handlerRuntime.getServiceId();
+        Collection<ServletRuntime> servletRuntimes = contextRuntime.getServletRuntimes();
+        Collection<ServletRuntime> resourceRuntimes = contextRuntime.getResourceRuntimes();
+        Collection<FilterRuntime> filterRuntimes = contextRuntime.getFilterRuntimes();
+        Collection<ErrorPageRuntime> errorPageRuntimes = contextRuntime.getErrorPageRuntimes();
+        long servletContextId = contextRuntime.getServiceId();
 
-        Collection<ServletDTO> servletDTOs = SERVLET_DTO_BUILDER.build(servletHandlers, servletContextId);
-        Collection<ResourceDTO> resourcesDTOs = RESOURCE_DTO_BUILDER.build(resourceHandlers, servletContextId);
-        Collection<FilterDTO> filtersDTOs = FILTER_DTO_BUILDER.build(filterHandlers, servletContextId);
-        Collection<ErrorPageDTO> errorsDTOs = ERROR_PAGE_DTO_BUILDER.build(errorPages, servletContextId);
-        Collection<ListenerDTO> listenersDTOs = LISTENER_DTO_BUILDER.build(listenerRefs, servletContextId);
+        Collection<ServletDTO> servletDTOs = ServletDTOBuilder.create().build(servletRuntimes, servletContextId);
+        Collection<ResourceDTO> resourceDTOs = ResourceDTOBuilder.create().build(resourceRuntimes, servletContextId);
+        Collection<FilterDTO> filterDTOs = FilterDTOBuilder.create().build(filterRuntimes, servletContextId);
+        Collection<ErrorPageDTO> errorDTOs = ErrorPageDTOBuilder.create().build(errorPageRuntimes, servletContextId);
+        Collection<ListenerDTO> listenerDTOs = ListenerDTOBuilder.create().build(listenerRuntimes, servletContextId);
 
         return new ServletContextDTOBuilder(context,
                     servletDTOs,
-                    resourcesDTOs,
-                    filtersDTOs,
-                    errorsDTOs,
-                    listenersDTOs)
+                    resourceDTOs,
+                    filterDTOs,
+                    errorDTOs,
+                    listenerDTOs)
                 .build();
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextDTOBuilder.java
index f32f815..34d5bc4 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextDTOBuilder.java
@@ -21,13 +21,13 @@
 import static java.util.Collections.list;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.servlet.ServletContext;
 
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
-import org.apache.felix.http.base.internal.whiteboard.ContextHandler;
 import org.osgi.dto.DTO;
 import org.osgi.service.http.runtime.dto.ErrorPageDTO;
 import org.osgi.service.http.runtime.dto.FilterDTO;
@@ -39,21 +39,24 @@
 final class ServletContextDTOBuilder
 {
 
-    private final ContextHandler contextHandler;
+    private final ServletContextDTO contextDTO;
+    private final ServletContextHelperRuntime contextRuntime;
     private final ServletDTO[] servletDTOs;
     private final ResourceDTO[] resourceDTOs;
     private final FilterDTO[] filterDTOs;
     private final ErrorPageDTO[] errorPageDTOs;
     private final ListenerDTO[] listenerDTOs;
 
-    public ServletContextDTOBuilder(ContextHandler contextHandler,
+    ServletContextDTOBuilder(ServletContextDTO contextDTO,
+            ServletContextHelperRuntime contextRuntime,
             Collection<ServletDTO> servletDTOs,
             Collection<ResourceDTO> resourceDTOs,
             Collection<FilterDTO> filterDTOs,
             Collection<ErrorPageDTO> errorPageDTOs,
             Collection<ListenerDTO> listenerDTOs)
     {
-        this.contextHandler = contextHandler;
+        this.contextDTO = contextDTO;
+        this.contextRuntime = contextRuntime;
         this.servletDTOs = servletDTOs != null ?
                 servletDTOs.toArray(BuilderConstants.SERVLET_DTO_ARRAY) : BuilderConstants.SERVLET_DTO_ARRAY;
         this.resourceDTOs = resourceDTOs != null ?
@@ -66,20 +69,34 @@
                 listenerDTOs.toArray(BuilderConstants.LISTENER_DTO_ARRAY) : BuilderConstants.LISTENER_DTO_ARRAY;
     }
 
+    ServletContextDTOBuilder(ServletContextHelperRuntime contextRuntime,
+            Collection<ServletDTO> servletDTOs,
+            Collection<ResourceDTO> resourceDTOs,
+            Collection<FilterDTO> filterDTOs,
+            Collection<ErrorPageDTO> errorPageDTOs,
+            Collection<ListenerDTO> listenerDTOs)
+    {
+        this(new ServletContextDTO(), contextRuntime, servletDTOs, resourceDTOs, filterDTOs, errorPageDTOs, listenerDTOs);
+    }
+
+    ServletContextDTOBuilder(ServletContextDTO contextDTO, ServletContextHelperRuntime contextRuntime)
+    {
+        this(contextDTO, contextRuntime, null, null, null, null, null);
+    }
+
     ServletContextDTO build()
     {
-        ServletContext context  = contextHandler.getSharedContext();
-        ServletContextHelperInfo contextInfo = contextHandler.getContextInfo();
+        ServletContext context  = contextRuntime.getSharedContext();
+        ServletContextHelperInfo contextInfo = contextRuntime.getContextInfo();
         long contextId = contextInfo.getServiceId();
 
-        ServletContextDTO contextDTO = new ServletContextDTO();
         contextDTO.attributes = getAttributes(context);
-        contextDTO.contextPath = context.getContextPath();
+        contextDTO.contextPath = context == null ? contextInfo.getPath() : context.getContextPath();
         contextDTO.errorPageDTOs = errorPageDTOs;
         contextDTO.filterDTOs = filterDTOs;
         contextDTO.initParams = contextInfo.getInitParameters();
         contextDTO.listenerDTOs = listenerDTOs;
-        contextDTO.name = context.getServletContextName();
+        contextDTO.name = contextInfo.getName();
         contextDTO.resourceDTOs = resourceDTOs;
         contextDTO.servletDTOs = servletDTOs;
         contextDTO.serviceId = contextId;
@@ -89,6 +106,11 @@
 
     private Map<String, Object> getAttributes(ServletContext context)
     {
+        if (context == null)
+        {
+            return Collections.emptyMap();
+        }
+
         Map<String, Object> attributes = new HashMap<String, Object>();
         for (String name : list(context.getAttributeNames()))
         {
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextHelperRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextHelperRuntime.java
new file mode 100644
index 0000000..b597e45
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletContextHelperRuntime.java
@@ -0,0 +1,41 @@
+/*
+ * 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.runtime.dto;
+
+import java.util.Comparator;
+
+import javax.servlet.ServletContext;
+
+import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+
+public interface ServletContextHelperRuntime
+{
+    static final Comparator<ServletContextHelperRuntime> COMPARATOR = new Comparator<ServletContextHelperRuntime>()
+    {
+        @Override
+        public int compare(ServletContextHelperRuntime o1, ServletContextHelperRuntime o2)
+        {
+            return o1.getContextInfo().compareTo(o2.getContextInfo());
+        }
+    };
+
+    ServletContext getSharedContext();
+
+    ServletContextHelperInfo getContextInfo();
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletDTOBuilder.java
index 0444837..107d683 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletDTOBuilder.java
@@ -18,19 +18,27 @@
  */
 package org.apache.felix.http.base.internal.runtime.dto;
 
-import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.osgi.service.http.runtime.dto.ServletDTO;
 
-final class ServletDTOBuilder extends BaseServletDTOBuilder<ServletHandler, ServletDTO>
+final class ServletDTOBuilder<T extends ServletDTO> extends BaseServletDTOBuilder<ServletRuntime, T>
 {
-    @Override
-    ServletDTO buildDTO(ServletHandler servletHandler, long servletContextId)
+    static ServletDTOBuilder<ServletDTO> create()
     {
-        ServletInfo info = servletHandler.getServletInfo();
+        return new ServletDTOBuilder<ServletDTO>(DTOFactories.SERVLET);
+    }
 
-        ServletDTO servletDTO = new ServletDTO();
-        setBaseFields(servletDTO, servletHandler, servletContextId);
+    ServletDTOBuilder(DTOFactory<T> dtoFactory)
+    {
+        super(dtoFactory);
+    }
+
+    @Override
+    T buildDTO(ServletRuntime servletRuntime, long servletContextId)
+    {
+        ServletInfo info = servletRuntime.getServletInfo();
+
+        T servletDTO = super.buildDTO(servletRuntime, servletContextId);
         servletDTO.patterns = copyWithDefault(checkNotEmpty(info.getPatterns()), null);
         return servletDTO;
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletRuntime.java
new file mode 100644
index 0000000..e994be3
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/ServletRuntime.java
@@ -0,0 +1,43 @@
+/*
+ * 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.runtime.dto;
+
+import java.util.Comparator;
+
+import javax.servlet.Servlet;
+
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+
+
+
+public interface ServletRuntime extends WhiteboardServiceRuntime
+{
+    static final Comparator<ServletRuntime> COMPARATOR = new Comparator<ServletRuntime>()
+    {
+        @Override
+        public int compare(ServletRuntime o1, ServletRuntime o2)
+        {
+            return o1.getServletInfo().compareTo(o2.getServletInfo());
+        }
+    };
+
+    Servlet getServlet();
+
+    ServletInfo getServletInfo();
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/WhiteboardServiceRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/WhiteboardServiceRuntime.java
new file mode 100644
index 0000000..3fb16d5
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/WhiteboardServiceRuntime.java
@@ -0,0 +1,26 @@
+/*
+ * 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.runtime.dto;
+
+
+
+interface WhiteboardServiceRuntime
+{
+    long getContextServiceId();
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
index 096ae72..83262cc 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
@@ -22,7 +22,7 @@
 import java.util.Hashtable;
 
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
-import org.apache.felix.http.base.internal.runtime.RegistryRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.RegistryRuntime;
 import org.apache.felix.http.base.internal.runtime.dto.RuntimeDTOBuilder;
 import org.apache.felix.http.base.internal.whiteboard.ServletContextHelperManager;
 import org.osgi.service.http.runtime.HttpServiceRuntime;
@@ -36,7 +36,6 @@
     private final HandlerRegistry registry;
     private final ServletContextHelperManager contextManager;
 
-
     public HttpServiceRuntimeImpl(HandlerRegistry registry,
             ServletContextHelperManager contextManager)
     {
@@ -54,7 +53,6 @@
     @Override
     public RequestInfoDTO calculateRequestInfoDTO(String path)
     {
-        // TODO Auto-generated method stub
         return null;
     }
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
index fc20fe8..9f58a64 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
@@ -31,6 +31,7 @@
 import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.whiteboard.RegistrationFailureException;
 import org.osgi.service.http.NamespaceException;
 
 public final class SharedHttpServiceImpl
@@ -103,7 +104,15 @@
             {
                 throw new IllegalArgumentException("Nothing registered at " + alias);
             }
-            return this.handlerRegistry.removeServlet(handler.getServletInfo(), true);
+
+            try
+            {
+                return this.handlerRegistry.removeServlet(handler.getServletInfo(), true);
+            } catch (RegistrationFailureException e)
+            {
+                // TODO create FailureDTO
+                return null;
+            }
         }
     }
 
@@ -111,7 +120,14 @@
     {
         if (servlet != null)
         {
-            this.handlerRegistry.removeServlet(servlet, destroy);
+            try
+            {
+                this.handlerRegistry.removeServlet(servlet, destroy);
+            } catch (RegistrationFailureException e)
+            {
+                // TODO create FailureDTO
+            }
+
             synchronized (this.aliasMap)
             {
                 final Iterator<Map.Entry<String, ServletHandler>> i = this.aliasMap.entrySet().iterator();
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/util/CollectionUtils.java b/http/base/src/main/java/org/apache/felix/http/base/internal/util/CollectionUtils.java
index 2f3b45f..0a2d00a 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/util/CollectionUtils.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/util/CollectionUtils.java
@@ -17,13 +17,19 @@
 package org.apache.felix.http.base.internal.util;
 
 import java.util.Collection;
-import java.util.Set;
+import java.util.Comparator;
+import java.util.SortedSet;
 import java.util.TreeSet;
 
 public class CollectionUtils {
-	public static <T extends Comparable<?>> Set<T> union(Collection<? extends T>... collections)
+    public static <T extends Comparable<?>> SortedSet<T> sortedUnion(Collection<? extends T>... collections)
     {
-        Set<T> union = new TreeSet<T>();
+        return sortedUnion(null, collections);
+    }
+
+    public static <T> SortedSet<T> sortedUnion(Comparator<T> comparator, Collection<? extends T>... collections)
+    {
+        SortedSet<T> union = comparator == null ? new TreeSet<T>() : new TreeSet<T>(comparator);
         for (Collection<? extends T> collection : collections)
         {
             union.addAll(collection);
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
index 31a286a..16dd573 100644
--- 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
@@ -24,11 +24,12 @@
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+import org.apache.felix.http.base.internal.runtime.dto.ServletContextHelperRuntime;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.ServiceObjects;
 import org.osgi.service.http.context.ServletContextHelper;
 
-public final class ContextHandler implements Comparable<ContextHandler>
+public final class ContextHandler implements Comparable<ContextHandler>, ServletContextHelperRuntime
 {
     /** The info object for the context. */
     private final ServletContextHelperInfo info;
@@ -59,6 +60,7 @@
                 eventListener);
     }
 
+    @Override
     public ServletContextHelperInfo getContextInfo()
     {
         return this.info;
@@ -80,6 +82,7 @@
         this.ungetServletContext(bundle);
     }
 
+    @Override
     public ServletContext getSharedContext()
     {
         return sharedContext;
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ListenerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ListenerRegistry.java
index 43d26c2..979423a 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ListenerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ListenerRegistry.java
@@ -23,9 +23,13 @@
 
 import javax.annotation.Nonnull;
 
-import org.apache.felix.http.base.internal.runtime.ListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestListenerInfo;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.ServiceReference;
 
@@ -40,40 +44,6 @@
         this.bundle = bundle;
     }
 
-    public void initialized(@Nonnull final ServletContextListenerInfo listenerInfo,
-            ContextHandler contextHandler)
-    {
-        registriesByContext.get(contextHandler.getContextInfo()).initialized(listenerInfo, contextHandler);
-    }
-
-    public void destroyed(@Nonnull final ServletContextListenerInfo listenerInfo,
-            ContextHandler contextHandler)
-    {
-        registriesByContext.get(contextHandler.getContextInfo()).destroyed(listenerInfo, contextHandler);
-    }
-
-    public <T extends ListenerInfo<?>> void addListener(@Nonnull final T info,
-            final ContextHandler contextHandler)
-    {
-        getRegistryForContext(contextHandler).addListener(info);
-    }
-
-    public <T extends ListenerInfo<?>> void removeListener(@Nonnull final T info,
-           final ContextHandler contextHandler)
-    {
-        getRegistryForContext(contextHandler).removeListener(info);
-    }
-
-    private PerContextEventListener getRegistryForContext(ContextHandler contextHandler)
-    {
-        PerContextEventListener contextRegistry = registriesByContext.get(contextHandler.getContextInfo());
-        if (contextRegistry == null)
-        {
-            throw new IllegalArgumentException("ContextHandler " + contextHandler.getContextInfo().getName() + " is not registered");
-        }
-        return contextRegistry;
-    }
-
     public PerContextEventListener addContext(ServletContextHelperInfo info)
     {
         if (registriesByContext.containsKey(info))
@@ -91,12 +61,95 @@
         registriesByContext.remove(info);
     }
 
+    public void initialized(@Nonnull final ServletContextListenerInfo listenerInfo,
+            ContextHandler contextHandler)
+    {
+        registriesByContext.get(contextHandler.getContextInfo()).initialized(listenerInfo, contextHandler);
+    }
+
+    public void destroyed(@Nonnull final ServletContextListenerInfo listenerInfo,
+            ContextHandler contextHandler)
+    {
+        registriesByContext.get(contextHandler.getContextInfo()).destroyed(listenerInfo, contextHandler);
+    }
+
+    void addListener(@Nonnull final ServletContextAttributeListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).addListener(info);
+    }
+
+    void removeListener(@Nonnull final ServletContextAttributeListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).removeListener(info);
+    }
+
+    void addListener(@Nonnull final HttpSessionAttributeListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).addListener(info);
+    }
+
+    void removeListener(@Nonnull final HttpSessionAttributeListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).removeListener(info);
+    }
+
+    void addListener(@Nonnull final HttpSessionListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).addListener(info);
+    }
+
+    void removeListener(@Nonnull final HttpSessionListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).removeListener(info);
+    }
+
+    void addListener(@Nonnull final ServletRequestListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).addListener(info);
+    }
+
+    void removeListener(@Nonnull final ServletRequestListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).removeListener(info);
+    }
+
+    void addListener(@Nonnull final ServletRequestAttributeListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).addListener(info);
+    }
+
+    void removeListener(@Nonnull final ServletRequestAttributeListenerInfo info,
+            final ContextHandler contextHandler)
+    {
+        getRegistryForContext(contextHandler).removeListener(info);
+    }
+
+    private PerContextEventListener getRegistryForContext(ContextHandler contextHandler)
+    {
+        PerContextEventListener contextRegistry = registriesByContext.get(contextHandler.getContextInfo());
+        if (contextRegistry == null)
+        {
+            throw new IllegalArgumentException("ContextHandler " + contextHandler.getContextInfo().getName() + " is not registered");
+        }
+        return contextRegistry;
+    }
+
     public Map<Long, Collection<ServiceReference<?>>> getContextRuntimes()
     {
         Map<Long, Collection<ServiceReference<?>>> listenersByContext = new HashMap<Long, Collection<ServiceReference<?>>>();
         for (ServletContextHelperInfo contextInfo : registriesByContext.keySet())
         {
-            listenersByContext.put(contextInfo.getServiceId(), registriesByContext.get(contextInfo).getRuntime());
+            long serviceId = contextInfo.getServiceId();
+            listenersByContext.put(serviceId, registriesByContext.get(contextInfo).getRuntime());
         }
         return listenersByContext;
     }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java
index d572666..19244a3 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java
@@ -17,6 +17,7 @@
 package org.apache.felix.http.base.internal.whiteboard;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.ConcurrentSkipListMap;
 
@@ -37,7 +38,6 @@
 
 import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
-import org.apache.felix.http.base.internal.runtime.ListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletRequestAttributeListenerInfo;
@@ -262,19 +262,6 @@
         }
     }
 
-    // Make calling from ListenerRegistry easier
-    <T extends ListenerInfo<?>> void addListener(@Nonnull T info)
-    {
-        throw new UnsupportedOperationException("Listeners of type "
-                + info.getClass() + "are not supported");
-    }
-
-    <T extends ListenerInfo<?>> void removeListener(@Nonnull T info)
-    {
-        throw new UnsupportedOperationException("Listeners of type "
-                + info.getClass() + "are not supported");
-    }
-
     @Override
     public void attributeReplaced(final HttpSessionBindingEvent event)
     {
@@ -404,7 +391,8 @@
     @SuppressWarnings("unchecked")
     Collection<ServiceReference<?>> getRuntime()
     {
-        return CollectionUtils.<ServiceReference<?>> union(
+        return CollectionUtils.<ServiceReference<?>>sortedUnion(
+                Collections.<ServiceReference<?>>reverseOrder(),
                 contextListeners.keySet(),
                 contextAttributeListeners.keySet(),
                 sessionAttributeListeners.keySet(),
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/RegistrationFailureException.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/RegistrationFailureException.java
new file mode 100644
index 0000000..46a60e8
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/RegistrationFailureException.java
@@ -0,0 +1,59 @@
+/*
+ * 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 javax.servlet.ServletException;
+
+import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
+
+@SuppressWarnings("serial")
+public class RegistrationFailureException extends ServletException
+{
+    private final WhiteboardServiceInfo<?> info;
+    private final int errorCode;
+
+    public RegistrationFailureException(WhiteboardServiceInfo<?> info, int errorCode)
+    {
+        super();
+        this.info = info;
+        this.errorCode = errorCode;
+    }
+
+    public RegistrationFailureException(WhiteboardServiceInfo<?> info, int errorCode, String message)
+    {
+        super(message);
+        this.info = info;
+        this.errorCode = errorCode;
+    }
+
+    public RegistrationFailureException(WhiteboardServiceInfo<?> info, int errorCode, Throwable exception)
+    {
+        super(exception);
+        this.info = info;
+        this.errorCode = errorCode;
+    }
+
+    public WhiteboardServiceInfo<?> getInfo()
+    {
+        return info;
+    }
+
+    public int getErrorCode()
+    {
+        return errorCode;
+    }
+}
\ No newline at end of file
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
index 6ef65dc..84da0b9 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletContextHelperManager.java
@@ -16,6 +16,11 @@
  */
 package org.apache.felix.http.base.internal.whiteboard;
 
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_UNKNOWN;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_VALIDATION_FAILED;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -25,10 +30,9 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
-import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.ConcurrentSkipListMap;
 
 import javax.annotation.Nonnull;
 import javax.servlet.ServletContext;
@@ -38,14 +42,20 @@
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.AbstractInfo;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime;
-import org.apache.felix.http.base.internal.runtime.ListenerInfo;
-import org.apache.felix.http.base.internal.runtime.RegistryRuntime;
+import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ResourceInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestListenerInfo;
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
+import org.apache.felix.http.base.internal.runtime.dto.ContextRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.FailureRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.RegistryRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.ServletContextHelperRuntime;
 import org.apache.felix.http.base.internal.util.MimeTypes;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -73,7 +83,7 @@
 
     private final BundleContext bundleContext;
 
-    private final Set<AbstractInfo<?>> invalidRegistrations = new ConcurrentSkipListSet<AbstractInfo<?>>();
+    private final Map<AbstractInfo<?>, Integer> serviceFailures = new ConcurrentSkipListMap<AbstractInfo<?>, Integer>();
 
     private volatile ServletContext webContext;
 
@@ -176,6 +186,7 @@
                 {
                     services.add(entry.getKey());
                 }
+                removeFailure(entry.getKey(), FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
             }
         }
         // context listeners first
@@ -222,7 +233,6 @@
         handler.deactivate();
 
         this.httpService.unregisterContext(handler);
-
     }
 
     /**
@@ -257,17 +267,24 @@
                         // check for deactivate
                         if ( handlerList.size() > 1 )
                         {
-                            this.deactivate(handlerList.get(1));
+                            ContextHandler oldHead = handlerList.get(1);
+                            this.deactivate(oldHead);
+                            this.serviceFailures.put(oldHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
                         }
+                        removeFailure(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
                         this.activate(handler);
                     }
+                    else
+                    {
+                        this.serviceFailures.put(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                    }
                 }
             }
             else
             {
                 final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
                 SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
-                this.invalidRegistrations.add(info);
+                this.serviceFailures.put(info, FAILURE_REASON_VALIDATION_FAILED);
             }
         }
     }
@@ -312,16 +329,15 @@
                         }
                         else if ( activateNext )
                         {
-                            this.activate(handlerList.get(0));
+                            ContextHandler newHead = handlerList.get(0);
+                            this.activate(newHead);
+                            removeFailure(newHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
                         }
                         listenerRegistry.removeContext(info);
                     }
                 }
             }
-            else
-            {
-                this.invalidRegistrations.remove(info);
-            }
+            this.serviceFailures.remove(info);
         }
     }
 
@@ -360,13 +376,17 @@
                     {
                         this.registerWhiteboardService(h, info);
                     }
+                    if (handlerList.isEmpty())
+                    {
+                        this.serviceFailures.put(info, FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
+                    }
                 }
             }
             else
             {
                 final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
                 SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
-                this.invalidRegistrations.add(info);
+                this.serviceFailures.put(info, FAILURE_REASON_VALIDATION_FAILED);
             }
         }
     }
@@ -393,10 +413,7 @@
                     }
                 }
             }
-            else
-            {
-                this.invalidRegistrations.remove(info);
-            }
+            this.serviceFailures.remove(info);
         }
     }
 
@@ -407,21 +424,51 @@
      */
     private void registerWhiteboardService(final ContextHandler handler, final WhiteboardServiceInfo<?> info)
     {
-        if ( info instanceof ServletInfo )
+        try
         {
-            this.httpService.registerServlet(handler, (ServletInfo)info);
+            if ( info instanceof ServletInfo )
+            {
+                this.httpService.registerServlet(handler, (ServletInfo)info);
+            }
+            else if ( info instanceof FilterInfo )
+            {
+                this.httpService.registerFilter(handler, (FilterInfo)info);
+            }
+            else if ( info instanceof ResourceInfo )
+            {
+                this.httpService.registerResource(handler, (ResourceInfo)info);
+            }
+
+            else if ( info instanceof ServletContextAttributeListenerInfo )
+            {
+                this.listenerRegistry.addListener((ServletContextAttributeListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionListenerInfo )
+            {
+                this.listenerRegistry.addListener((HttpSessionListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionAttributeListenerInfo )
+            {
+                this.listenerRegistry.addListener((HttpSessionAttributeListenerInfo) info, handler);
+            }
+            else if ( info instanceof ServletRequestListenerInfo )
+            {
+                this.listenerRegistry.addListener((ServletRequestListenerInfo) info, handler);
+            }
+            else if ( info instanceof ServletRequestAttributeListenerInfo )
+            {
+                this.listenerRegistry.addListener((ServletRequestAttributeListenerInfo) info, handler);
+            }
         }
-        else if ( info instanceof FilterInfo )
+        catch (RegistrationFailureException e)
         {
-            this.httpService.registerFilter(handler, (FilterInfo)info);
+            serviceFailures.put(e.getInfo(), e.getErrorCode());
+            SystemLogger.error("Exception while adding servlet", e);
         }
-        else if ( info instanceof ResourceInfo )
+        catch (RuntimeException e)
         {
-            this.httpService.registerResource(handler, (ResourceInfo)info);
-        }
-        else if ( info instanceof ListenerInfo )
-        {
-            this.listenerRegistry.addListener((ListenerInfo<?>)info, handler);
+            serviceFailures.put(info, FAILURE_REASON_UNKNOWN);
+            throw e;
         }
     }
 
@@ -432,21 +479,56 @@
      */
     private void unregisterWhiteboardService(final ContextHandler handler, final WhiteboardServiceInfo<?> info)
     {
-        if ( info instanceof ServletInfo )
+        try
         {
-            this.httpService.unregisterServlet(handler, (ServletInfo)info);
+            if ( info instanceof ServletInfo )
+            {
+                this.httpService.unregisterServlet(handler, (ServletInfo)info);
+            }
+            else if ( info instanceof FilterInfo )
+            {
+                this.httpService.unregisterFilter(handler, (FilterInfo)info);
+            }
+            else if ( info instanceof ResourceInfo )
+            {
+                this.httpService.unregisterResource(handler, (ResourceInfo)info);
+            }
+
+            else if ( info instanceof ServletContextAttributeListenerInfo )
+            {
+                this.listenerRegistry.removeListener((ServletContextAttributeListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionListenerInfo )
+            {
+                this.listenerRegistry.removeListener((HttpSessionListenerInfo) info, handler);
+            }
+            else if ( info instanceof HttpSessionAttributeListenerInfo )
+            {
+                this.listenerRegistry.removeListener((HttpSessionAttributeListenerInfo) info, handler);
+            }
+            else if ( info instanceof ServletRequestListenerInfo )
+            {
+                this.listenerRegistry.removeListener((ServletRequestListenerInfo) info, handler);
+            }
+            else if ( info instanceof ServletRequestAttributeListenerInfo )
+            {
+                this.listenerRegistry.removeListener((ServletRequestAttributeListenerInfo) info, handler);
+            }
         }
-        else if ( info instanceof FilterInfo )
+        catch (RegistrationFailureException e)
         {
-            this.httpService.unregisterFilter(handler, (FilterInfo)info);
+            serviceFailures.put(e.getInfo(), e.getErrorCode());
+            SystemLogger.error("Exception while removing servlet", e);
         }
-        else if ( info instanceof ResourceInfo )
+        serviceFailures.remove(info);
+    }
+
+    private void removeFailure(AbstractInfo<?> info, int failureCode)
+    {
+        Integer registeredFailureCode = this.serviceFailures.get(info);
+        if (registeredFailureCode != null && registeredFailureCode == failureCode)
         {
-            this.httpService.unregisterResource(handler, (ResourceInfo)info);
-        }
-        else if ( info instanceof ListenerInfo )
-        {
-            this.listenerRegistry.removeListener((ListenerInfo<?>)info, handler);
+            this.serviceFailures.remove(info);
         }
     }
 
@@ -506,21 +588,23 @@
 
     public RegistryRuntime getRuntime(HandlerRegistry registry)
     {
-        List<HandlerRuntime> handlerRuntimes;
+        Collection<ServletContextHelperRuntime> contextRuntimes = new TreeSet<ServletContextHelperRuntime>(ServletContextHelperRuntime.COMPARATOR);
+        List<ContextRuntime> handlerRuntimes;
         Map<Long, Collection<ServiceReference<?>>> listenerRuntimes;
-        Set<ContextHandler> contextHandlers = new TreeSet<ContextHandler>();
+        FailureRuntime.Builder failureRuntime = FailureRuntime.builder();
         synchronized ( this.contextMap )
         {
             for (List<ContextHandler> contextHandlerList : this.contextMap.values())
             {
                 if ( !contextHandlerList.isEmpty() )
                 {
-                    contextHandlers.add(contextHandlerList.get(0));
+                    contextRuntimes.add(contextHandlerList.get(0));
                 }
             }
-            handlerRuntimes = registry.getRuntime();
+            handlerRuntimes = registry.getRuntime(failureRuntime);
             listenerRuntimes = listenerRegistry.getContextRuntimes();
+            failureRuntime.add(serviceFailures);
         }
-        return new RegistryRuntime(contextHandlers, handlerRuntimes, listenerRuntimes, this.invalidRegistrations);
+        return new RegistryRuntime(contextRuntimes, handlerRuntimes, listenerRuntimes, failureRuntime.build());
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
index 10a6d40..f31a463 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
@@ -16,9 +16,11 @@
  */
 package org.apache.felix.http.base.internal.whiteboard;
 
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+
 import javax.annotation.Nonnull;
 import javax.servlet.Filter;
-import javax.servlet.Servlet;
 import javax.servlet.ServletException;
 
 import org.apache.felix.http.base.internal.handler.FilterHandler;
@@ -27,9 +29,9 @@
 import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.ResourceInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceObjects;
 
 public final class WhiteboardHttpService
 {
@@ -53,33 +55,47 @@
      * Register a servlet.
      * @param contextInfo The servlet context helper info
      * @param servletInfo The servlet info
+     * @throws RegistrationFailureException 
      */
     public void registerServlet(@Nonnull final ContextHandler contextHandler,
             @Nonnull final ServletInfo servletInfo)
+            throws RegistrationFailureException
     {
-    	final PerContextHandlerRegistry registry = this.handlerRegistry.getRegistry(contextHandler.getContextInfo());
-    	if (registry != null)
-    	{
-    		try {
-    			ServletHandler handler = new ServletHandler(contextHandler.getContextInfo(), 
-    					contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()), 
-    					servletInfo, 
-    					null, 
-    					true);
-    			
-    			registry.addServlet(handler);
-			} catch (ServletException e) {
-				// TODO create failure DTO
-			}
-    	}
+        ServletContextHelperInfo contextInfo = contextHandler.getContextInfo();
+        final PerContextHandlerRegistry registry = this.handlerRegistry.getRegistry(contextInfo);
+        if (registry != null)
+        {
+            try
+            {
+                ServletHandler handler = new ServletHandler(contextHandler.getContextInfo(),
+                        contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
+                        servletInfo,
+                        null,
+                        true);
+
+                registry.addServlet(handler);
+            }
+            catch (final RegistrationFailureException e)
+            {
+                throw e;
+            }
+            catch (final ServletException e)
+            {
+                throw new RegistrationFailureException(servletInfo, FAILURE_REASON_EXCEPTION_ON_INIT, e);
+            }
+        } else
+        {
+            throw new RegistrationFailureException(servletInfo, FAILURE_REASON_SERVICE_NOT_GETTABLE);
+        }
     }
 
     /**
      * Unregister a servlet
      * @param contextInfo The servlet context helper info
      * @param servletInfo The servlet info
+     * @throws RegistrationFailureException 
      */
-    public void unregisterServlet(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletInfo servletInfo)
+    public void unregisterServlet(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletInfo servletInfo) throws RegistrationFailureException
     {
         final PerContextHandlerRegistry registry = this.handlerRegistry.getRegistry(contextHandler.getContextInfo());
         if (registry != null )
@@ -93,12 +109,12 @@
      * Register a filter
      * @param contextInfo The servlet context helper info
      * @param filterInfo The filter info
+     * @throws RegistrationFailureException 
      */
     public void registerFilter(@Nonnull  final ContextHandler contextHandler,
-            @Nonnull final FilterInfo filterInfo)
+            @Nonnull final FilterInfo filterInfo) throws RegistrationFailureException
     {
         final Filter filter = this.bundleContext.getServiceObjects(filterInfo.getServiceReference()).getService();
-        // TODO create failure DTO if null
         if ( filter != null )
         {
             final FilterHandler handler = new FilterHandler(contextHandler.getContextInfo(),
@@ -111,9 +127,19 @@
                 {
                     registry.addFilter(handler);
                 }
-            } catch (final ServletException e) {
-                // TODO create failure DTO
             }
+            catch (final RegistrationFailureException e)
+            {
+                throw e;
+            }
+            catch (final ServletException e)
+            {
+                throw new RegistrationFailureException(filterInfo, FAILURE_REASON_EXCEPTION_ON_INIT, e);
+            }
+        }
+        else
+        {
+            throw new RegistrationFailureException(filterInfo, FAILURE_REASON_SERVICE_NOT_GETTABLE);
         }
     }
 
@@ -140,9 +166,10 @@
      * Register a resource.
      * @param contextInfo The servlet context helper info
      * @param resourceInfo The resource info
+     * @throws RegistrationFailureException 
      */
     public void registerResource(@Nonnull final ContextHandler contextHandler,
-            @Nonnull final ResourceInfo resourceInfo)
+            @Nonnull final ResourceInfo resourceInfo) throws RegistrationFailureException
     {
     	final ServletInfo servletInfo = new ServletInfo(resourceInfo);
     	
@@ -159,7 +186,7 @@
     				registry.addServlet(handler);
     		}
     	} catch (ServletException e) {
-    		// TODO create failure DTO
+            throw new RegistrationFailureException(resourceInfo, FAILURE_REASON_EXCEPTION_ON_INIT, e);
     	}
     }
 
@@ -167,8 +194,9 @@
      * Unregister a resource.
      * @param contextInfo The servlet context helper info
      * @param resourceInfo The resource info
+     * @throws RegistrationFailureException 
      */
-    public void unregisterResource(@Nonnull final ContextHandler contextHandler, @Nonnull final ResourceInfo resourceInfo)
+    public void unregisterResource(@Nonnull final ContextHandler contextHandler, @Nonnull final ResourceInfo resourceInfo) throws RegistrationFailureException
     {
         final ServletInfo servletInfo = new ServletInfo(resourceInfo);
         final PerContextHandlerRegistry registry = this.handlerRegistry.getRegistry(contextHandler.getContextInfo());
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java
index 624d2d3..00096af 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/FilterHandlerTest.java
@@ -19,7 +19,7 @@
 import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
 import static javax.servlet.http.HttpServletResponse.SC_OK;
 import static javax.servlet.http.HttpServletResponse.SC_PAYMENT_REQUIRED;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -59,14 +59,14 @@
         FilterHandler h2 = createHandler(10, "b");
         FilterHandler h3 = createHandler(10, "c");
 
-        assertEquals(0, h1.compareTo(h1));
+        assertTrue(h1.compareTo(h1) == 0);
 
-        assertEquals(1, h1.compareTo(h2));
-        assertEquals(-1, h2.compareTo(h1));
+        assertTrue(h1.compareTo(h2) > 0);
+        assertTrue(h2.compareTo(h1) < 0);
 
         // h2 is actually registered first, so should be called first...
-        assertEquals(-1, h2.compareTo(h3));
-        assertEquals(1, h3.compareTo(h2));
+        assertTrue(h2.compareTo(h3) < 0);
+        assertTrue(h3.compareTo(h2) > 0);
     }
 
     @Test
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistryTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistryTest.java
index 9dfdc84..a2d767c 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistryTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistryTest.java
@@ -17,6 +17,7 @@
 package org.apache.felix.http.base.internal.handler;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -32,7 +33,8 @@
 public class PerContextHandlerRegistryTest
 {
 
-    @Test public void testPathOrdering()
+    @Test
+    public void testPathOrdering()
     {
         final List<PerContextHandlerRegistry> list = new ArrayList<PerContextHandlerRegistry>();
         list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/", 1L, 0), null));
@@ -48,7 +50,8 @@
         assertEquals(3L, list.get(3).getContextServiceId());
     }
 
-    @Test public void testRankingOrdering()
+    @Test
+    public void testRankingOrdering()
     {
         final List<PerContextHandlerRegistry> list = new ArrayList<PerContextHandlerRegistry>();
         list.add(new PerContextHandlerRegistry(createServletContextHelperInfo("/", 1L, 0), null));
@@ -64,7 +67,8 @@
         assertEquals(3L, list.get(3).getContextServiceId());
     }
 
-    @Test public void testOrderingSymetry()
+    @Test
+    public void testOrderingSymetry()
     {
         testSymetry("/", "/foo", 1L, 2L, 0, 0);
         testSymetry("/", "/", 1L, 2L, 0, 10);
@@ -83,7 +87,8 @@
         assertEquals(handlerRegistry.compareTo(other), -other.compareTo(handlerRegistry));
     }
 
-    @Test public void testOrderingTransitivity()
+    @Test
+    public void testOrderingTransitivity()
     {
         testTransitivity("/", "/foo", "/barrr", 1L, 2L, 3L, 0, 0, 0);
         testTransitivity("/", "/", "/", 0L, 1L, 2L, 1, 2, 3);
@@ -92,22 +97,18 @@
         testTransitivity("/", "/", "/", -2L, -1L, 0L, 0, 0, 0);
     }
 
-    private void testTransitivity(String highPath, String midPath, String lowPath,
-            long highId, long midId, long lowId,
-            int highRanking, int midRanking, int lowRanking)
+    private void testTransitivity(String highPath, String midPath, String lowPath, long highId, long midId, long lowId, int highRanking, int midRanking, int lowRanking)
     {
         PerContextHandlerRegistry high = new PerContextHandlerRegistry(createServletContextHelperInfo(highPath, highId, highRanking), null);
         PerContextHandlerRegistry mid = new PerContextHandlerRegistry(createServletContextHelperInfo(midPath, midId, midRanking), null);
         PerContextHandlerRegistry low = new PerContextHandlerRegistry(createServletContextHelperInfo(lowPath, lowId, lowRanking), null);
 
-        assertEquals(1, high.compareTo(mid));
-        assertEquals(1, mid.compareTo(low));
-        assertEquals(1, high.compareTo(low));
+        assertTrue(high.compareTo(mid) > 0);
+        assertTrue(mid.compareTo(low) > 0);
+        assertTrue(high.compareTo(low) > 0);
     }
 
-    private ServletContextHelperInfo createServletContextHelperInfo(final String path,
-            final long serviceId,
-            final int ranking)
+    private ServletContextHelperInfo createServletContextHelperInfo(final String path, final long serviceId, final int ranking)
     {
         return WhiteboardServiceHelper.createContextInfo(ranking, serviceId, "", path, null);
     }
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/WhiteboardServiceHelper.java b/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/WhiteboardServiceHelper.java
index 2108ee4..8e01e05 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/WhiteboardServiceHelper.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/WhiteboardServiceHelper.java
@@ -34,25 +34,28 @@
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.ServletHandler;
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime.ErrorPage;
+import org.apache.felix.http.base.internal.runtime.dto.ErrorPageRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.FilterRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.ServletRuntime;
+import org.osgi.framework.ServiceReference;
 
 public final class WhiteboardServiceHelper
 {
     public static final AtomicLong ID_COUNTER = new AtomicLong();
 
-    public static FilterHandler createTestFilterWithServiceId(String identifier,
+    public static FilterRuntime createTestFilterWithServiceId(String identifier,
             ExtServletContext context)
     {
         return createTestFilter(identifier, context, ID_COUNTER.incrementAndGet());
     }
 
-    public static FilterHandler createTestFilter(String identifier,
+    public static FilterRuntime createTestFilter(String identifier,
             ExtServletContext context)
     {
         return createTestFilter(identifier, context, -ID_COUNTER.incrementAndGet());
     }
 
-    private static FilterHandler createTestFilter(String identifier,
+    private static FilterRuntime createTestFilter(String identifier,
             ExtServletContext context,
             Long serviceId)
     {
@@ -94,18 +97,18 @@
         return info;
     }
 
-    public static ServletHandler createTestServletWithServiceId(String identifier,
+    public static ServletRuntime createTestServletWithServiceId(String identifier,
             ExtServletContext context)
     {
         return createTestServlet(identifier, context, ID_COUNTER.incrementAndGet());
     }
 
-    public static ServletHandler createTestServlet(String identifier, ExtServletContext context)
+    public static ServletRuntime createTestServlet(String identifier, ExtServletContext context)
     {
         return createTestServlet(identifier, context, -ID_COUNTER.incrementAndGet());
     }
 
-    private static ServletHandler createTestServlet(String identifier,
+    private static ServletRuntime createTestServlet(String identifier,
             ExtServletContext context,
             Long serviceId)
     {
@@ -136,7 +139,7 @@
                 serviceId,
                 name,
                 patterns,
-                null,
+                errorPages,
                 asyncSupported,
                 initParams);
     }
@@ -153,25 +156,25 @@
                 };
     }
 
-    public static ErrorPage createErrorPageWithServiceId(String identifier, ExtServletContext context)
+    public static ErrorPageRuntime createErrorPageWithServiceId(String identifier, ExtServletContext context)
     {
         return createErrorPage(identifier, context, ID_COUNTER.incrementAndGet());
     }
 
-    public static ErrorPage createErrorPage(String identifier, ExtServletContext context)
+    public static ErrorPageRuntime createErrorPage(String identifier, ExtServletContext context)
     {
         return createErrorPage(identifier, context, -ID_COUNTER.incrementAndGet());
     }
 
-    private static ErrorPage createErrorPage(String identifier,
+    private static ErrorPageRuntime createErrorPage(String identifier,
             ExtServletContext context,
             Long serviceId)
     {
-        ServletHandler servletHandler = createTestServlet(identifier, context, serviceId);
+        ServletRuntime servletHandler = createTestServlet(identifier, context, serviceId);
         Collection<Integer> errorCodes = Arrays.asList(400, 500);
         Collection<String> exceptions = Arrays.asList("Bad request", "Error");
 
-        return new ErrorPage(servletHandler, errorCodes, exceptions);
+        return new ErrorPageRuntime(servletHandler, errorCodes, exceptions);
     }
 
     public static ServletContextHelperInfo createContextInfo(int serviceRanking,
@@ -186,4 +189,9 @@
                 path,
                 initParams);
     }
+
+    public static ResourceInfo createContextInfo(ServiceReference<Object> ref)
+    {
+        return new ResourceInfo(ref);
+    }
 }
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilderTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilderTest.java
index d495076..4d1a59d 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilderTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/runtime/dto/RuntimeDTOBuilderTest.java
@@ -58,10 +58,8 @@
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.ServletHandler;
+import org.apache.felix.http.base.internal.runtime.AbstractInfo;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime;
-import org.apache.felix.http.base.internal.runtime.HandlerRuntime.ErrorPage;
-import org.apache.felix.http.base.internal.runtime.RegistryRuntime;
 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.whiteboard.ContextHandler;
@@ -85,6 +83,7 @@
 import org.osgi.service.http.runtime.dto.RuntimeDTO;
 import org.osgi.service.http.runtime.dto.ServletContextDTO;
 import org.osgi.service.http.runtime.dto.ServletDTO;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
 @RunWith(MockitoJUnitRunner.class)
 public class RuntimeDTOBuilderTest
@@ -95,6 +94,8 @@
     private static final Long ID_0 = -ID_COUNTER.incrementAndGet();
     private static final Long ID_A = ID_COUNTER.incrementAndGet();
     private static final Long ID_B = ID_COUNTER.incrementAndGet();
+    private static final Long ID_C = ID_COUNTER.incrementAndGet();
+    private static final Long ID_D = ID_COUNTER.incrementAndGet();
 
     private static final Long ID_LISTENER_1 = ID_COUNTER.incrementAndGet();
     private static final Long ID_LISTENER_2 = ID_COUNTER.incrementAndGet();
@@ -111,6 +112,15 @@
                 }
             };
 
+    @SuppressWarnings("serial")
+    private static final Map<String, Object> RUNTIME_ATTRIBUTES = new HashMap<String, Object>()
+    {
+        {
+            put("attr_1", "val_1");
+            put("attr_2", "val_2");
+        }
+    };
+
     @Mock private Bundle bundle;
 
     @Mock private DTO testDTO;
@@ -118,10 +128,14 @@
     @Mock private ExtServletContext context_0;
     @Mock private ExtServletContext context_A;
     @Mock private ExtServletContext context_B;
+    @Mock private ExtServletContext context_C;
+    @Mock private ExtServletContext context_D;
 
     @Mock private ServiceReference<?> listener_1;
     @Mock private ServiceReference<?> listener_2;
 
+    @Mock private ServiceReference<Object> resource;
+
     private RegistryRuntime registry;
     private Map<String, Object> runtimeAttributes;
 	private ListenerRegistry listenerRegistry;
@@ -130,11 +144,11 @@
     public void setUp()
     {
         registry = null;
-        runtimeAttributes = Collections.emptyMap();
+        runtimeAttributes = RUNTIME_ATTRIBUTES;
         listenerRegistry = new ListenerRegistry(bundle);
     }
 
-	public ContextHandler setupContext(ServletContext context, String name, long serviceId)
+    public ServletContextHelperRuntime setupContext(ServletContext context, String name, long serviceId)
     {
         when(context.getServletContextName()).thenReturn(name);
 
@@ -146,13 +160,11 @@
         when(context.getInitParameter("param_1")).thenReturn("init_val_1");
         when(context.getInitParameter("param_2")).thenReturn("init_val_2");
 
-        Map<String, String> initParemters = new HashMap<String, String>();
-        initParemters.put("param_1", "init_val_1");
-        initParemters.put("param_2", "init_val_2");
-        ServletContextHelperInfo contextInfo = createContextInfo(0, serviceId, name, path, initParemters);
+        Map<String, String> initParameters = createInitParameterMap();
+        ServletContextHelperInfo contextInfo = createContextInfo(0, serviceId, name, path, initParameters);
 
         PerContextEventListener eventListener = listenerRegistry.addContext(contextInfo);
-        ContextHandler contextHandler = new ContextHandler(contextInfo, context, eventListener, bundle);
+        ServletContextHelperRuntime contextHandler = new ContextHandler(contextInfo, context, eventListener, bundle);
 
         ServletContext sharedContext = contextHandler.getSharedContext();
         sharedContext.setAttribute("intAttr", 1);
@@ -163,12 +175,21 @@
         return contextHandler;
     }
 
+    private Map<String, String> createInitParameterMap()
+    {
+        Map<String, String> initParameters = new HashMap<String, String>();
+        initParameters.put("param_1", "init_val_1");
+        initParameters.put("param_2", "init_val_2");
+        return initParameters;
+    }
+
     @SuppressWarnings("unchecked")
     public Map<Long, Collection<ServiceReference<?>>> setupListeners()
     {
         Map<Long, Collection<ServiceReference<?>>> listenerRuntimes = new HashMap<Long, Collection<ServiceReference<?>>>();
+
         listenerRuntimes.put(ID_0, asList(listener_1, listener_2));
-        listenerRuntimes.put(ID_A, Arrays.<ServiceReference<?>> asList(listener_1));
+        listenerRuntimes.put(ID_A, Arrays.<ServiceReference<?>>asList(listener_1));
         listenerRuntimes.put(ID_B, asList(listener_1, listener_2));
 
         when(listener_1.getProperty(Constants.SERVICE_ID)).thenReturn(ID_LISTENER_1);
@@ -182,50 +203,65 @@
         return listenerRuntimes;
     }
 
-    public void setupRegistry(List<ContextHandler> contexts,
-            List<HandlerRuntime> contextRuntimes,
-            Map<Long, Collection<ServiceReference<?>>> listenerRuntimes)
+    public void setupResource()
     {
-        registry = new RegistryRuntime(contexts, contextRuntimes, listenerRuntimes, Collections.EMPTY_SET);
+        when(resource.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN)).thenReturn(new String[] { "/" });
+        when(resource.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX)).thenReturn("prefix");
+    }
+
+    public void setupRegistry(List<ServletContextHelperRuntime> contexts,
+            List<ContextRuntime> contextRuntimes,
+            Map<Long, Collection<ServiceReference<?>>> listenerRuntimes,
+            FailureRuntime failures)
+    {
+        registry = new RegistryRuntime(contexts, contextRuntimes, listenerRuntimes, failures);
     }
 
     @Test
     public void buildRuntimeDTO()
     {
-        ContextHandler contextHelper_0 = setupContext(context_0, "0", ID_0);
-        ContextHandler contextHelper_A = setupContext(context_A, "A", ID_A);
-        ContextHandler contextHelper_B = setupContext(context_B, "B", ID_B);
+        ServletContextHelperRuntime contextHelper_0 = setupContext(context_0, "0", ID_0);
+        ServletContextHelperRuntime contextHelper_A = setupContext(context_A, "A", ID_A);
+        ServletContextHelperRuntime contextHelper_B = setupContext(context_B, "B", ID_B);
 
-        List<ServletHandler> servlets_0 = asList(createTestServlet("1", context_0));
-        List<FilterHandler> filters_0 = asList(createTestFilter("1", context_0));
-        List<ServletHandler> resources_0 = asList(createTestServlet("1", context_0));
-        List<ErrorPage> errorPages_0 = asList(createErrorPage("E_1", context_0));
-        HandlerRuntime contextRuntime_0 = new HandlerRuntime(servlets_0, filters_0, resources_0, errorPages_0, ID_0);
+        List<ServletRuntime> servlets_0 = asList(createTestServlet("1", context_0));
+        List<FilterRuntime> filters_0 = asList(createTestFilter("1", context_0));
+        List<ServletRuntime> resources_0 = asList(createTestServlet("1", context_0));
+        List<ErrorPageRuntime> errorPages_0 = asList(createErrorPage("E_1", context_0));
+        ContextRuntime contextRuntime_0 = new ContextRuntime(servlets_0, filters_0, resources_0, errorPages_0, ID_0);
 
-        List<ServletHandler> servlets_A = asList(createTestServlet("A_1", context_A));
-        List<FilterHandler> filters_A = asList(createTestFilter("A_1", context_A));
-        List<ServletHandler> resources_A = asList(createTestServlet("A_1", context_A));
-        List<ErrorPage> errorPages_A = asList(createErrorPage("E_A_1", context_A));
-        HandlerRuntime contextRuntime_A = new HandlerRuntime(servlets_A, filters_A, resources_A, errorPages_A, ID_A);
+        List<ServletRuntime> servlets_A = asList(createTestServlet("A_1", context_A));
+        List<FilterRuntime> filters_A = asList(createTestFilter("A_1", context_A));
+        List<ServletRuntime> resources_A = asList(createTestServlet("A_1", context_A));
+        List<ErrorPageRuntime> errorPages_A = asList(createErrorPage("E_A_1", context_A));
+        ContextRuntime contextRuntime_A = new ContextRuntime(servlets_A, filters_A, resources_A, errorPages_A, ID_A);
 
-        List<ServletHandler> servlets_B = asList(createTestServletWithServiceId("B_1", context_B),
+        List<ServletRuntime> servlets_B = asList(createTestServletWithServiceId("B_1", context_B),
                 createTestServletWithServiceId("B_2", context_B));
-        List<FilterHandler> filters_B = asList(createTestFilterWithServiceId("B_1", context_B),
+        List<FilterRuntime> filters_B = asList(createTestFilterWithServiceId("B_1", context_B),
                 createTestFilterWithServiceId("B_2", context_B));
-        List<ServletHandler> resources_B = asList(createTestServletWithServiceId("B_1", context_B),
+        List<ServletRuntime> resources_B = asList(createTestServletWithServiceId("B_1", context_B),
                 createTestServletWithServiceId("B_2", context_B));
-        List<ErrorPage> errorPages_B = asList(createErrorPageWithServiceId("E_B_1", context_B),
+        List<ErrorPageRuntime> errorPages_B = asList(createErrorPageWithServiceId("E_B_1", context_B),
                 createErrorPageWithServiceId("E_B_2", context_B));
-        HandlerRuntime contextRuntime_B = new HandlerRuntime(servlets_B, filters_B, resources_B, errorPages_B, ID_B);
+        ContextRuntime contextRuntime_B = new ContextRuntime(servlets_B, filters_B, resources_B, errorPages_B, ID_B);
 
         Map<Long, Collection<ServiceReference<?>>> listenerRuntimes = setupListeners();
 
         setupRegistry(asList(contextHelper_0, contextHelper_A, contextHelper_B),
                 asList(contextRuntime_0, contextRuntime_A, contextRuntime_B),
-                listenerRuntimes);
+                listenerRuntimes,
+                FailureRuntime.empty());
 
         RuntimeDTO runtimeDTO = new RuntimeDTOBuilder(registry, runtimeAttributes).build();
 
+        assertEquals(0, runtimeDTO.failedErrorPageDTOs.length);
+        assertEquals(0, runtimeDTO.failedFilterDTOs.length);
+        assertEquals(0, runtimeDTO.failedListenerDTOs.length);
+        assertEquals(0, runtimeDTO.failedResourceDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletDTOs.length);
+
         assertServletContextDTOs(runtimeDTO);
     }
 
@@ -522,7 +558,7 @@
 
     @Test
     public void nullValuesInEntities() {
-        ContextHandler contextHandler = setupContext(context_0, "0", ID_0);
+        ServletContextHelperRuntime contextHandler = setupContext(context_0, "0", ID_0);
 
         ServletInfo servletInfo = createServletInfo(0,
                 ID_COUNTER.incrementAndGet(),
@@ -532,7 +568,7 @@
                 true,
                 Collections.<String, String>emptyMap());
         Servlet servlet = mock(Servlet.class);
-        ServletHandler servletHandler = new ServletHandler(null, context_0, servletInfo, servlet);
+        ServletRuntime servletHandler = new ServletHandler(null, context_0, servletInfo, servlet);
         when(servlet.getServletInfo()).thenReturn("info_0");
 
         FilterInfo filterInfo = createFilterInfo(0,
@@ -544,7 +580,7 @@
                 true,
                 null,
                 Collections.<String, String>emptyMap());
-        FilterHandler filterHandler = new FilterHandler(null, context_0, mock(Filter.class), filterInfo);
+        FilterRuntime filterHandler = new FilterHandler(null, context_0, mock(Filter.class), filterInfo);
 
         ServletInfo resourceInfo = createServletInfo(0,
                 ID_COUNTER.incrementAndGet(),
@@ -554,15 +590,16 @@
                 true,
                 Collections.<String, String>emptyMap());
         Servlet resource = mock(Servlet.class);
-        ServletHandler resourceHandler = new ServletHandler(null, context_0, resourceInfo, resource);
+        ServletRuntime resourceHandler = new ServletHandler(null, context_0, resourceInfo, resource);
 
-        HandlerRuntime contextRuntime = new HandlerRuntime(asList(servletHandler),
+        ContextRuntime contextRuntime = new ContextRuntime(asList(servletHandler),
                 asList(filterHandler),
                 asList(resourceHandler),
-                Collections.<ErrorPage>emptyList(),
+                Collections.<ErrorPageRuntime>emptyList(),
                 ID_0);
         setupRegistry(asList(contextHandler), asList(contextRuntime),
-                Collections.<Long, Collection<ServiceReference<?>>>emptyMap());
+                Collections.<Long, Collection<ServiceReference<?>>>emptyMap(),
+                FailureRuntime.empty());
 
         RuntimeDTO runtimeDTO = new RuntimeDTOBuilder(registry, runtimeAttributes).build();
 
@@ -579,12 +616,13 @@
 
     @Test
     public void contextWithNoEntities() {
-        ContextHandler contextHandler_0 = setupContext(context_0, "0", ID_0);
-        ContextHandler contextHandler_A = setupContext(context_A, "A", ID_A);
+        ServletContextHelperRuntime contextHandler_0 = setupContext(context_0, "0", ID_0);
+        ServletContextHelperRuntime contextHandler_A = setupContext(context_A, "A", ID_A);
 
         setupRegistry(asList(contextHandler_0, contextHandler_A),
-                asList(HandlerRuntime.empty(ID_0), HandlerRuntime.empty(ID_A)),
-                Collections.<Long, Collection<ServiceReference<?>>>emptyMap());
+                asList(ContextRuntime.empty(ID_0), ContextRuntime.empty(ID_A)),
+                Collections.<Long, Collection<ServiceReference<?>>>emptyMap(),
+                FailureRuntime.empty());
 
         RuntimeDTO runtimeDTO = new RuntimeDTOBuilder(registry, runtimeAttributes).build();
 
@@ -601,7 +639,7 @@
         expectedException.expect(IllegalArgumentException.class);
         expectedException.expectMessage("patterns");
 
-        ContextHandler contextHandler = setupContext(context_0, "0", ID_0);
+        ServletContextHelperRuntime contextHandler = setupContext(context_0, "0", ID_0);
 
         ServletInfo servletInfo = createServletInfo(0,
                 ID_COUNTER.incrementAndGet(),
@@ -611,17 +649,144 @@
                 true,
                 Collections.<String, String>emptyMap());
         Servlet servlet = mock(Servlet.class);
-        ServletHandler servletHandler = new ServletHandler(null, context_0, servletInfo, servlet);
+        ServletRuntime servletHandler = new ServletHandler(null, context_0, servletInfo, servlet);
         when(servlet.getServletInfo()).thenReturn("info_0");
 
-        HandlerRuntime contextRuntime = new HandlerRuntime(asList(servletHandler),
-                Collections.<FilterHandler>emptyList(),
-                Collections.<ServletHandler>emptyList(),
-                Collections.<ErrorPage>emptyList(),
+        ContextRuntime contextRuntime = new ContextRuntime(asList(servletHandler),
+                Collections.<FilterRuntime>emptyList(),
+                Collections.<ServletRuntime>emptyList(),
+                Collections.<ErrorPageRuntime>emptyList(),
                 ID_0);
         setupRegistry(asList(contextHandler), asList(contextRuntime),
-                Collections.<Long, Collection<ServiceReference<?>>> emptyMap());
+                Collections.<Long, Collection<ServiceReference<?>>>emptyMap(),
+                FailureRuntime.empty());
 
         new RuntimeDTOBuilder(registry, runtimeAttributes).build();
     }
+
+    public FailureRuntime setupFailures()
+    {
+        Map<AbstractInfo<?>, Integer> serviceFailures = new HashMap<AbstractInfo<?>, Integer>();
+
+        ServletContextHelperInfo contextInfo = createContextInfo(0,
+                ID_C,
+                "context_failure_1",
+                "/",
+                createInitParameterMap());
+        serviceFailures.put(contextInfo, 1);
+
+        contextInfo = createContextInfo(0,
+                ID_D,
+                "context_failure_2",
+                "/",
+                createInitParameterMap());
+        serviceFailures.put(contextInfo, 2);
+
+        ServletInfo servletInfo = createServletInfo(0, ID_COUNTER.incrementAndGet(),
+                "servlet_failure_1",
+                new String[] {"/"},
+                null,
+                false,
+                createInitParameterMap());
+        serviceFailures.put(servletInfo, 3);
+
+        servletInfo = createServletInfo(0, ID_COUNTER.incrementAndGet(),
+                "servlet_failure_2",
+                new String[] {"/"},
+                null,
+                false,
+                createInitParameterMap());
+        serviceFailures.put(servletInfo, 4);
+
+        FilterInfo filterInfo = createFilterInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "filter_failure_1",
+                new String[] {"/"},
+                null,
+                null,
+                false,
+                null,
+                createInitParameterMap());
+        serviceFailures.put(filterInfo, 5);
+
+        ServletInfo errorPageInfo = createServletInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "error_failure_1",
+                null,
+                new String[] { "405", "TestException" },
+                false,
+                createInitParameterMap());
+        serviceFailures.put(errorPageInfo, 6);
+
+        ServletInfo invalidErrorPageInfo = createServletInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "error_failure_2",
+                new String[] { "/" },
+                new String[] { "405", "TestException" },
+                false,
+                createInitParameterMap());
+        serviceFailures.put(invalidErrorPageInfo, 7);
+
+        return FailureRuntime.builder().add(serviceFailures).build();
+    }
+
+    @Test
+    public void testFailureDTOs()
+    {
+        setupRegistry(Collections.<ServletContextHelperRuntime>emptyList(),
+                Collections.<ContextRuntime>emptyList(),
+                Collections.<Long, Collection<ServiceReference<?>>>emptyMap(),
+                setupFailures());
+
+        RuntimeDTO runtimeDTO = new RuntimeDTOBuilder(registry, runtimeAttributes).build();
+
+        assertEquals(0, runtimeDTO.servletContextDTOs.length);
+
+        assertEquals(2, runtimeDTO.failedErrorPageDTOs.length);
+        assertEquals(1, runtimeDTO.failedFilterDTOs.length);
+        // ListenerInfo is hard to setup
+        assertEquals(0, runtimeDTO.failedListenerDTOs.length);
+        // ResourceInfo is hard to setup
+        assertEquals(0, runtimeDTO.failedResourceDTOs.length);
+        assertEquals(2, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(2, runtimeDTO.failedServletDTOs.length);
+
+        assertEquals(1, runtimeDTO.failedServletContextDTOs[0].failureReason);
+        assertEquals(2, runtimeDTO.failedServletContextDTOs[1].failureReason);
+        assertEquals(3, runtimeDTO.failedServletDTOs[0].failureReason);
+        assertEquals(4, runtimeDTO.failedServletDTOs[1].failureReason);
+        assertEquals(5, runtimeDTO.failedFilterDTOs[0].failureReason);
+        assertEquals(6, runtimeDTO.failedErrorPageDTOs[0].failureReason);
+        assertEquals(7, runtimeDTO.failedErrorPageDTOs[1].failureReason);
+
+        assertEquals("context_failure_1", runtimeDTO.failedServletContextDTOs[0].name);
+        assertEquals("context_failure_2", runtimeDTO.failedServletContextDTOs[1].name);
+        assertEquals("servlet_failure_1", runtimeDTO.failedServletDTOs[0].name);
+        assertEquals("servlet_failure_2", runtimeDTO.failedServletDTOs[1].name);
+        assertEquals("filter_failure_1", runtimeDTO.failedFilterDTOs[0].name);
+        assertEquals("error_failure_1", runtimeDTO.failedErrorPageDTOs[0].name);
+        assertEquals("error_failure_2", runtimeDTO.failedErrorPageDTOs[1].name);
+
+        assertEquals(ID_C.longValue(), runtimeDTO.failedServletContextDTOs[0].serviceId);
+        assertEquals(ID_D.longValue(), runtimeDTO.failedServletContextDTOs[1].serviceId);
+        assertEquals(0, runtimeDTO.failedServletDTOs[0].servletContextId);
+        assertEquals(0, runtimeDTO.failedServletDTOs[1].servletContextId);
+        assertEquals(0, runtimeDTO.failedFilterDTOs[0].servletContextId);
+        assertEquals(0, runtimeDTO.failedErrorPageDTOs[0].servletContextId);
+        assertEquals(0, runtimeDTO.failedErrorPageDTOs[1].servletContextId);
+
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].errorPageDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].filterDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].listenerDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].resourceDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[0].servletDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].errorPageDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].filterDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].listenerDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].resourceDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs[1].servletDTOs.length);
+
+        assertTrue(runtimeDTO.failedServletContextDTOs[0].attributes.isEmpty());
+        assertTrue(runtimeDTO.failedServletContextDTOs[1].attributes.isEmpty());
+    }
 }
\ No newline at end of file
diff --git a/http/bundle/pom.xml b/http/bundle/pom.xml
index 8323112..e73b008 100644
--- a/http/bundle/pom.xml
+++ b/http/bundle/pom.xml
@@ -123,7 +123,7 @@
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>org.apache.felix.http.jetty</artifactId>
-            <version>3.0.1-SNAPSHOT</version>
+            <version>3.0.3-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
diff --git a/http/itest/pom.xml b/http/itest/pom.xml
index d21661c..1d80cdb 100644
--- a/http/itest/pom.xml
+++ b/http/itest/pom.xml
@@ -79,8 +79,14 @@
 		</dependency>
 		<dependency>
 			<groupId>org.mockito</groupId>
-			<artifactId>mockito-all</artifactId>
-			<version>1.8.2</version>
+			<artifactId>mockito-core</artifactId>
+			<version>1.10.19</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.objenesis</groupId>
+			<artifactId>objenesis</artifactId>
+			<version>2.1</version>
 			<scope>test</scope>
 		</dependency>
 		<dependency>
diff --git a/http/itest/src/test/java/org/apache/felix/http/itest/BaseIntegrationTest.java b/http/itest/src/test/java/org/apache/felix/http/itest/BaseIntegrationTest.java
index e2998a2..562f09a 100644
--- a/http/itest/src/test/java/org/apache/felix/http/itest/BaseIntegrationTest.java
+++ b/http/itest/src/test/java/org/apache/felix/http/itest/BaseIntegrationTest.java
@@ -173,7 +173,7 @@
         }
     }
 
-    private static final int DEFAULT_TIMEOUT = 10000;
+    protected static final int DEFAULT_TIMEOUT = 10000;
 
     protected static final String ORG_APACHE_FELIX_HTTP_JETTY = "org.apache.felix.http.jetty";
 
@@ -334,6 +334,9 @@
             mavenBundle("org.apache.felix", ORG_APACHE_FELIX_HTTP_JETTY).versionAsInProject().startLevel(START_LEVEL_SYSTEM_BUNDLES),
             mavenBundle("org.apache.felix", "org.apache.felix.configadmin").versionAsInProject().startLevel(START_LEVEL_SYSTEM_BUNDLES),
 
+            mavenBundle("org.mockito", "mockito-core").versionAsInProject().startLevel(START_LEVEL_SYSTEM_BUNDLES),
+            mavenBundle("org.objenesis", "objenesis").versionAsInProject().startLevel(START_LEVEL_SYSTEM_BUNDLES),
+
             junitBundles(), frameworkStartLevel(START_LEVEL_TEST_BUNDLE), felix());
     }
 
@@ -373,18 +376,37 @@
      */
     protected <T> T awaitService(String serviceName) throws Exception
     {
-        ServiceTracker<?, ?> tracker = null;
+        ServiceTracker<T, T> tracker = null;
+        tracker = getTracker(serviceName);
+        return tracker.waitForService(DEFAULT_TIMEOUT);
+    }
+
+    /**
+     * Return an array of {@code ServiceReference}s for all services for the
+     * given serviceName
+     * @param serviceName
+     * @return Array of {@code ServiceReference}s or {@code null} if no services
+     *         are being tracked.
+     */
+    protected <T> ServiceReference<T>[] getServiceReferences(String serviceName)
+    {
+        ServiceTracker<T, T> tracker = getTracker(serviceName);
+        return tracker.getServiceReferences();
+    }
+
+    private <T> ServiceTracker<T, T> getTracker(String serviceName)
+    {
         synchronized ( this.trackers )
         {
-            tracker = trackers.get(serviceName);
+            ServiceTracker<?, ?> tracker = trackers.get(serviceName);
             if ( tracker == null )
             {
-                tracker = new ServiceTracker(m_context, serviceName, null);
+                tracker = new ServiceTracker<T, T>(m_context, serviceName, null);
                 trackers.put(serviceName, tracker);
                 tracker.open();
             }
+            return (ServiceTracker<T, T>) tracker;
         }
-        return (T) tracker.waitForService(DEFAULT_TIMEOUT);
     }
 
     protected void configureHttpService(Dictionary<?, ?> props) throws Exception
diff --git a/http/itest/src/test/java/org/apache/felix/http/itest/EventListenerTest.java b/http/itest/src/test/java/org/apache/felix/http/itest/EventListenerTest.java
index 6fa9d37..fc8d1f9 100644
--- a/http/itest/src/test/java/org/apache/felix/http/itest/EventListenerTest.java
+++ b/http/itest/src/test/java/org/apache/felix/http/itest/EventListenerTest.java
@@ -18,8 +18,9 @@
  */
 package org.apache.felix.http.itest;
 
-import static javax.servlet.http.HttpServletResponse.*;
-import static org.junit.Assert.*;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.net.URL;
diff --git a/http/itest/src/test/java/org/apache/felix/http/itest/HttpServiceRuntimeTest.java b/http/itest/src/test/java/org/apache/felix/http/itest/HttpServiceRuntimeTest.java
new file mode 100644
index 0000000..98f20c0
--- /dev/null
+++ b/http/itest/src/test/java/org/apache/felix/http/itest/HttpServiceRuntimeTest.java
@@ -0,0 +1,1072 @@
+/*
+ * 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.itest;
+
+import static java.util.Arrays.asList;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.osgi.framework.Constants.SERVICE_ID;
+import static org.osgi.framework.Constants.SERVICE_RANKING;
+import static org.osgi.service.http.runtime.HttpServiceRuntimeConstants.HTTP_SERVICE_ENDPOINT_ATTRIBUTE;
+import static org.osgi.service.http.runtime.HttpServiceRuntimeConstants.HTTP_SERVICE_ID_ATTRIBUTE;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE;
+import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_VALIDATION_FAILED;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_NAME;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN;
+import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionListener;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.context.ServletContextHelper;
+import org.osgi.service.http.runtime.HttpServiceRuntime;
+import org.osgi.service.http.runtime.dto.FailedServletDTO;
+import org.osgi.service.http.runtime.dto.RuntimeDTO;
+import org.osgi.service.http.runtime.dto.ServletContextDTO;
+
+@RunWith(JUnit4TestRunner.class)
+public class HttpServiceRuntimeTest extends BaseIntegrationTest
+{
+    private static final long DEFAULT_SLEEP = 100;
+
+    private void registerServlet(String name, String path) throws InterruptedException
+    {
+        CountDownLatch initLatch = new CountDownLatch(1);
+        registerServlet(name, path, null, initLatch);
+        awaitServiceRegistration(initLatch);
+    }
+
+    private void registerServlet(String name, String path, CountDownLatch initLatch)
+    {
+        registerServlet(name, path, null, initLatch);
+    }
+
+    private void registerServlet(String name, String path, String context, CountDownLatch initLatch)
+    {
+        List<Object> propertyEntries = Arrays.<Object>asList(
+                HTTP_WHITEBOARD_SERVLET_PATTERN, path,
+                HTTP_WHITEBOARD_SERVLET_NAME, name,
+                HTTP_WHITEBOARD_CONTEXT_SELECT, context);
+
+        Dictionary<String, ?> properties = createDictionary(context == null ?
+                propertyEntries.subList(0, 4).toArray() : propertyEntries.toArray());
+
+        m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties);
+    }
+
+    private void registerFilter(String name, String path) throws InterruptedException
+    {
+        CountDownLatch initLatch = new CountDownLatch(1);
+        registerFilter(name, path, initLatch);
+        awaitServiceRegistration(initLatch);
+    }
+
+    private void registerFilter(String name, String path, CountDownLatch initLatch)
+    {
+        registerFilter(name, path, null, initLatch);
+    }
+
+    private void registerFilter(String name, String path, String context, CountDownLatch initLatch)
+    {
+        List<Object> propertyEntries = Arrays.<Object>asList(
+                HTTP_WHITEBOARD_FILTER_PATTERN, path,
+                HTTP_WHITEBOARD_FILTER_NAME, name,
+                HTTP_WHITEBOARD_CONTEXT_SELECT, context);
+
+        Dictionary<String, ?> properties = createDictionary(context == null ?
+                propertyEntries.subList(0, 4).toArray() : propertyEntries.toArray());
+
+        m_context.registerService(Filter.class.getName(), new TestFilter(initLatch, null), properties);
+    }
+
+    private void registerResource(String prefix, String path) throws InterruptedException
+    {
+        registerResource(prefix, path, null);
+    }
+
+    private void registerResource(String prefix, String path, String context) throws InterruptedException
+    {
+        List<Object> propertyEntries = Arrays.<Object>asList(
+                HTTP_WHITEBOARD_RESOURCE_PATTERN, path,
+                HTTP_WHITEBOARD_RESOURCE_PREFIX, prefix,
+                HTTP_WHITEBOARD_CONTEXT_SELECT, context);
+
+        Dictionary<String, ?> properties = createDictionary(context == null ?
+                propertyEntries.subList(0, 4).toArray() : propertyEntries.toArray());
+
+        m_context.registerService(TestResource.class.getName(), new TestResource(), properties);
+        awaitServiceRegistration();
+    }
+
+    private void registerErrorPage(String name, List<String> errors) throws InterruptedException
+    {
+        CountDownLatch initLatch = new CountDownLatch(1);
+        registerErrorPage(name, errors, initLatch);
+        awaitServiceRegistration(initLatch);
+    }
+
+    private void registerErrorPage(String name, List<String> errors, CountDownLatch initLatch)
+    {
+        registerErrorPage(name, errors, null, initLatch);
+    }
+
+    private void registerErrorPage(String name, List<String> errors, String context, CountDownLatch initLatch)
+    {
+        List<Object> propertyEntries = Arrays.<Object>asList(
+                HTTP_WHITEBOARD_SERVLET_ERROR_PAGE, errors,
+                HTTP_WHITEBOARD_SERVLET_NAME, name,
+                HTTP_WHITEBOARD_CONTEXT_SELECT, context);
+
+        Dictionary<String, ?> properties = createDictionary(context == null ?
+                propertyEntries.subList(0, 4).toArray() : propertyEntries.toArray());
+
+        m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties);
+    }
+
+    private void registerListener(Class<?> listenerClass, boolean useWithWhiteboard) throws InterruptedException
+    {
+        registerListener(listenerClass, useWithWhiteboard, null);
+    }
+
+    private void registerListener(Class<?> listenerClass, boolean useWithWhiteboard, String context) throws InterruptedException
+    {
+        List<Object> propertyEntries = Arrays.<Object>asList(
+                HTTP_WHITEBOARD_LISTENER, useWithWhiteboard ? "true" : "false",
+                HTTP_WHITEBOARD_CONTEXT_SELECT, context);
+
+        Dictionary<String, ?> properties = createDictionary(context == null ?
+                propertyEntries.subList(0, 2).toArray() : propertyEntries.toArray());
+
+        m_context.registerService(listenerClass.getName(), mock(listenerClass), properties);
+        awaitServiceRegistration();
+    }
+
+    private ServiceRegistration<?> registerContext(String name, String path) throws InterruptedException
+    {
+        Dictionary<String, ?> properties = createDictionary(
+                HTTP_WHITEBOARD_CONTEXT_NAME, name,
+                HTTP_WHITEBOARD_CONTEXT_PATH, path);
+
+        ServiceRegistration<?> contextRegistration = m_context.registerService(ServletContextHelper.class.getName(), mock(ServletContextHelper.class), properties);
+        awaitServiceRegistration();
+        return contextRegistration;
+    }
+
+    @Before
+    public void awaitServiceRuntime() throws Exception
+    {
+        awaitService(HttpServiceRuntime.class.getName());
+    }
+
+    @Test
+    public void httpRuntimeServiceIsAvailableAfterBundleActivation() throws Exception
+    {
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+        Map<String, String> runtimeDTOAttributes = runtimeDTO.attributes;
+
+        assertNotNull(runtimeDTOAttributes);
+        assertTrue(runtimeDTOAttributes.containsKey(HTTP_SERVICE_ID_ATTRIBUTE));
+        assertTrue(runtimeDTOAttributes.containsKey(HTTP_SERVICE_ENDPOINT_ATTRIBUTE));
+        assertTrue(0 < Integer.valueOf(runtimeDTOAttributes.get(HTTP_SERVICE_ID_ATTRIBUTE)));
+
+        assertEquals(0, runtimeDTO.failedErrorPageDTOs.length);
+        assertEquals(0, runtimeDTO.failedFilterDTOs.length);
+        assertEquals(0, runtimeDTO.failedListenerDTOs.length);
+        assertEquals(0, runtimeDTO.failedResourceDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletDTOs.length);
+
+        assertEquals(1, runtimeDTO.servletContextDTOs.length);
+        assertEquals("default", runtimeDTO.servletContextDTOs[0].name);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].attributes.size());
+
+        // TODO The default context should have a negative service Id
+//        assertTrue(0 > runtimeDTO.servletContextDTOs[0].serviceId);
+        assertEquals("", runtimeDTO.servletContextDTOs[0].contextPath);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].initParams.size());
+
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].filterDTOs.length);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].servletDTOs.length);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].resourceDTOs.length);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].errorPageDTOs.length);
+        assertEquals(0, runtimeDTO.servletContextDTOs[0].listenerDTOs.length);
+    }
+
+    @Test
+    public void dtosForSuccesfullyRegisteredServlets() throws Exception
+    {
+        //register first servlet
+        registerServlet("testServlet 1", "/servlet_1");
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTOWithFirstSerlvet = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithFirstSerlvet.failedServletDTOs.length);
+
+        ServletContextDTO contextDTO = assertDefaultContext(runtimeDTOWithFirstSerlvet);
+        assertEquals(1, contextDTO.servletDTOs.length);
+        assertEquals("testServlet 1", contextDTO.servletDTOs[0].name);
+
+        //register second servlet
+        registerServlet("testServlet 2", "/servlet_2");
+
+        RuntimeDTO runtimeDTOWithBothSerlvets = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithBothSerlvets.failedServletDTOs.length);
+
+        contextDTO = assertDefaultContext(runtimeDTOWithBothSerlvets);
+        assertEquals(2, contextDTO.servletDTOs.length);
+        assertEquals("testServlet 1", contextDTO.servletDTOs[0].name);
+        assertEquals("testServlet 2", contextDTO.servletDTOs[1].name);
+    }
+
+    @Test
+    public void dtosForSuccesfullyRegisteredFilters() throws Exception
+    {
+        //register first filter
+        registerFilter("testFilter 1", "/servlet_1");
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTOWithFirstFilter = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithFirstFilter.failedFilterDTOs.length);
+
+        ServletContextDTO contextDTO = assertDefaultContext(runtimeDTOWithFirstFilter);
+        assertEquals(1, contextDTO.filterDTOs.length);
+        assertEquals("testFilter 1", contextDTO.filterDTOs[0].name);
+
+        //register second filter
+        registerFilter("testFilter 2", "/servlet_1");
+
+        RuntimeDTO runtimeDTOWithBothFilters = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithBothFilters.failedFilterDTOs.length);
+
+        contextDTO = assertDefaultContext(runtimeDTOWithBothFilters);
+        assertEquals(2, contextDTO.filterDTOs.length);
+        assertEquals("testFilter 1", contextDTO.filterDTOs[0].name);
+        assertEquals("testFilter 2", contextDTO.filterDTOs[1].name);
+    }
+
+    @Test
+    public void dtosForSuccesfullyRegisteredResources() throws Exception
+    {
+        // register first resource service
+        registerResource("/resources", "/resource_1/*");
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTOWithFirstResource = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithFirstResource.failedResourceDTOs.length);
+
+        ServletContextDTO contextDTO = assertDefaultContext(runtimeDTOWithFirstResource);
+        assertEquals(1, contextDTO.resourceDTOs.length);
+        assertEquals("/resources", contextDTO.resourceDTOs[0].prefix);
+        assertArrayEquals(new String[] { "/resource_1/*" }, contextDTO.resourceDTOs[0].patterns);
+
+        // register second resource service
+        registerResource("/resources", "/resource_2/*");
+
+        RuntimeDTO runtimeDTOWithBothResources = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithBothResources.failedResourceDTOs.length);
+
+        contextDTO = assertDefaultContext(runtimeDTOWithBothResources);
+        assertEquals(2, contextDTO.resourceDTOs.length);
+        assertEquals("/resources", contextDTO.resourceDTOs[0].prefix);
+        assertArrayEquals(new String[] { "/resource_1/*" }, contextDTO.resourceDTOs[0].patterns);
+        assertEquals("/resources", contextDTO.resourceDTOs[1].prefix);
+        assertArrayEquals(new String[] { "/resource_2/*" }, contextDTO.resourceDTOs[1].patterns);
+    }
+
+    @Test
+    public void dtosForSuccesfullyRegisteredErrorPages() throws Exception
+    {
+        // register first error page
+        registerErrorPage("error page 1", asList("404", NoSuchElementException.class.getName()));
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTOWithFirstErrorPage = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithFirstErrorPage.failedServletDTOs.length);
+        assertEquals(0, runtimeDTOWithFirstErrorPage.failedErrorPageDTOs.length);
+
+        ServletContextDTO contextDTO = runtimeDTOWithFirstErrorPage.servletContextDTOs[0];
+        assertEquals(1, contextDTO.errorPageDTOs.length);
+        assertEquals("error page 1", contextDTO.errorPageDTOs[0].name);
+        assertArrayEquals(new String[] { NoSuchElementException.class.getName() }, contextDTO.errorPageDTOs[0].exceptions);
+        assertArrayEquals(new long[] { 404 }, contextDTO.errorPageDTOs[0].errorCodes);
+
+        // register second error page
+        registerErrorPage("error page 2", asList("500", ServletException.class.getName()));
+
+        RuntimeDTO runtimeDTOWithBothErrorPages = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithBothErrorPages.failedServletDTOs.length);
+        assertEquals(0, runtimeDTOWithBothErrorPages.failedErrorPageDTOs.length);
+
+        contextDTO = assertDefaultContext(runtimeDTOWithBothErrorPages);
+        assertEquals(2, contextDTO.errorPageDTOs.length);
+        assertEquals("error page 1", contextDTO.errorPageDTOs[0].name);
+        assertEquals("error page 2", contextDTO.errorPageDTOs[1].name);
+        assertArrayEquals(new String[] { ServletException.class.getName() }, contextDTO.errorPageDTOs[1].exceptions);
+        assertArrayEquals(new long[] { 500 }, contextDTO.errorPageDTOs[1].errorCodes);
+    }
+
+    @Test
+    public void dtosForSuccesfullyRegisteredListeners() throws Exception
+    {
+        // register a servlet context listenere as first listener
+        registerListener(ServletContextListener.class, true);
+        awaitService(ServletContextListener.class.getName());
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTOWithFirstListener = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithFirstListener.failedListenerDTOs.length);
+        assertEquals(1, runtimeDTOWithFirstListener.servletContextDTOs.length);
+
+        ServletContextDTO contextDTO = runtimeDTOWithFirstListener.servletContextDTOs[0];
+        // TODO fix : servlet context listener is only added when registerd before context activation
+        assertEquals(0, contextDTO.listenerDTOs.length);
+        // TODO
+//        assertEquals(ServletContextListener.class.getName(), contextDTO.listenerDTOs[0].types[0]);
+
+        // register all other listener types
+        registerListener(ServletContextAttributeListener.class, true);
+        registerListener(ServletRequestListener.class, true);
+        registerListener(ServletRequestAttributeListener.class, true);
+        registerListener(HttpSessionListener.class, true);
+        registerListener(HttpSessionAttributeListener.class, true);
+
+        awaitService(ServletContextAttributeListener.class.getName());
+        awaitService(ServletRequestListener.class.getName());
+        awaitService(ServletRequestAttributeListener.class.getName());
+        awaitService(HttpSessionListener.class.getName());
+        awaitService(HttpSessionAttributeListener.class.getName());
+
+        RuntimeDTO runtimeDTOWithAllListeners = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithAllListeners.failedListenerDTOs.length);
+        assertEquals(1, runtimeDTOWithAllListeners.servletContextDTOs.length);
+
+        contextDTO = runtimeDTOWithAllListeners.servletContextDTOs[0];
+        // TODO
+        assertEquals(5, contextDTO.listenerDTOs.length);
+//        assertEquals(ServletContextListener.class.getName(), contextDTO.listenerDTOs[0].types[0]);
+        assertEquals(ServletContextAttributeListener.class.getName(), contextDTO.listenerDTOs[0].types[0]);
+        assertEquals(ServletRequestListener.class.getName(), contextDTO.listenerDTOs[1].types[0]);
+        assertEquals(ServletRequestAttributeListener.class.getName(), contextDTO.listenerDTOs[2].types[0]);
+        assertEquals(HttpSessionListener.class.getName(), contextDTO.listenerDTOs[3].types[0]);
+        assertEquals(HttpSessionAttributeListener.class.getName(), contextDTO.listenerDTOs[4].types[0]);
+    }
+
+    @Test
+    public void dtosForSuccesfullyRegisteredContexts() throws Exception
+    {
+        // register first additional context
+        registerContext("contextA", "/contextA");
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTOWithAdditionalContext = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithAdditionalContext.failedServletContextDTOs.length);
+        assertEquals(2, runtimeDTOWithAdditionalContext.servletContextDTOs.length);
+
+        // default context is last, as it has the lowest service ranking
+        assertEquals("contextA", runtimeDTOWithAdditionalContext.servletContextDTOs[0].name);
+        assertEquals("/contextA", runtimeDTOWithAdditionalContext.servletContextDTOs[0].contextPath);
+        assertEquals("default", runtimeDTOWithAdditionalContext.servletContextDTOs[1].name);
+        // TODO should this be "/" ?
+        assertEquals("", runtimeDTOWithAdditionalContext.servletContextDTOs[1].contextPath);
+
+        // register second additional context
+        registerContext("contextB", "/contextB");
+
+        RuntimeDTO runtimeDTOWithAllContexts = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTOWithAllContexts.failedServletContextDTOs.length);
+        assertEquals(3, runtimeDTOWithAllContexts.servletContextDTOs.length);
+
+        // default context is last, as it has the lowest service ranking
+        assertEquals("contextA", runtimeDTOWithAllContexts.servletContextDTOs[0].name);
+        assertEquals("/contextA", runtimeDTOWithAllContexts.servletContextDTOs[0].contextPath);
+        assertEquals("contextB", runtimeDTOWithAllContexts.servletContextDTOs[1].name);
+        assertEquals("/contextB", runtimeDTOWithAllContexts.servletContextDTOs[1].contextPath);
+        assertEquals("default", runtimeDTOWithAllContexts.servletContextDTOs[2].name);
+        assertEquals("", runtimeDTOWithAllContexts.servletContextDTOs[2].contextPath);
+    }
+
+    @Test
+    public void successfulSetup() throws InterruptedException
+    {
+        CountDownLatch initLatch = new CountDownLatch(6);
+
+        registerContext("test-context", "/test-context");
+
+        registerServlet("default servlet", "/default", initLatch);
+        registerFilter("default filter", "/default", initLatch);
+        registerErrorPage("default error page", asList(Exception.class.getName()), initLatch);
+        registerResource("/", "/default/resource");
+        registerListener(ServletRequestListener.class, true);
+
+        registerServlet("context servlet", "/default", "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=test-context)", initLatch);
+        registerFilter("context filter", "/default", "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=test-context)", initLatch);
+        registerErrorPage("context error page", asList("500"), "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=test-context)", initLatch);
+        registerResource("/", "/test-contextd/resource", "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=test-context)");
+        registerListener(ServletRequestListener.class, true, "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=test-context)");
+
+        awaitServiceRegistration(initLatch);
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedErrorPageDTOs.length);
+        assertEquals(0, runtimeDTO.failedFilterDTOs.length);
+        assertEquals(0, runtimeDTO.failedListenerDTOs.length);
+        assertEquals(0, runtimeDTO.failedResourceDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(0, runtimeDTO.failedServletDTOs.length);
+
+        assertEquals(2, runtimeDTO.servletContextDTOs.length);
+        assertEquals("test-context", runtimeDTO.servletContextDTOs[0].name);
+        assertEquals("default", runtimeDTO.servletContextDTOs[1].name);
+
+        ServletContextDTO defaultContextDTO = runtimeDTO.servletContextDTOs[1];
+        long contextServiceId = defaultContextDTO.serviceId;
+
+        assertEquals(1, defaultContextDTO.servletDTOs.length);
+        assertEquals("default servlet", defaultContextDTO.servletDTOs[0].name);
+        assertEquals(contextServiceId, defaultContextDTO.servletDTOs[0].servletContextId);
+        assertEquals(1, defaultContextDTO.filterDTOs.length);
+        assertEquals("default filter", defaultContextDTO.filterDTOs[0].name);
+        assertEquals(contextServiceId, defaultContextDTO.filterDTOs[0].servletContextId);
+        assertEquals(1, defaultContextDTO.errorPageDTOs.length);
+        assertEquals(Exception.class.getName(), defaultContextDTO.errorPageDTOs[0].exceptions[0]);
+        assertEquals(contextServiceId, defaultContextDTO.errorPageDTOs[0].servletContextId);
+        assertEquals(1, defaultContextDTO.listenerDTOs.length);
+        assertEquals(ServletRequestListener.class.getName(), defaultContextDTO.listenerDTOs[0].types[0]);
+        assertEquals(contextServiceId, defaultContextDTO.listenerDTOs[0].servletContextId);
+
+        ServletContextDTO testContextDTO = runtimeDTO.servletContextDTOs[0];
+        contextServiceId = testContextDTO.serviceId;
+
+        assertEquals(1, testContextDTO.servletDTOs.length);
+        assertEquals("context servlet", testContextDTO.servletDTOs[0].name);
+        assertEquals(contextServiceId, testContextDTO.servletDTOs[0].servletContextId);
+        assertEquals(1, testContextDTO.filterDTOs.length);
+        assertEquals("context filter", testContextDTO.filterDTOs[0].name);
+        assertEquals(contextServiceId, testContextDTO.filterDTOs[0].servletContextId);
+        assertEquals(1, testContextDTO.errorPageDTOs.length);
+        assertEquals(500L, testContextDTO.errorPageDTOs[0].errorCodes[0]);
+        assertEquals(contextServiceId, testContextDTO.errorPageDTOs[0].servletContextId);
+        assertEquals(1, testContextDTO.listenerDTOs.length);
+        assertEquals(ServletRequestListener.class.getName(), testContextDTO.listenerDTOs[0].types[0]);
+        assertEquals(contextServiceId, testContextDTO.listenerDTOs[0].servletContextId);
+    }
+
+    @Test
+    public void exceptionInServletInitAppearsAsFailure() throws ServletException, InterruptedException
+    {
+        Dictionary<String, ?> properties = createDictionary(
+                HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet",
+                HTTP_WHITEBOARD_SERVLET_NAME, "servlet");
+
+        CountDownLatch initLatch = new CountDownLatch(1);
+
+        @SuppressWarnings("serial")
+        Servlet failingServlet = new TestServlet(initLatch, null) {
+            @Override
+            public void init() throws ServletException
+            {
+                super.init();
+                throw new ServletException();
+            }
+        };
+
+        m_context.registerService(Servlet.class.getName(), failingServlet, properties);
+        awaitServiceRegistration(initLatch);
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+        assertEquals(1, runtimeDTO.failedServletDTOs.length);
+        assertEquals("servlet", runtimeDTO.failedServletDTOs[0].name);
+        assertEquals(FAILURE_REASON_EXCEPTION_ON_INIT, runtimeDTO.failedServletDTOs[0].failureReason);
+    }
+
+    @Test
+    public void exceptionInFilterInitAppearsAsFailure() throws ServletException, InterruptedException
+    {
+        Dictionary<String, ?> properties = createDictionary(
+                HTTP_WHITEBOARD_FILTER_PATTERN, "/filter",
+                HTTP_WHITEBOARD_FILTER_NAME, "filter");
+
+        CountDownLatch initLatch = new CountDownLatch(1);
+
+        Filter failingFilter = new TestFilter(initLatch, null) {
+            @Override
+            public void init(FilterConfig config) throws ServletException
+            {
+                super.init(config);
+                throw new ServletException();
+            }
+        };
+
+        m_context.registerService(Filter.class.getName(), failingFilter, properties);
+        awaitServiceRegistration(initLatch);
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+        assertEquals(1, runtimeDTO.failedFilterDTOs.length);
+        assertEquals("filter", runtimeDTO.failedFilterDTOs[0].name);
+        assertEquals(FAILURE_REASON_EXCEPTION_ON_INIT, runtimeDTO.failedFilterDTOs[0].failureReason);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.1 (TODO : exact version)
+    @Test
+    public void hiddenDefaultContextAppearsAsFailure() throws InterruptedException
+    {
+        registerContext("default", "");
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+        assertEquals(1, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals("default", runtimeDTO.failedServletContextDTOs[0].name);
+        assertDefaultContext(runtimeDTO);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.1
+    @Test
+    public void contextHelperWithDuplicateNameAppearsAsFailure() throws InterruptedException
+    {
+        ServiceRegistration<?> firstContextReg = registerContext("contextA", "/first");
+        registerContext("contextA", "/second");
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(1, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals("contextA", runtimeDTO.failedServletContextDTOs[0].name);
+        assertEquals("/second", runtimeDTO.failedServletContextDTOs[0].contextPath);
+        assertEquals(FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, runtimeDTO.failedServletContextDTOs[0].failureReason);
+
+        assertEquals(2, runtimeDTO.servletContextDTOs.length);
+        assertEquals("default", runtimeDTO.servletContextDTOs[1].name);
+
+        assertEquals("contextA", runtimeDTO.servletContextDTOs[0].name);
+        assertEquals("/first", runtimeDTO.servletContextDTOs[0].contextPath);
+
+        firstContextReg.unregister();
+
+        runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedServletContextDTOs.length);
+
+        assertEquals(2, runtimeDTO.servletContextDTOs.length);
+        assertEquals("default", runtimeDTO.servletContextDTOs[1].name);
+
+        assertEquals("contextA", runtimeDTO.servletContextDTOs[0].name);
+        assertEquals("/second", runtimeDTO.servletContextDTOs[0].contextPath);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.1
+    @Test
+    public void missingContextHelperNameAppearsAsFailure()
+    {
+        Dictionary<String, ?> properties = createDictionary(HTTP_WHITEBOARD_CONTEXT_PATH, "");
+
+        m_context.registerService(ServletContextHelper.class.getName(), mock(ServletContextHelper.class), properties);
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(1, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(null, runtimeDTO.failedServletContextDTOs[0].name);
+        assertEquals(FAILURE_REASON_VALIDATION_FAILED, runtimeDTO.failedServletContextDTOs[0].failureReason);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.1
+    @Test
+    public void invalidContextHelperNameAppearsAsFailure() throws InterruptedException
+    {
+        registerContext("context A", "");
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(1, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals("context A", runtimeDTO.failedServletContextDTOs[0].name);
+        assertEquals(FAILURE_REASON_VALIDATION_FAILED, runtimeDTO.failedServletContextDTOs[0].failureReason);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.1
+    @Test
+    public void invalidContextHelperPathAppearsAsFailure() throws InterruptedException
+    {
+        registerContext("contextA", "#");
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(1, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals("#", runtimeDTO.failedServletContextDTOs[0].contextPath);
+        assertEquals(FAILURE_REASON_VALIDATION_FAILED, runtimeDTO.failedServletContextDTOs[0].failureReason);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.3
+    @Test
+    public void selectionOfNonExistingContextHelperAppearsAsFailure() throws InterruptedException
+    {
+        registerServlet("servlet 1", "/", "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=contextA)", null);
+        awaitServiceRegistration();
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(1, runtimeDTO.failedServletDTOs.length);
+        assertEquals("servlet 1", runtimeDTO.failedServletDTOs[0].name);
+        assertEquals(FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING, runtimeDTO.failedServletDTOs[0].failureReason);
+
+        registerContext("contextA", "/contextA");
+
+        runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedServletDTOs.length);
+        assertEquals(2, runtimeDTO.servletContextDTOs.length);
+        assertEquals("contextA", runtimeDTO.servletContextDTOs[0].name);
+        assertEquals(1, runtimeDTO.servletContextDTOs[0].servletDTOs.length);
+        assertEquals("servlet 1", runtimeDTO.servletContextDTOs[0].servletDTOs[0].name);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.3
+    @Test
+    public void differentTargetIsIgnored() throws InterruptedException
+    {
+        Dictionary<String, ?> properties = createDictionary(
+                HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet",
+                HTTP_WHITEBOARD_SERVLET_NAME, "servlet",
+                HTTP_WHITEBOARD_TARGET, "(org.osgi.service.http.port=8282)");
+
+        m_context.registerService(Servlet.class.getName(), new TestServlet(), properties);
+        awaitServiceRegistration();
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedServletDTOs.length);
+
+        ServletContextDTO defaultContext = assertDefaultContext(runtimeDTO);
+        assertEquals(0, defaultContext.servletDTOs.length);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.4
+    @Test
+    public void servletWithoutNameGetsFullyQualifiedName() throws InterruptedException
+    {
+        Dictionary<String, ?> properties = createDictionary(HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet");
+
+        CountDownLatch initLatch = new CountDownLatch(1);
+        m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties);
+        awaitServiceRegistration(initLatch);
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedServletDTOs.length);
+
+        ServletContextDTO defaultContext = assertDefaultContext(serviceRuntime.getRuntimeDTO());
+        assertEquals(1, defaultContext.servletDTOs.length);
+        assertEquals(TestServlet.class.getName(), defaultContext.servletDTOs[0].name);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.4.1
+    @Test
+    public void patternAndErrorPageSpecifiedInvalidAndAppearsAsFailure() throws InterruptedException
+    {
+        Dictionary<String, ?> properties = createDictionary(
+                HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet",
+                HTTP_WHITEBOARD_SERVLET_NAME, "servlet",
+                HTTP_WHITEBOARD_SERVLET_ERROR_PAGE, asList("400"));
+
+        m_context.registerService(Servlet.class.getName(), new TestServlet(), properties);
+        awaitServiceRegistration();
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        ServletContextDTO defaultContext = assertDefaultContext(serviceRuntime.getRuntimeDTO());
+        assertEquals(0, defaultContext.servletDTOs.length);
+        assertEquals(0, defaultContext.errorPageDTOs.length);
+
+        assertEquals(0, serviceRuntime.getRuntimeDTO().failedServletDTOs.length);
+        assertEquals(1, serviceRuntime.getRuntimeDTO().failedErrorPageDTOs.length);
+        assertEquals("servlet", serviceRuntime.getRuntimeDTO().failedErrorPageDTOs[0].name);
+        assertEquals(FAILURE_REASON_VALIDATION_FAILED, serviceRuntime.getRuntimeDTO().failedErrorPageDTOs[0].failureReason);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.4.1
+    @Test
+    public void multipleServletsForSamePatternChoosenByServiceRankingRules() throws InterruptedException
+    {
+        registerServlet("servlet 1", "/pathcollision");
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedServletDTOs.length);
+        ServletContextDTO defaultContext = assertDefaultContext(runtimeDTO);
+        assertEquals(1, defaultContext.servletDTOs.length);
+
+        Dictionary<String, ?> properties = createDictionary(
+                HTTP_WHITEBOARD_SERVLET_PATTERN, "/pathcollision",
+                HTTP_WHITEBOARD_SERVLET_NAME, "servlet 2",
+                SERVICE_RANKING, Integer.MAX_VALUE);
+
+        CountDownLatch initLatch = new CountDownLatch(1);
+        CountDownLatch destroyLatch = new CountDownLatch(1);
+        TestServlet testServlet = new TestServlet(initLatch, destroyLatch);
+        ServiceRegistration<?> higherRankingServlet = m_context.registerService(Servlet.class.getName(), testServlet, properties);
+
+        RuntimeDTO runtimeWithShadowedServlet = serviceRuntime.getRuntimeDTO();
+        awaitServiceRegistration(initLatch);
+
+        defaultContext = assertDefaultContext(runtimeWithShadowedServlet);
+        assertEquals(1, defaultContext.servletDTOs.length);
+
+        assertEquals(1, runtimeWithShadowedServlet.failedServletDTOs.length);
+        FailedServletDTO failedServletDTO = runtimeWithShadowedServlet.failedServletDTOs[0];
+        assertEquals("servlet 1", failedServletDTO.name);
+        assertEquals(FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, failedServletDTO.failureReason);
+
+        higherRankingServlet.unregister();
+        awaitServiceRegistration(destroyLatch);
+
+        runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedServletDTOs.length);
+        defaultContext = assertDefaultContext(runtimeDTO);
+        assertEquals(1, defaultContext.servletDTOs.length);
+        assertEquals("servlet 1", defaultContext.servletDTOs[0].name);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.4.1
+    @Test
+    @Ignore
+    public void multipleErrorPagesForSameExceptionsChoosenByServiceRankingRules()
+    {
+        // TODO
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.4
+    @Test
+    @Ignore
+    public void mulitpleServletsWithSamePatternHttpServiceRegistrationWins()
+    {
+        // TODO
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.7
+    @Test
+    public void invalidListenerPopertyValueAppearsAsFailure() throws Exception
+    {
+        Dictionary<String, ?> properties = createDictionary(HTTP_WHITEBOARD_LISTENER, "invalid");
+
+        m_context.registerService(ServletRequestListener.class.getName(), mock(ServletRequestListener.class), properties);
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(1, runtimeDTO.failedListenerDTOs.length);
+        assertEquals(FAILURE_REASON_VALIDATION_FAILED, runtimeDTO.failedListenerDTOs[0].failureReason);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.8
+    @Test
+    public void contextReplacedWithHigherRankingContext() throws Exception
+    {
+        ServiceRegistration<?> firstContext = registerContext("test-context", "/first");
+        Long firstContextId = (Long) firstContext.getReference().getProperty(Constants.SERVICE_ID);
+
+        CountDownLatch initLatch = new CountDownLatch(1);
+        registerServlet("servlet", "/servlet", "(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=test-context)", initLatch);
+        awaitServiceRegistration(initLatch);
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(2, runtimeDTO.servletContextDTOs.length);
+        assertEquals(firstContextId.longValue(), runtimeDTO.servletContextDTOs[0].serviceId);
+        assertEquals("test-context", runtimeDTO.servletContextDTOs[0].name);
+        assertEquals("/first", runtimeDTO.servletContextDTOs[0].contextPath);
+        assertEquals("default", runtimeDTO.servletContextDTOs[1].name);
+
+        assertEquals(1, runtimeDTO.servletContextDTOs[0].servletDTOs.length);
+        assertEquals("servlet", runtimeDTO.servletContextDTOs[0].servletDTOs[0].name);
+
+        Dictionary<String, ?> properties = createDictionary(
+                HTTP_WHITEBOARD_CONTEXT_NAME, "test-context",
+                HTTP_WHITEBOARD_CONTEXT_PATH, "/second",
+                SERVICE_RANKING, Integer.MAX_VALUE);
+
+        ServiceRegistration<?> secondContext = m_context.registerService(ServletContextHelper.class.getName(), mock(ServletContextHelper.class), properties);
+        Long secondContextId = (Long) secondContext.getReference().getProperty(Constants.SERVICE_ID);
+
+        runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(1, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(firstContextId.longValue(), runtimeDTO.failedServletContextDTOs[0].serviceId);
+        assertEquals("test-context", runtimeDTO.failedServletContextDTOs[0].name);
+        assertEquals("/first", runtimeDTO.failedServletContextDTOs[0].contextPath);
+
+        assertEquals(2, runtimeDTO.servletContextDTOs.length);
+
+        assertEquals(secondContextId.longValue(), runtimeDTO.servletContextDTOs[0].serviceId);
+        assertEquals("test-context", runtimeDTO.servletContextDTOs[0].name);
+        assertEquals("/second", runtimeDTO.servletContextDTOs[0].contextPath);
+        assertEquals("default", runtimeDTO.servletContextDTOs[1].name);
+
+        assertEquals(1, runtimeDTO.servletContextDTOs[0].servletDTOs.length);
+        assertEquals("servlet", runtimeDTO.servletContextDTOs[0].servletDTOs[0].name);
+
+        secondContext.unregister();
+
+        runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedServletContextDTOs.length);
+        assertEquals(2, runtimeDTO.servletContextDTOs.length);
+        assertEquals(firstContextId.longValue(), runtimeDTO.servletContextDTOs[0].serviceId);
+        assertEquals("test-context", runtimeDTO.servletContextDTOs[0].name);
+        assertEquals("/first", runtimeDTO.servletContextDTOs[0].contextPath);
+        assertEquals("default", runtimeDTO.servletContextDTOs[1].name);
+
+        assertEquals(1, runtimeDTO.servletContextDTOs[0].servletDTOs.length);
+        assertEquals("servlet", runtimeDTO.servletContextDTOs[0].servletDTOs[0].name);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.9
+    @Test
+    public void httServiceIdIsSet()
+    {
+        ServiceReference<?> httpServiceRef = m_context.getServiceReference(HttpService.class.getName());
+        ServiceReference<?> httpServiceRuntimeRef = m_context.getServiceReference(HttpServiceRuntime.class.getName());
+
+        Long expectedId = (Long) httpServiceRef.getProperty(SERVICE_ID);
+        Long actualId = (Long) httpServiceRuntimeRef.getProperty(HTTP_SERVICE_ID_ATTRIBUTE);
+
+        assertEquals(expectedId, actualId);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.9
+    @Test
+    @Ignore // This is still broken
+    public void serviceRegisteredWithHttpServiceHasNegativeServiceId() throws Exception
+    {
+        CountDownLatch initLatch = new CountDownLatch(1);
+        register("/test", new TestServlet(initLatch, null));
+        awaitServiceRegistration(initLatch);
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(1, runtimeDTO.servletContextDTOs.length);
+        assertEquals(1, runtimeDTO.servletContextDTOs[0].servletDTOs.length);
+        assertTrue(0 > runtimeDTO.servletContextDTOs[0].servletDTOs[0].serviceId);
+    }
+
+    // As specified in OSGi Compendium Release 6, Chapter 140.9
+    @Test
+    public void serviceWithoutRequiredPropertiesIsIgnored() throws InterruptedException
+    {
+        // Neither pattern nor error page specified
+        Dictionary<String, ?> properties = createDictionary(HTTP_WHITEBOARD_SERVLET_NAME, "servlet");
+
+        m_context.registerService(Servlet.class.getName(), new TestServlet(), properties);
+        awaitServiceRegistration();
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+
+        assertEquals(0, runtimeDTO.failedServletContextDTOs.length);
+        ServletContextDTO defaultContext = assertDefaultContext(runtimeDTO);
+        assertEquals(0, defaultContext.servletDTOs.length);
+    }
+
+    @Test
+    public void dtosAreIndependentCopies() throws Exception
+    {
+        //register first servlet
+        Dictionary<String, ?> properties = createDictionary(
+                HTTP_WHITEBOARD_SERVLET_PATTERN, "/test",
+                HTTP_WHITEBOARD_SERVLET_NAME, "servlet 1",
+                HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + "test", "testValue");
+
+        CountDownLatch initLatch = new CountDownLatch(1);
+        m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties);
+        awaitServiceRegistration(initLatch);
+
+        HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+        assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+        RuntimeDTO runtimeDTOWithFirstSerlvet = serviceRuntime.getRuntimeDTO();
+
+        //register second servlet
+        registerServlet("testServlet 2", "/servlet_2");
+
+        RuntimeDTO runtimeDTOWithTwoSerlvets = serviceRuntime.getRuntimeDTO();
+
+        assertNotSame(runtimeDTOWithFirstSerlvet, runtimeDTOWithTwoSerlvets);
+
+        ServletContextDTO defaultContextFirstServlet = assertDefaultContext(runtimeDTOWithFirstSerlvet);
+        ServletContextDTO defaultContextTwoServlets = assertDefaultContext(runtimeDTOWithTwoSerlvets);
+        assertNotSame(defaultContextFirstServlet.servletDTOs[0].patterns,
+                defaultContextTwoServlets.servletDTOs[0].patterns);
+
+        boolean mapsModifiable = true;
+        try
+        {
+            runtimeDTOWithTwoSerlvets.servletContextDTOs[0].servletDTOs[0].initParams.clear();
+        } catch (UnsupportedOperationException e)
+        {
+            mapsModifiable = false;
+        }
+
+        if (mapsModifiable)
+        {
+            assertNotSame(defaultContextFirstServlet.servletDTOs[0].initParams,
+                    defaultContextTwoServlets.servletDTOs[0].initParams);
+        }
+    }
+
+    private ServletContextDTO assertDefaultContext(RuntimeDTO runtimeDTO)
+    {
+        assertTrue(0 < runtimeDTO.servletContextDTOs.length);
+        assertEquals("default", runtimeDTO.servletContextDTOs[0].name);
+        return runtimeDTO.servletContextDTOs[0];
+    }
+
+    private void awaitServiceRegistration() throws InterruptedException
+    {
+        // Wait some time until the whiteboard (hopefully) picked up the service
+        Thread.sleep(DEFAULT_SLEEP);
+    }
+
+    private void awaitServiceRegistration(CountDownLatch initLatch) throws InterruptedException
+    {
+        if (!initLatch.await(5, TimeUnit.SECONDS))
+        {
+            fail("Service was not initialized in time!");
+        };
+        awaitServiceRegistration();
+    }
+
+    public static class TestResource
+    {
+        // Tagging class
+    }
+}