FELIX-4546 : Implement HttpServiceRuntime service

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1659791 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java b/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
index fe0a0e1..7c0143e 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
@@ -27,16 +27,12 @@
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
 import org.apache.felix.http.base.internal.handler.HttpServicePlugin;
 import org.apache.felix.http.base.internal.handler.HttpSessionWrapper;
-import org.apache.felix.http.base.internal.runtime.HttpServiceRuntimeImpl;
 import org.apache.felix.http.base.internal.service.HttpServiceFactory;
 import org.apache.felix.http.base.internal.service.listener.ServletContextAttributeListenerManager;
 import org.apache.felix.http.base.internal.service.listener.ServletRequestAttributeListenerManager;
 import org.apache.felix.http.base.internal.service.listener.ServletRequestListenerManager;
 import org.apache.felix.http.base.internal.whiteboard.WhiteboardHttpService;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.http.runtime.HttpServiceRuntime;
-import org.osgi.service.http.runtime.HttpServiceRuntimeConstants;
 
 public final class HttpServiceController
 {
@@ -45,21 +41,19 @@
     private final Dispatcher dispatcher;
     private final HttpServicePlugin plugin;
     private final HttpServiceFactory httpServiceFactory;
-    private volatile WhiteboardHttpService whiteboardHttpService;
+    private final WhiteboardHttpService whiteboardHttpService;
 
-    private volatile ServiceRegistration<HttpServiceRuntime> runtimeServiceReg;
-    private final Hashtable<String, Object> runtimeServiceProps = new Hashtable<String, Object>();;
-
-    public HttpServiceController(BundleContext bundleContext)
+    public HttpServiceController(final BundleContext bundleContext)
     {
         this.bundleContext = bundleContext;
         this.registry = new HandlerRegistry();
         this.dispatcher = new Dispatcher(this.registry);
         this.plugin = new HttpServicePlugin(bundleContext, registry);
         this.httpServiceFactory = new HttpServiceFactory(this.bundleContext, this.registry);
+        this.whiteboardHttpService = new WhiteboardHttpService(this.bundleContext, this.registry, this.httpServiceFactory);
     }
 
-    public Dispatcher getDispatcher()
+    Dispatcher getDispatcher()
     {
         return this.dispatcher;
     }
@@ -104,17 +98,7 @@
     public void setProperties(final Hashtable<String, Object> props)
     {
         this.httpServiceFactory.setProperties(props);
-
-        // runtime service gets the same props for now
-        this.runtimeServiceProps.clear();
-        this.runtimeServiceProps.putAll(props);
-
-        if (this.runtimeServiceReg != null)
-        {
-            this.runtimeServiceProps.put(HttpServiceRuntimeConstants.HTTP_SERVICE_ID_ATTRIBUTE,
-                    this.httpServiceFactory.getHttpServiceServiceId());
-            this.runtimeServiceReg.setProperties(this.runtimeServiceProps);
-        }
+        this.whiteboardHttpService.setProperties(props);
     }
 
     public void register(final ServletContext servletContext)
@@ -122,37 +106,22 @@
         this.plugin.register();
 
         this.httpServiceFactory.start(servletContext);
+        this.whiteboardHttpService.start(servletContext);
 
-        this.runtimeServiceProps.put(HttpServiceRuntimeConstants.HTTP_SERVICE_ID_ATTRIBUTE,
-                this.httpServiceFactory.getHttpServiceServiceId());
-        this.runtimeServiceReg = this.bundleContext.registerService(HttpServiceRuntime.class,
-                new HttpServiceRuntimeImpl(),
-                this.runtimeServiceProps);
-
-        this.whiteboardHttpService = new WhiteboardHttpService(this.bundleContext,
-                servletContext,
-                this.registry,
-                this.runtimeServiceReg.getReference());
         this.dispatcher.setWhiteboardHttpService(this.whiteboardHttpService);
     }
 
     public void unregister()
     {
+        this.plugin.unregister();
+
         this.dispatcher.setWhiteboardHttpService(null);
+
         if ( this.whiteboardHttpService != null )
         {
-            this.whiteboardHttpService.close();
-            this.whiteboardHttpService = null;
+            this.whiteboardHttpService.stop();
         }
 
-        if ( this.runtimeServiceReg != null )
-        {
-            this.runtimeServiceReg.unregister();
-            this.runtimeServiceReg = null;
-        }
-
-        this.plugin.unregister();
-
         if ( this.httpServiceFactory != null )
         {
             this.httpServiceFactory.stop();
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpServiceRuntimeImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpServiceRuntimeImpl.java
deleted file mode 100644
index 11e1e7f..0000000
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpServiceRuntimeImpl.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.felix.http.base.internal.runtime;
-
-import org.osgi.service.http.runtime.HttpServiceRuntime;
-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.FailedServletDTO;
-import org.osgi.service.http.runtime.dto.FilterDTO;
-import org.osgi.service.http.runtime.dto.RequestInfoDTO;
-import org.osgi.service.http.runtime.dto.RuntimeDTO;
-import org.osgi.service.http.runtime.dto.ServletDTO;
-
-public final class HttpServiceRuntimeImpl implements HttpServiceRuntime
-{
-
-    @Override
-    public RuntimeDTO getRuntimeDTO()
-    {
-        // create new DTO on every call
-        final RuntimeDTO runtime = new RuntimeDTO();
-
-        return runtime;
-    }
-
-    public void registerServlet(ServletDTO servletDTO)
-    {
-        // TODO
-    }
-
-    public void registerFailedServlet(FailedServletDTO failedServletDTO)
-    {
-        // TODO
-    }
-
-    public void registerErrorPage(ErrorPageDTO errorPageDTO)
-    {
-        // TODO
-    }
-
-    public void registerFailedErrorPage(FailedErrorPageDTO failedErrorPageDTO)
-    {
-        // TODO
-    }
-
-    public void registerFilter(FilterDTO filterDTO)
-    {
-        // TODO
-    }
-
-    public void registerFailedFilter(FailedFilterDTO failedFilterDTO)
-    {
-        // TODO
-    }
-
-    @Override
-    public RequestInfoDTO calculateRequestInfoDTO(String path) {
-        // TODO
-        return null;
-    }
-
-}
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 17b0fc1..6960d09 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
@@ -17,6 +17,7 @@
 package org.apache.felix.http.base.internal.whiteboard;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashMap;
@@ -55,7 +56,6 @@
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.http.context.ServletContextHelper;
-import org.osgi.service.http.runtime.HttpServiceRuntime;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
 public final class ServletContextHelperManager
@@ -74,8 +74,6 @@
 
     private final Bundle bundle;
 
-    private final ServiceReference<HttpServiceRuntime> runtimeRef;
-
     private final Set<AbstractInfo<?>> invalidRegistrations = new ConcurrentSkipListSet<AbstractInfo<?>>();
 
     /**
@@ -84,13 +82,11 @@
      */
     public ServletContextHelperManager(final BundleContext bundleContext,
             final ServletContext webContext,
-            final ServiceReference<HttpServiceRuntime> runtimeRef,
             final WhiteboardHttpService httpService)
     {
         this.httpService = httpService;
         this.webContext = webContext;
         this.bundle = bundleContext.getBundle();
-        this.runtimeRef = runtimeRef;
 
         final Dictionary<String, Object> props = new Hashtable<String, Object>();
         props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME, HttpWhiteboardConstants.HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME);
@@ -481,7 +477,7 @@
             try
             {
                 final Filter f = this.bundle.getBundleContext().createFilter(target);
-                return f.match(this.runtimeRef);
+                return f.match(this.httpService.getServiceReference());
             }
             catch ( final InvalidSyntaxException ise)
             {
@@ -508,4 +504,18 @@
         }
         return null;
     }
+
+    public Collection<ContextHandler> getContextHandlers()
+    {
+         final List<ContextHandler> handlers = new ArrayList<ContextHandler>();
+         synchronized ( this.contextMap )
+         {
+             for(final List<ContextHandler> handlerList : this.contextMap.values())
+             {
+                 final ContextHandler h = handlerList.get(0);
+                 handlers.add(h);
+             }
+         }
+         return handlers;
+    }
 }
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 fe7c46e..e197517 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
@@ -17,7 +17,11 @@
 package org.apache.felix.http.base.internal.whiteboard;
 
 import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.annotation.Nonnull;
