FELIX-4546 : Implement HttpServiceRuntime service. Apply patch from Thomas Baier

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1662253 13f79535-47bb-0310-9956-ffa450edef68
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 f45479c..8d27a96 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
@@ -354,17 +354,29 @@
     }
 
     public synchronized HandlerRuntime getRuntime() {
-        List<ServletHandler> servletHandlers = new ArrayList<ServletHandler>(servletMap.values());
-        List<FilterHandler> filterHandlers = new ArrayList<FilterHandler>(filterMap.values());
-
         Collection<ErrorPage> errorPages = new ArrayList<HandlerRuntime.ErrorPage>();
         Collection<ServletHandler> errorHandlers = errorsMapping.getMappedHandlers();
         for (ServletHandler servletHandler : errorHandlers)
         {
             errorPages.add(errorsMapping.getErrorPage(servletHandler));
         }
-        servletHandlers.removeAll(errorHandlers);
 
-        return new HandlerRuntime(servletHandlers, filterHandlers, errorPages, serviceId);
+        List<FilterHandler> filterHandlers = new ArrayList<FilterHandler>(filterMap.values());
+
+        List<ServletHandler> servletHandlers = new ArrayList<ServletHandler>();
+        List<ServletHandler> resourceHandlers = new ArrayList<ServletHandler>();
+        for (ServletHandler servletHandler : servletMap.values())
+        {
+            if (servletHandler.getServletInfo().isResource())
+            {
+                resourceHandlers.add(servletHandler);
+            }
+            else if (!errorHandlers.contains(servletHandler))
+            {
+                servletHandlers.add(servletHandler);
+            }
+        }
+
+        return new HandlerRuntime(servletHandlers, filterHandlers, resourceHandlers, errorPages, serviceId);
     }
 }
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HandlerRuntime.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HandlerRuntime.java
index ee86d25..ab815bf 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HandlerRuntime.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HandlerRuntime.java
@@ -28,16 +28,19 @@
 {
     private final Collection<ServletHandler> servletHandlers;
     private final Collection<FilterHandler> filterHandlers;
+    private final Collection<ServletHandler> resourceHandlers;
     private final Collection<ErrorPage> errorPages;
     private final long serviceId;
 
     public HandlerRuntime(Collection<ServletHandler> servletHandlers,
             Collection<FilterHandler> filterHandlers,
+            Collection<ServletHandler> resourceHandlers,
             Collection<ErrorPage> errorPages,
             long serviceId)
     {
         this.servletHandlers = servletHandlers;
         this.filterHandlers = filterHandlers;
+        this.resourceHandlers = resourceHandlers;
         this.errorPages = errorPages;
         this.serviceId = serviceId;
     }
@@ -46,6 +49,7 @@
     {
         return new HandlerRuntime(Collections.<ServletHandler>emptyList(),
                 Collections.<FilterHandler>emptyList(),
+                Collections.<ServletHandler>emptyList(),
                 Collections.<ErrorPage> emptyList(),
                 serviceId);
     }
@@ -60,6 +64,11 @@
         return filterHandlers;
     }
 
+    public Collection<ServletHandler> getResourceHandlers()
+    {
+        return resourceHandlers;
+    }
+
     public Collection<ErrorPage> getErrorPages()
     {
         return errorPages;
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 560234d..ec139e7 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
@@ -24,6 +24,7 @@
 import javax.servlet.Servlet;
 
 import org.osgi.dto.DTO;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.runtime.dto.ServletDTO;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
@@ -36,7 +37,7 @@
  *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public final class ServletInfo extends WhiteboardServiceInfo<Servlet>
+public class ServletInfo extends WhiteboardServiceInfo<Servlet>
 {
     /**
      * Properties starting with this prefix are passed as servlet init parameters to the
@@ -68,10 +69,17 @@
     private final boolean asyncSupported;
 
     /**
+     * Specifies whether the info represents a resource.
+     */
+    private final boolean isResource;
+
+    /**
      * The servlet initialization parameters as provided during registration of the servlet.
      */
     private final Map<String, String> initParams;
 
+    private final String prefix;
+
     public ServletInfo(final ServiceReference<Servlet> ref)
     {
         super(ref);
@@ -80,6 +88,8 @@
         this.patterns = getStringArrayProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN);
         this.asyncSupported = getBooleanProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED);
         this.initParams = getInitParams(ref, SERVLET_INIT_PREFIX);
+        this.isResource = false;
+        this.prefix = null;
     }
 
     @SuppressWarnings("unchecked")
@@ -91,8 +101,11 @@
         this.errorPage = null;
         this.asyncSupported = false;
         this.initParams = Collections.emptyMap();
+        this.isResource = true;
+        this.prefix = resource.getPrefix();
     }
 
