FELIX-4545 : Implement Servlet Context Helper

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1656012 13f79535-47bb-0310-9956-ffa450edef68
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/HttpServiceImpl.java
index 64cc5a8..d19b424 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/HttpServiceImpl.java
@@ -39,9 +39,11 @@
 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;
+import org.apache.felix.http.base.internal.whiteboard.HttpContextBridge;
 import org.osgi.framework.Bundle;
 import org.osgi.service.http.HttpContext;
 import org.osgi.service.http.NamespaceException;
+import org.osgi.service.http.context.ServletContextHelper;
 
 public final class HttpServiceImpl implements ExtHttpService
 {
@@ -187,17 +189,10 @@
     }
 
     /**
-     * TODO As the servlet can be registered with multiple patterns
-     *      we shouldn't pass the servlet object around in order to
-     *      be able to get different instances (prototype scope).
-     *      Or we do the splitting into single pattern registrations
-     *      already before calling registerServlet()
-     * @param servlet
-     * @param servletInfo
-     * @throws ServletException
-     * @throws NamespaceException
      */
-    public void registerServlet(final ServletInfo servletInfo)
+    public void registerServlet(final ServletContextHelper context,
+    		final String prefix,
+    		final ServletInfo servletInfo)
     {
         if (servletInfo == null)
         {
@@ -208,6 +203,15 @@
             throw new IllegalArgumentException("ServletInfo must at least have one pattern or error page!");
         }
 
+        final ExtServletContext httpContext;
+        if ( context != null )
+        {
+        	httpContext = getServletContext(new HttpContextBridge(context));
+        }
+        else
+        {
+        	httpContext = getServletContext(servletInfo.getContext());
+        }
         for(final String alias : servletInfo.getPatterns())
         {
             // create a handler for each alias
@@ -217,10 +221,11 @@
                 servlet = this.bundle.getBundleContext().getServiceObjects(servletInfo.getServiceReference()).getService();
                 // TODO - handle null
             }
-            final ServletHandler handler = new ServletHandler(getServletContext(servletInfo.getContext()),
+            final String pattern = (prefix == null ? alias : prefix + alias);
+            final ServletHandler handler = new ServletHandler(httpContext,
                     servletInfo,
                     servlet,
-                    alias);
+                    pattern);
             try {
                 this.handlerRegistry.addServlet(handler);
             } catch (ServletException e) {
@@ -292,7 +297,7 @@
 
         final ServletInfo info = new ServletInfo(null, alias, 0, paramMap, servlet, context);
 
-        this.registerServlet(info);
+        this.registerServlet(null, null, info);
     }
 
     @Override
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java
index 802ddd3..f4bb94c 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java
@@ -29,7 +29,7 @@
 
     private final ServletContextHelper delegatee;
 
-    HttpContextBridge(final ServletContextHelper delegatee)
+    public HttpContextBridge(final ServletContextHelper delegatee)
     {
         this.delegatee = delegatee;
     }
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 0c804b4..93d9498 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
@@ -20,10 +20,13 @@
 import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.felix.http.base.internal.runtime.AbstractInfo;
 import org.apache.felix.http.base.internal.runtime.ContextInfo;
@@ -47,6 +50,7 @@
     private final HttpServiceImpl httpService;
 
     private final ServiceRegistration<ServletContextHelper> defaultContextRegistration;
+    
     /**
      * Create a new servlet context helper manager
      * and the default context
@@ -95,7 +99,7 @@
             if ( entry.getKey().getContextSelectionFilter().match(holder.getInfo().getServiceReference()) )
             {
                 entry.getValue().add(holder);
-                this.httpService.registerServlet(entry.getKey());
+            	this.registerServlet(entry.getKey(), holder);
             }
         }
     }
@@ -108,7 +112,7 @@
             final Map.Entry<ServletInfo, List<ContextHolder>> entry = i.next();
             if ( entry.getValue().remove(holder) )
             {
-                this.httpService.unregisterServlet(entry.getKey());
+                this.unregisterServlet(entry.getKey(), holder);
                 if ( entry.getValue().isEmpty() ) {
                     i.remove();
                 }
@@ -199,6 +203,18 @@
         return result;
     }
 
+    private void registerServlet(final ServletInfo servletInfo, final ContextHolder holder)
+    {
+    	final ServletContextHelper helper = holder.getContext(servletInfo.getServiceReference().getBundle());
+    	String prefix = holder.getPrefix();
+        this.httpService.registerServlet(helper, prefix, servletInfo);    	
+    }
+
+    private void unregisterServlet(final ServletInfo servletInfo, final ContextHolder holder)
+    {
+        this.httpService.unregisterServlet(servletInfo);    	
+    }
+
     /**
      * Add a new servlet.
      * @param servletInfo The servlet info
@@ -211,7 +227,7 @@
             this.servletList.put(servletInfo, holderList);
             for(final ContextHolder h : holderList)
             {
-                this.httpService.registerServlet(servletInfo);
+            	this.registerServlet(servletInfo, h);
             }
         }
     }
@@ -229,7 +245,7 @@
             {
                 for(final ContextHolder h : holderList)
                 {
-                    this.httpService.unregisterServlet(servletInfo);
+                    this.unregisterServlet(servletInfo, h);
                 }
             }
         }
@@ -242,9 +258,19 @@
     {
         private final ContextInfo info;
 
+        private final String prefix;
+        
         public ContextHolder(final ContextInfo info)
         {
             this.info = info;
+            if ( info.getPath().equals("/") )
+            {
+            	prefix = null;
+            }
+            else
+            {
+            	prefix = info.getPath().substring(0, info.getPath().length() - 1);
+            }
         }
 
         public ContextInfo getInfo()
@@ -252,11 +278,22 @@
             return this.info;
         }
 
+        public String getPrefix() 
+        {
+        	return this.prefix;
+        }
+        
         @Override
         public int compareTo(final ContextHolder o)
         {
             return this.info.compareTo(o.info);
         }
+        
+        public ServletContextHelper getContext(final Bundle b) 
+        {
+        	// TODO - we should somehow keep track of these objects to later on dispose them
+        	return b.getBundleContext().getServiceObjects(this.info.getServiceReference()).getService();
+        }
     }
 
 }