@@ -35,6 +39,7 @@
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.ResourceInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.service.HttpServiceFactory;
 import org.apache.felix.http.base.internal.whiteboard.tracker.FilterTracker;
 import org.apache.felix.http.base.internal.whiteboard.tracker.HttpSessionAttributeListenerTracker;
 import org.apache.felix.http.base.internal.whiteboard.tracker.HttpSessionListenerTracker;
@@ -48,20 +53,36 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceObjects;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.http.runtime.HttpServiceRuntime;
+import org.osgi.service.http.runtime.HttpServiceRuntimeConstants;
+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.RequestInfoDTO;
+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;
 import org.osgi.util.tracker.ServiceTracker;
 
-public final class WhiteboardHttpService
+public final class WhiteboardHttpService implements HttpServiceRuntime
 {
 
     private final HandlerRegistry handlerRegistry;
 
     private final BundleContext bundleContext;
 
-    private final ServletContextHelperManager contextManager;
+    private volatile ServletContextHelperManager contextManager;
 
     private final List<ServiceTracker<?, ?>> trackers = new ArrayList<ServiceTracker<?, ?>>();
 
+    private final Hashtable<String, Object> runtimeServiceProps = new Hashtable<String, Object>();;
+
+    private final HttpServiceFactory httpServiceFactory;
+
+    private volatile ServiceRegistration<HttpServiceRuntime> runtimeServiceReg;
+
     /**
      * Create a new whiteboard http service
      * @param bundleContext
@@ -69,13 +90,17 @@
      * @param handlerRegistry
      */
     public WhiteboardHttpService(final BundleContext bundleContext,
-            final ServletContext context,
             final HandlerRegistry handlerRegistry,
-            final ServiceReference<HttpServiceRuntime> runtimeRef)
+            final HttpServiceFactory httpServiceFactory)
     {
         this.handlerRegistry = handlerRegistry;
         this.bundleContext = bundleContext;
-        this.contextManager = new ServletContextHelperManager(bundleContext, context, runtimeRef, this);
+        this.httpServiceFactory = httpServiceFactory;
+    }
+
+    public void start(final ServletContext context)
+    {
+        this.contextManager = new ServletContextHelperManager(bundleContext, context, this);
 
         addTracker(new FilterTracker(bundleContext, contextManager));
         addTracker(new ServletTracker(bundleContext, this.contextManager));
@@ -90,16 +115,32 @@
 
         addTracker(new ServletRequestListenerTracker(bundleContext, this.contextManager));
         addTracker(new ServletRequestAttributeListenerTracker(bundleContext, this.contextManager));
+
+        this.runtimeServiceProps.put(HttpServiceRuntimeConstants.HTTP_SERVICE_ID_ATTRIBUTE,
+                this.httpServiceFactory.getHttpServiceServiceId());
+        this.runtimeServiceReg = this.bundleContext.registerService(HttpServiceRuntime.class,
+                this,
+                this.runtimeServiceProps);
     }
 
