FELIX-4060 : Implement HTTP Service Update (RFC-189)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1656701 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 748db74..c286cf0 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
@@ -24,7 +24,6 @@
 import org.apache.felix.http.base.internal.dispatch.Dispatcher;
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
 import org.apache.felix.http.base.internal.handler.HttpServicePlugin;
-import org.apache.felix.http.base.internal.handler.PerContextHandlerRegistry;
 import org.apache.felix.http.base.internal.listener.HttpSessionAttributeListenerManager;
 import org.apache.felix.http.base.internal.listener.HttpSessionListenerManager;
 import org.apache.felix.http.base.internal.listener.ServletContextAttributeListenerManager;
@@ -79,7 +78,6 @@
     {
         this.bundleContext = bundleContext;
         this.registry = new HandlerRegistry();
-        this.registry.add(new PerContextHandlerRegistry());
         this.dispatcher = new Dispatcher(this.registry);
         this.serviceProps = new Hashtable<String, Object>();
         this.contextAttributeListener = new ServletContextAttributeListenerManager(bundleContext);
@@ -177,7 +175,7 @@
             try
             {
                 this.serviceReg.unregister();
-                this.registry.removeAll();
+                this.registry.shutdown();
             }
             finally
             {
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 b3570d0..aaa07ca 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
@@ -18,6 +18,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
 import javax.annotation.Nonnull;
@@ -25,11 +26,79 @@
 
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 
+/**
+ * Registry for all services.
+ *
+ * The registry is organized per servlet context and is dispatching to one
+ * of the {@link PerContextHandlerRegistry} registries.
+ */
 public final class HandlerRegistry
 {
+    /** Current list of context registrations. */
     private volatile List<PerContextHandlerRegistry> registrations = Collections.emptyList();
 
-    public void add(@Nonnull PerContextHandlerRegistry registry)
+    public HandlerRegistry()
+    {
+        this.add(new PerContextHandlerRegistry());
+    }
+
+    /**
+     * Shutdown
+     */
+    public void shutdown()
+    {
+        final List<PerContextHandlerRegistry> list;
+
+        synchronized ( this )
+        {
+            list = new ArrayList<PerContextHandlerRegistry>(this.registrations);
+            this.registrations = Collections.emptyList();
+
+        }
+
+        for(final PerContextHandlerRegistry r : list)
+        {
+            r.removeAll();
+        }
+    }
+
+    /**
+     * Add a context registration.
+     * @param info The servlet context helper info
+     */
+    public void add(@Nonnull ServletContextHelperInfo info)
+    {
+        this.add(new PerContextHandlerRegistry(info));
+    }
+
+    /**
+     * Remove a context registration.
+     * @param info The servlet context helper info
+     */
+    public void remove(@Nonnull ServletContextHelperInfo info)
+    {
+        synchronized ( this )
+        {
+            final List<PerContextHandlerRegistry> updatedList = new ArrayList<PerContextHandlerRegistry>(this.registrations);
+            final Iterator<PerContextHandlerRegistry> i = updatedList.iterator();
+            while ( i.hasNext() )
+            {
+                final PerContextHandlerRegistry reg = i.next();
+                if ( reg.getContextServiceId() == info.getServiceId() )
+                {
+                    i.remove();
+                    this.registrations = updatedList;
+                    break;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Add a new context registration.
+     */
+    private void add(@Nonnull PerContextHandlerRegistry registry)
     {
         synchronized ( this )
         {
@@ -41,17 +110,11 @@
         }
     }
 
-    public void remove(@Nonnull PerContextHandlerRegistry registry)
-    {
-        synchronized ( this )
-        {
-            final List<PerContextHandlerRegistry> updatedList = new ArrayList<PerContextHandlerRegistry>(this.registrations);
-            updatedList.remove(registry);
-
-            this.registrations = updatedList;
-        }
-    }
-
+    /**
+     * Get the per context registry.
+     * @param info The servlet context helper info or {@code null} for the Http Service context.
+     * @return A per context registry or {@code null}
+     */
     public PerContextHandlerRegistry getRegistry(final ServletContextHelperInfo info)
     {
         final long key = (info == null ? 0 : info.getServiceId());
@@ -65,11 +128,9 @@
                     return r;
                 }
             }
-            final PerContextHandlerRegistry reg = new PerContextHandlerRegistry(info);
-            this.add(reg);
-
-            return reg;
         }
+
+        return null;
     }
 
     public ErrorsMapping getErrorsMapping(final String requestURI, final Long serviceId)
@@ -140,21 +201,4 @@
         }
         return null;
     }
-
-    public synchronized void removeAll()
-    {
-        final List<PerContextHandlerRegistry> list;
-
-        synchronized ( this )
-        {
-            list = new ArrayList<PerContextHandlerRegistry>(this.registrations);
-            this.registrations = Collections.emptyList();
-
-        }
-
-        for(final PerContextHandlerRegistry r : list)
-        {
-            r.removeAll();
-        }
-    }
 }
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 2b77de2..ef35c0f 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
@@ -120,6 +120,9 @@
     private void activate(final ContextHandler handler)
     {
         handler.activate();
+
+        this.httpService.registerContext(handler);
+
         // context listeners first
         final List<WhiteboardServiceInfo<?>> services = new ArrayList<WhiteboardServiceInfo<?>>();
         for(final Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>> entry : this.servicesMap.entrySet())
@@ -150,6 +153,8 @@
      */
     private void deactivate(final ContextHandler handler)
     {
+        this.httpService.unregisterContext(handler);
+
         // context listeners last
         final List<ServletContextListenerInfo> listeners = new ArrayList<ServletContextListenerInfo>();
         final Iterator<Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>>> i = this.servicesMap.entrySet().iterator();
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 d6f9c5d..2dfbbe7 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
@@ -201,4 +201,14 @@
         final ServletInfo servletInfo = new ServletInfo(resourceInfo);
         this.unregisterServlet(contextHandler, servletInfo);
     }
+
+    public void registerContext(@Nonnull final ContextHandler contextHandler)
+    {
+        this.handlerRegistry.add(contextHandler.getContextInfo());
+    }
+
+    public void unregisterContext(@Nonnull final ContextHandler contextHandler)
+    {
+        this.handlerRegistry.remove(contextHandler.getContextInfo());
+    }
 }