FELIX-4060 : Split implementation of http service into shared and per bundle part.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1661355 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
index 23d95ee..1d3c057 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceFactory.java
@@ -64,7 +64,6 @@
     private static final String OBSOLETE_REG_PROPERTY_ENDPOINTS = "osgi.http.service.endpoints";
 
     private final BundleContext bundleContext;
-    private final HandlerRegistry handlerRegistry;
     private final boolean sharedContextAttributes;
 
     private final ServletContextAttributeListenerManager contextAttributeListenerManager;
@@ -77,6 +76,9 @@
     private volatile ServletContext context;
     private volatile ServiceRegistration<?> httpServiceReg;
 
+    private final HandlerRegistry handlerRegistry;
+    private volatile SharedHttpServiceImpl sharedHttpService;
+
     public HttpServiceFactory(final BundleContext bundleContext,
             final HandlerRegistry handlerRegistry)
     {
@@ -100,6 +102,8 @@
         this.sessionListenerManager.open();
         this.sessionAttributeListenerManager.open();
 
+        this.sharedHttpService = new SharedHttpServiceImpl(handlerRegistry.getRegistry(null));
+
         final String[] ifaces = new String[] { HttpService.class.getName(), ExtHttpService.class.getName() };
         this.httpServiceReg = bundleContext.registerService(ifaces, this, this.httpServiceProps);
     }
@@ -113,6 +117,8 @@
             this.httpServiceReg = null;
         }
 
+        this.sharedHttpService = null;
+
         this.contextAttributeListenerManager.close();
         this.requestListenerManager.close();
         this.requestAttributeListenerManager.close();