-    public void close()
+    public void stop()
     {
+        if ( this.runtimeServiceReg != null )
+        {
+            this.runtimeServiceReg.unregister();
+            this.runtimeServiceReg = null;
+        }
+
         for(final ServiceTracker<?, ?> t : this.trackers)
         {
             t.close();
         }
         this.trackers.clear();
-        this.contextManager.close();
+        if ( this.contextManager != null )
+        {
+            this.contextManager.close();
+            this.contextManager = null;
+        }
     }
 
     private void addTracker(ServiceTracker<?, ?> tracker)
@@ -108,6 +149,20 @@
         tracker.open();
     }
 
+    public void setProperties(final Hashtable<String, Object> props)
+    {
+        // runtime service gets the same props for now
+        this.runtimeServiceProps.clear();
+        this.runtimeServiceProps.putAll(props);
+
+        if (this.runtimeServiceReg != null)
+        {
+            this.runtimeServiceProps.put(HttpServiceRuntimeConstants.HTTP_SERVICE_ID_ATTRIBUTE,
+                    this.httpServiceFactory.getHttpServiceServiceId());
+            this.runtimeServiceReg.setProperties(this.runtimeServiceProps);
+        }
+    }
+
     /**
      * Register a servlet.
      * @param contextInfo The servlet context helper info
@@ -247,4 +302,80 @@
             }
         }
     }
+
+    public ServiceReference<HttpServiceRuntime> getServiceReference()
+    {
+        return this.runtimeServiceReg.getReference();
+    }
+
+    @Override
+    public RuntimeDTO getRuntimeDTO()
+    {
+        // create new DTO on every call
+        final RuntimeDTO runtime = new RuntimeDTO();
+
+        // attributes
+        runtime.attributes = new HashMap<String, String>();
+        for(final Map.Entry<String, Object> entry : this.runtimeServiceProps.entrySet())
+        {
+            runtime.attributes.put(entry.getKey(), entry.getValue().toString());
+        }
+
+        // servlet context DTOs
+        final List<ServletContextDTO> contextDTOs = new ArrayList<ServletContextDTO>();
+        for(final ContextHandler handler : this.contextManager.getContextHandlers())
+        {
+            final ServletContextDTO dto = new ServletContextDTO();
+
+            final ServletContext ctx = handler.getServletContext(this.bundleContext.getBundle());
+            try
+            {
+                dto.name = handler.getContextInfo().getName();
+                dto.contextPath = handler.getContextInfo().getPath();
+                dto.initParams = new HashMap<String, String>(handler.getContextInfo().getInitParameters());
+                dto.serviceId = handler.getContextInfo().getServiceId();
+
+                dto.contextName = ctx.getServletContextName();
+                dto.attributes = new HashMap<String, Object>();
+                final Enumeration<String> e = ctx.getAttributeNames();
+                while ( e.hasMoreElements() )
+                {
+                    final String name = e.nextElement();
+                    final Object value = ctx.getAttribute(name);
+                    if ( value != null )
+                    {
+                        // TODO - check for appropriate value types
+                    }
+                }
+
+                dto.errorPageDTOs = new ErrorPageDTO[0]; // TODO
+                dto.filterDTOs = new FilterDTO[0]; // TODO
+                dto.listenerDTOs = new ListenerDTO[0]; // TODO
+                dto.resourceDTOs = new ResourceDTO[0]; // TODO
+                dto.servletDTOs = new ServletDTO[0]; // TODO
+            }
+            finally
+            {
+                handler.ungetServletContext(this.bundleContext.getBundle());
+            }
+            contextDTOs.add(dto);
+        }
+        runtime.servletContextDTOs = contextDTOs.toArray(new ServletContextDTO[contextDTOs.size()]);
+
+        runtime.failedErrorPageDTOs = null; // TODO
+        runtime.failedFilterDTOs = null; // TODO
+        runtime.failedListenerDTOs = null; // TODO
+        runtime.failedResourceDTOs = null; // TODO
+        runtime.failedServletContextDTOs = null; // TODO
+        runtime.failedServletDTOs = null; // TODO
+
+        return runtime;
+    }
+
+    @Override
+    public RequestInfoDTO calculateRequestInfoDTO(final String path) {
+        // TODO
+        return null;
+    }
+
 }