+    @SuppressWarnings("rawtypes")
     private static ServiceReference getRef(ServiceReference ref)
     {
         return ref;
@@ -119,6 +132,8 @@
         this.initParams = initParams;
         this.asyncSupported = true;
         this.errorPage = null;
+        this.isResource = false;
+        this.prefix = null;
     }
 
     ServletInfo(int serviceRanking,
@@ -135,6 +150,8 @@
         this.errorPage = errorPage;
         this.asyncSupported = asyncSupported;
         this.initParams = initParams;
+        this.isResource = false;
+        this.prefix = null;
     }
 
     @Override
@@ -167,4 +184,41 @@
     {
         return initParams;
     }
+
+    public boolean isResource()
+    {
+        return isResource;
+    }
+
+    public String getPrefix()
+    {
+        return prefix;
+    }
+
+    @Override
+    public ServiceReference<Servlet> getServiceReference()
+    {
+        // TODO This method returns a ServiceReference<Object> in case of a resource
+        return super.getServiceReference();
+    }
+
+    @Override
+    public Servlet getService(Bundle bundle)
+    {
+        if (isResource)
+        {
+            throw new UnsupportedOperationException();
+        };
+        return super.getService(bundle);
+    }
+
+    @Override
+    public void ungetService(Bundle bundle, Servlet service)
+    {
+        if (isResource)
+        {
+            throw new UnsupportedOperationException();
+        };
+        super.ungetService(bundle, service);
+    }
 }
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 25a40da..5fa0156 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
@@ -19,18 +19,22 @@
 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;
 
-//TODO
 final class ResourceDTOBuilder extends BaseDTOBuilder<ServletHandler, ResourceDTO>
 {
+    private static final String[] STRING_ARRAY = new String[0];
+
     @Override
     ResourceDTO buildDTO(ServletHandler handler, long servletContextId)
     {
+        ServletInfo servletInfo = handler.getServletInfo();
+
         ResourceDTO resourceDTO = new ResourceDTO();
-        resourceDTO.patterns = null;
-        resourceDTO.prefix = null;
-        resourceDTO.serviceId = handler.getServletInfo().getServiceId();
+        resourceDTO.patterns = copyWithDefault(servletInfo.getPatterns(), STRING_ARRAY);
+        resourceDTO.prefix = servletInfo.getPrefix();
+        resourceDTO.serviceId = servletInfo.getServiceId();
         resourceDTO.servletContextId = servletContextId;
         return resourceDTO;
     }
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 eb4dcc1..7a03b83 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,7 +20,6 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -108,8 +107,7 @@
             Collection<ServiceReference<?>> listenerRefs)
     {
         Collection<ServletHandler> servletHandlers = handlerRuntime.getServletHandlers();
-        //TODO missing functionality
-        Collection<ServletHandler> resourceHandlers = Collections.emptyList();
+        Collection<ServletHandler> resourceHandlers = handlerRuntime.getResourceHandlers();
         Collection<FilterHandler> filterHandlers = handlerRuntime.getFilterHandlers();
         Collection<ErrorPage> errorPages = handlerRuntime.getErrorPages();
         long servletContextId = handlerRuntime.getServiceId();
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 5db1315..a78d8b0 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
@@ -81,6 +81,7 @@
 import org.osgi.service.http.runtime.dto.ErrorPageDTO;
 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.RuntimeDTO;
 import org.osgi.service.http.runtime.dto.ServletContextDTO;
 import org.osgi.service.http.runtime.dto.ServletDTO;
@@ -197,21 +198,25 @@
 
         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, errorPages_0, ID_0);
+        HandlerRuntime contextRuntime_0 = new HandlerRuntime(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, errorPages_A, ID_A);
+        HandlerRuntime contextRuntime_A = new HandlerRuntime(servlets_A, filters_A, resources_A, errorPages_A, ID_A);
 
         List<ServletHandler> servlets_B = asList(createTestServletWithServiceId("B_1", context_B),
                 createTestServletWithServiceId("B_2", context_B));
         List<FilterHandler> filters_B = asList(createTestFilterWithServiceId("B_1", context_B),
                 createTestFilterWithServiceId("B_2", context_B));
+        List<ServletHandler> resources_B = asList(createTestServletWithServiceId("B_1", context_B),
+                createTestServletWithServiceId("B_2", context_B));
         List<ErrorPage> errorPages_B = asList(createErrorPageWithServiceId("E_B_1", context_B),
                 createErrorPageWithServiceId("E_B_2", context_B));
-        HandlerRuntime contextRuntime_B = new HandlerRuntime(servlets_B, filters_B, errorPages_B, ID_B);
+        HandlerRuntime contextRuntime_B = new HandlerRuntime(servlets_B, filters_B, resources_B, errorPages_B, ID_B);
 
         Map<Long, Collection<ServiceReference<?>>> listenerRuntimes = setupListeners();
 