@@ -123,8 +129,9 @@
     @Override
     public HttpService getService(final Bundle bundle, final ServiceRegistration<HttpService> reg)
     {
-        return new HttpServiceImpl(bundle, this.context,
-                this.handlerRegistry.getRegistry(null),
+        return new PerBundleHttpServiceImpl(bundle,
+                this.sharedHttpService,
+                this.context,
                 this.contextAttributeListenerManager,
                 this.sharedContextAttributes,
                 this.requestListenerManager,
@@ -135,9 +142,9 @@
     public void ungetService(final Bundle bundle, final ServiceRegistration<HttpService> reg,
             final HttpService service)
     {
-        if ( service instanceof HttpServiceImpl )
+        if ( service instanceof PerBundleHttpServiceImpl )
         {
-            ((HttpServiceImpl)service).unregisterAll();
+            ((PerBundleHttpServiceImpl)service).unregisterAll();
         }
     }
 
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
similarity index 75%
rename from http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java
rename to http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
index bb5a128..7634f39 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
@@ -20,7 +20,6 @@
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -34,9 +33,6 @@
 
 import org.apache.felix.http.api.ExtHttpService;
 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.PerContextHandlerRegistry;
-import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
@@ -44,16 +40,26 @@
 import org.osgi.service.http.HttpContext;
 import org.osgi.service.http.NamespaceException;
 
-public final class HttpServiceImpl implements ExtHttpService
+/**
+ * This implementation of the {@link ExtHttpService} implements the front end
+ * used by client bundles. It performs the validity checks and passes the
+ * real operation to the shared http service.
+ */
+public final class PerBundleHttpServiceImpl implements ExtHttpService
 {
     private final Bundle bundle;
-    private final PerContextHandlerRegistry handlerRegistry;
     private final Set<Servlet> localServlets = new HashSet<Servlet>();
     private final Set<Filter> localFilters = new HashSet<Filter>();
     private final ServletContextManager contextManager;
-    private final Map<String, ServletHandler> aliasMap = new HashMap<String, ServletHandler>();
+    private final SharedHttpServiceImpl sharedHttpService;
 
-    public HttpServiceImpl(Bundle bundle, ServletContext context, PerContextHandlerRegistry handlerRegistry, ServletContextAttributeListener servletAttributeListener, boolean sharedContextAttributes, ServletRequestListener reqListener, ServletRequestAttributeListener reqAttrListener)
+    public PerBundleHttpServiceImpl(final Bundle bundle,
+            final SharedHttpServiceImpl sharedHttpService,
+            final ServletContext context,
+            final ServletContextAttributeListener servletAttributeListener,
+            final boolean sharedContextAttributes,
+            final ServletRequestListener reqListener,
+            final ServletRequestAttributeListener reqAttrListener)
     {
         if (bundle == null)
         {
@@ -63,14 +69,10 @@
         {
             throw new IllegalArgumentException("Context cannot be null!");
         }
-        if (handlerRegistry == null)
-        {
-            throw new IllegalArgumentException("HandlerRegistry cannot be null!");
-        }
 
         this.bundle = bundle;
-        this.handlerRegistry = handlerRegistry;
         this.contextManager = new ServletContextManager(this.bundle, context, servletAttributeListener, sharedContextAttributes, reqListener, reqAttrListener);
+        this.sharedHttpService = sharedHttpService;
     }
 
     @Override
@@ -83,7 +85,12 @@
      * @see org.apache.felix.http.api.ExtHttpService#registerFilter(javax.servlet.Filter, java.lang.String, java.util.Dictionary, int, org.osgi.service.http.HttpContext)
      */
     @Override
-    public void registerFilter(Filter filter, String pattern, Dictionary initParams, int ranking, HttpContext context) throws ServletException
+    public void registerFilter(final Filter filter,
+            final String pattern,
+            final Dictionary initParams,
+            final int ranking,
+            final HttpContext context)
+    throws ServletException
     {
         if (filter == null)
         {
@@ -114,16 +121,13 @@
 
         final ExtServletContext httpContext = getServletContext(context);
 
-        FilterHandler handler = new FilterHandler(null, httpContext, filter, filterInfo);
-        try
+        if ( this.sharedHttpService.registerFilter(httpContext, filter, filterInfo) )
         {
-            this.handlerRegistry.addFilter(handler);
+            synchronized ( this.localFilters )
+            {
+                this.localFilters.add(filter);
+            }
         }
-        catch (ServletException e)
-        {
-            // TODO create failure DTO
-        }
-        this.localFilters.add(filter);
     }
 
     /**
@@ -181,26 +185,33 @@
             }
         }
 
+        synchronized (this.localServlets)
+        {
+            if (this.localServlets.contains(servlet))
+            {
+                throw new ServletException("Servlet instance " + servlet + " already registered");
+            }
+            this.localServlets.add(servlet);
+        }
+
         final ServletInfo servletInfo = new ServletInfo(String.format("%s_%d", servlet.getClass(), this.hashCode()), alias, 0, paramMap);
         final ExtServletContext httpContext = getServletContext(context);
 
-        final ServletHandler handler = new ServletHandler(null, httpContext, servletInfo, servlet);
-
-        synchronized (this.aliasMap)
+        boolean success = false;
+        try
         {
-            if (this.aliasMap.containsKey(alias))
+            this.sharedHttpService.registerServlet(alias, httpContext,  servlet,  servletInfo);
+            success = true;
+        }
+        finally
+        {
+            if ( !success )
             {
-                throw new NamespaceException("Alias " + alias + " is already in use.");
+                synchronized ( this.localServlets )
+                {
+                    this.localServlets.remove(servlet);
+                }
             }
-            if (this.localServlets.contains(servlet))
-            {
-                throw new ServletException("Servlet instance " + handler.getName() + " already registered");
-            }
-
-            this.handlerRegistry.addServlet(handler);
-
-            this.aliasMap.put(alias, handler);
-            this.localServlets.add(servlet);
         }
     }
 
@@ -210,15 +221,10 @@
     @Override
     public void unregister(final String alias)
     {
-        synchronized (this.aliasMap)
+        final Servlet servlet = this.sharedHttpService.unregister(alias);
+        if ( servlet != null )
         {
-            final ServletHandler handler = this.aliasMap.remove(alias);
-            if (handler == null)
-            {
-                throw new IllegalArgumentException("Nothing registered at " + alias);
-            }
-            final Servlet servlet = this.handlerRegistry.removeServlet(handler.getServletInfo(), true);
-            if (servlet != null)
+            synchronized ( this.localServlets )
             {
                 this.localServlets.remove(servlet);
             }
@@ -245,9 +251,9 @@
      * @see org.apache.felix.http.api.ExtHttpService#unregisterFilter(javax.servlet.Filter)
      */
     @Override
-    public void unregisterFilter(Filter filter)
+    public void unregisterFilter(final Filter filter)
     {
-        unregisterFilter(filter, true);
+        this.unregisterFilter(filter, true);
     }
 
     /**
@@ -264,22 +270,11 @@
     {
         if (servlet != null)
         {
-            this.handlerRegistry.removeServlet(servlet, destroy);
-            synchronized (this.aliasMap)
+            synchronized ( this.localServlets )
             {
-                final Iterator<Map.Entry<String, ServletHandler>> i = this.aliasMap.entrySet().iterator();
-                while (i.hasNext())
-                {
-                    final Map.Entry<String, ServletHandler> entry = i.next();
-                    if (entry.getValue().getServlet() == servlet)
-                    {
-                        i.remove();
-                        break;
-                    }
-
-                }
                 this.localServlets.remove(servlet);
             }
+            this.sharedHttpService.unregisterServlet(servlet, destroy);
         }
     }
 
@@ -293,7 +288,19 @@
         return this.contextManager.getServletContext(context);
     }
 
-    private boolean isNameValid(String name)
+    private void unregisterFilter(Filter filter, final boolean destroy)
+    {
+        if (filter != null)
+        {
+            synchronized ( this.localFilters )
+            {
+                this.localFilters.remove(filter);
+            }
+            this.sharedHttpService.unregisterFilter(filter, destroy);
+        }
+    }
+
+    private boolean isNameValid(final String name)
     {
         if (name == null)
         {
@@ -308,15 +315,6 @@
         return true;
     }
 
-    private void unregisterFilter(Filter filter, final boolean destroy)
-    {
-        if (filter != null)
-        {
-            this.handlerRegistry.removeFilter(filter, destroy);
-            this.localFilters.remove(filter);
-        }
-    }
-
     private boolean isAliasValid(final String alias)
     {
         if (alias == 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
new file mode 100644
index 0000000..fc20fe8
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
@@ -0,0 +1,139 @@
+/*
+ * 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.service;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+
+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.PerContextHandlerRegistry;
+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.osgi.service.http.NamespaceException;
+
+public final class SharedHttpServiceImpl
+{
+    private final PerContextHandlerRegistry handlerRegistry;
+
+    private final Map<String, ServletHandler> aliasMap = new HashMap<String, ServletHandler>();
+
+    public SharedHttpServiceImpl(final PerContextHandlerRegistry handlerRegistry)
+    {
+        if (handlerRegistry == null)
+        {
+            throw new IllegalArgumentException("HandlerRegistry cannot be null!");
+        }
+
+        this.handlerRegistry = handlerRegistry;
+    }
+
+    /**
+     * Register a filter
+     */
+    public boolean registerFilter(@Nonnull final ExtServletContext httpContext,
+            @Nonnull final Filter filter,
+            @Nonnull final FilterInfo filterInfo)
+    {
+        final FilterHandler handler = new FilterHandler(null, httpContext, filter, filterInfo);
+        try
+        {
+            this.handlerRegistry.addFilter(handler);
+            return true;
+        }
+        catch (final ServletException e)
+        {
+            // TODO create failure DTO
+        }
+        return false;
+    }
+
+    /**
+     * Register a servlet
+     */
+    public void registerServlet(@Nonnull final String alias,
+            @Nonnull final ExtServletContext httpContext,
+            @Nonnull final Servlet servlet,
+            @Nonnull final ServletInfo servletInfo) throws ServletException, NamespaceException
+    {
+        final ServletHandler handler = new ServletHandler(null, httpContext, servletInfo, servlet);
+
+        synchronized (this.aliasMap)
+        {
+            if (this.aliasMap.containsKey(alias))
+            {
+                throw new NamespaceException("Alias " + alias + " is already in use.");
+            }
+            this.handlerRegistry.addServlet(handler);
+
+            this.aliasMap.put(alias, handler);
+        }
+    }
+
+    /**
+     * @see org.osgi.service.http.HttpService#unregister(java.lang.String)
+     */
+    public Servlet unregister(final String alias)
+    {
+        synchronized (this.aliasMap)
+        {
+            final ServletHandler handler = this.aliasMap.remove(alias);
+            if (handler == null)
+            {
+                throw new IllegalArgumentException("Nothing registered at " + alias);
+            }
+            return this.handlerRegistry.removeServlet(handler.getServletInfo(), true);
+        }
+    }
+
+    public void unregisterServlet(final Servlet servlet, final boolean destroy)
+    {
+        if (servlet != null)
+        {
+            this.handlerRegistry.removeServlet(servlet, destroy);
+            synchronized (this.aliasMap)
+            {
+                final Iterator<Map.Entry<String, ServletHandler>> i = this.aliasMap.entrySet().iterator();
+                while (i.hasNext())
+                {
+                    final Map.Entry<String, ServletHandler> entry = i.next();
+                    if (entry.getValue().getServlet() == servlet)
+                    {
+                        i.remove();
+                        break;
+                    }
+
+                }
+            }
+        }
+    }
+
+    public void unregisterFilter(final Filter filter, final boolean destroy)
+    {
+        if (filter != null)
+        {
+            this.handlerRegistry.removeFilter(filter, destroy);
+        }
+    }
+}