@@ -243,6 +248,8 @@
                 assertEquals(contextName,
                         1, servletContextDTO.filterDTOs.length);
                 assertEquals(contextName,
+                        1, servletContextDTO.resourceDTOs.length);
+                assertEquals(contextName,
                         1, servletContextDTO.errorPageDTOs.length);
                 assertEquals(contextName,
                         2, servletContextDTO.listenerDTOs.length);
@@ -259,6 +266,8 @@
                 assertEquals(contextName,
                         expectedChildren, servletContextDTO.filterDTOs.length);
                 assertEquals(contextName,
+                        expectedChildren, servletContextDTO.resourceDTOs.length);
+                assertEquals(contextName,
                         expectedChildren, servletContextDTO.errorPageDTOs.length);
                 assertEquals(contextName,
                         expectedChildren, servletContextDTO.listenerDTOs.length);
@@ -292,6 +301,10 @@
                     servletContextDTO.serviceId, servletContextDTO.filterDTOs);
             seenServiceIds.addAll(serviceIds);
 
+            serviceIds = assertResourceDTOs(contextName,
+                    servletContextDTO.serviceId, servletContextDTO.resourceDTOs);
+            seenServiceIds.addAll(serviceIds);
+
             serviceIds = assertErrorPageDTOs(contextName,
                     servletContextDTO.serviceId, servletContextDTO.errorPageDTOs);
             seenServiceIds.addAll(serviceIds);
@@ -300,8 +313,8 @@
                     servletContextDTO.serviceId, servletContextDTO.listenerDTOs);
             seenServiceIds.addAll(serviceIds);
         }
-        assertEquals(10, seenServiceIds.tailSet(0L).size());
-        assertEquals(7, seenServiceIds.headSet(0L).size());
+        assertEquals(12, seenServiceIds.tailSet(0L).size());
+        assertEquals(9, seenServiceIds.headSet(0L).size());
     }
 
     private Collection<Long> assertServletDTOs(String contextName, long contextId, ServletDTO[] dtos) {
@@ -401,6 +414,33 @@
         return serviceIds;
     }
 
+    private Collection<Long> assertResourceDTOs(String contextName, long contextId, ResourceDTO[] dtos) {
+        List<Long> serviceIds = new ArrayList<Long>();
+        for (ResourceDTO resourceDTO : dtos)
+        {
+            if (contextId != ID_B)
+            {
+                assertTrue(contextId + " " + contextName,
+                        resourceDTO.serviceId < 0);
+            }
+            else
+            {
+                assertTrue(contextId + " " + contextName,
+                        resourceDTO.serviceId > 0);
+            }
+            serviceIds.add(resourceDTO.serviceId);
+
+            assertEquals(contextId + " " + contextName,
+                    contextId, resourceDTO.servletContextId);
+
+            assertEquals(contextId + " " + contextName,
+                    1, resourceDTO.patterns.length);
+            assertTrue(contextId + " " + contextName,
+                    resourceDTO.patterns[0].startsWith("/"));
+        }
+        return serviceIds;
+    }
+
     private Collection<Long> assertErrorPageDTOs(String contextName, long contextId, ErrorPageDTO[] dtos)
     {
         List<Long> serviceIds = new ArrayList<Long>();
@@ -506,7 +546,21 @@
                 Collections.<String, String>emptyMap());
         FilterHandler filterHandler = new FilterHandler(null, context_0, mock(Filter.class), filterInfo);
 
-        HandlerRuntime contextRuntime = new HandlerRuntime(asList(servletHandler), asList(filterHandler), Collections.<ErrorPage>emptyList(), ID_0);
+        ServletInfo resourceInfo = createServletInfo(0,
+                ID_COUNTER.incrementAndGet(),
+                "1",
+                new String[] { "/*" },
+                null,
+                true,
+                Collections.<String, String>emptyMap());
+        Servlet resource = mock(Servlet.class);
+        ServletHandler resourceHandler = new ServletHandler(null, context_0, resourceInfo, resource);
+
+        HandlerRuntime contextRuntime = new HandlerRuntime(asList(servletHandler),
+                asList(filterHandler),
+                asList(resourceHandler),
+                Collections.<ErrorPage>emptyList(),
+                ID_0);
         setupRegistry(asList(contextHandler), asList(contextRuntime),
                 Collections.<Long, Collection<ServiceReference<?>>>emptyMap());
 
@@ -562,6 +616,7 @@
 
         HandlerRuntime contextRuntime = new HandlerRuntime(asList(servletHandler),
                 Collections.<FilterHandler>emptyList(),
+                Collections.<ServletHandler>emptyList(),
                 Collections.<ErrorPage>emptyList(),
                 ID_0);
         setupRegistry(asList(contextHandler), asList(contextRuntime),