felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r1655654 [1/2] - in /felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal: handler/ runtime/ service/ whiteboard/ whiteboard/tracker/
Date Thu, 29 Jan 2015 13:39:12 GMT
Author: cziegeler
Date: Thu Jan 29 13:39:11 2015
New Revision: 1655654

URL: http://svn.apache.org/r1655654
Log:
FELIX-4060 : Implement HTTP Service Update (RFC-189)

Added:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/AbstractMapping.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/DefaultHttpContext.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ExtenderManager.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FilterMapping.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextManager.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ResourceMapping.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletMapping.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/AbstractTracker.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/FilterTracker.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ResourceTracker.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletTracker.java   (with props)
Modified:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServicePlugin.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java?rev=1655654&r1=1655653&r2=1655654&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java Thu Jan 29 13:39:11 2015
@@ -16,7 +16,9 @@
  */
 package org.apache.felix.http.base.internal.handler;
 
-import static javax.servlet.http.HttpServletResponse.*;
+import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+
 import java.io.IOException;
 import java.util.regex.Pattern;
 
@@ -27,6 +29,7 @@ import javax.servlet.http.HttpServletReq
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
 
 public final class FilterHandler extends AbstractHandler implements Comparable<FilterHandler>
 {
@@ -42,6 +45,16 @@ public final class FilterHandler extends
         this.regex = Pattern.compile(pattern);
     }
 
+    public FilterHandler(ExtServletContext context, Filter filter, FilterInfo filterInfo)
+    {
+        // TODO
+        super(context, filterInfo.name);
+        this.filter = filter;
+        this.ranking = filterInfo.ranking;
+        this.regex = Pattern.compile(filterInfo.regexs[0]);
+    }
+
+    @Override
     public int compareTo(FilterHandler other)
     {
         if (other.ranking == this.ranking)
@@ -52,6 +65,7 @@ public final class FilterHandler extends
         return (other.ranking > this.ranking) ? 1 : -1;
     }
 
+    @Override
     public void destroy()
     {
         this.filter.destroy();
@@ -85,6 +99,7 @@ public final class FilterHandler extends
         }
     }
 
+    @Override
     public void init() throws ServletException
     {
         this.filter.init(new FilterConfigImpl(getName(), getContext(), getInitParams()));
@@ -109,7 +124,7 @@ public final class FilterHandler extends
         }
         else
         {
-            // FELIX-3988: If the response is not yet committed and still has the default 
+            // FELIX-3988: If the response is not yet committed and still has the default
             // status, we're going to override this and send an error instead.
             if (!res.isCommitted() && (res.getStatus() == SC_OK || res.getStatus() == 0))
             {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java?rev=1655654&r1=1655653&r2=1655654&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java Thu Jan 29 13:39:11 2015
@@ -121,6 +121,11 @@ public final class HandlerRegistry
         return aliasMap.get(alias);
     }
 
+    public void addErrorServlet(String errorPage, ServletHandler handler) throws ServletException
+    {
+        // TODO
+    }
+
     public void removeAll()
     {
         for (Iterator<ServletHandler> it = servletMap.values().iterator(); it.hasNext(); )

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServicePlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServicePlugin.java?rev=1655654&r1=1655653&r2=1655654&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServicePlugin.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpServicePlugin.java Thu Jan 29 13:39:11 2015
@@ -19,20 +19,22 @@
 
 package org.apache.felix.http.base.internal.handler;
 
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceRegistration;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Hashtable;
 
 import javax.servlet.Servlet;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.Properties;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceRegistration;
 
 @SuppressWarnings("serial")
 public class HttpServicePlugin extends HttpServlet
@@ -51,7 +53,7 @@ public class HttpServicePlugin extends H
 
     public void register()
     {
-        Properties props = new Properties();
+        final Dictionary<String, Object> props = new Hashtable<String, Object>();
         props.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
         props.put(Constants.SERVICE_DESCRIPTION, "HTTP Service Web Console Plugin");
         props.put("felix.webconsole.label", "httpservice");

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java?rev=1655654&r1=1655653&r2=1655654&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandler.java Thu Jan 29 13:39:11 2015
@@ -43,6 +43,7 @@ import javax.servlet.http.HttpServletReq
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
 
 /**
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
@@ -73,6 +74,7 @@ public final class ServletHandler extend
             this.named = false;
         }
 
+        @Override
         public void forward(ServletRequest req, ServletResponse res) throws ServletException, IOException
         {
             if (res.isCommitted())
@@ -98,6 +100,7 @@ public final class ServletHandler extend
             }
         }
 
+        @Override
         public void include(ServletRequest req, ServletResponse res) throws ServletException, IOException
         {
             // Since we're already created this RequestDispatcher for *this* servlet handler, we do not need to
@@ -241,6 +244,15 @@ public final class ServletHandler extend
         this.servlet = servlet;
     }
 
+    public ServletHandler(ExtServletContext context, Servlet servlet, ServletInfo servletInfo)
+    {
+        // TODO
+        super(context, servletInfo.name);
+        this.servlet = servlet;
+        this.alias = servletInfo.patterns[0];
+    }
+
+    @Override
     public int compareTo(ServletHandler other)
     {
         return other.alias.length() - this.alias.length();
@@ -256,6 +268,7 @@ public final class ServletHandler extend
         return new RequestDispatcherImpl(path, pathInContext, query);
     }
 
+    @Override
     public void destroy()
     {
         this.servlet.destroy();
@@ -300,6 +313,7 @@ public final class ServletHandler extend
         return matches;
     }
 
+    @Override
     public void init() throws ServletException
     {
         this.servlet.init(new ServletConfigImpl(getName(), getContext(), getInitParams()));

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,104 @@
+/*
+ * 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 java.util.Map;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+
+import org.osgi.dto.DTO;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.runtime.dto.FilterDTO;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * Provides registration information for a {@link Filter}, and is used to programmatically register {@link Filter}s.
+ * <p>
+ * This class only provides information used at registration time, and as such differs slightly from {@link DTO}s like, {@link FilterDTO}.
+ * </p>
+ *
+ * TODO - we should move this to the same place as {@link ExtHttpServiceRuntime}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@ConsumerType
+public final class FilterInfo
+{
+    /**
+     * The name of the servlet.
+     */
+    public String name;
+
+    /**
+     * The request mappings for the servlet.
+     * <p>
+     * The specified patterns are used to determine whether a request is mapped to the servlet filter.<br>
+     * Note that these patterns should conform to the Servlet specification.
+     * </p>
+     */
+    public String[] patterns;
+
+    /**
+     * The servlet names for the servlet filter.
+     * <p>
+     * The specified names are used to determine the servlets whose requests are mapped to the servlet filter.
+     * </p>
+     */
+    public String[] servletNames;
+
+    /**
+     * The request mappings for the servlet filter.
+     * <p>
+     * The specified regular expressions are used to determine whether a request is mapped to the servlet filter.<br>
+     * These regular expressions are a convenience extension allowing one to specify filters that match paths that are difficult to match with plain Servlet patterns alone.
+     * </p>
+     */
+    public String[] regexs;
+
+    /**
+     * Specifies whether the servlet filter supports asynchronous processing.
+     */
+    public boolean asyncSupported = false;
+
+    /**
+     * Specifies the ranking order in which this filter should be called. Higher rankings are called first.
+     */
+    public int ranking = 0;
+
+    /**
+     * The dispatcher associations for the servlet filter.
+     * <p>
+     * The specified names are used to determine in what occasions the servlet filter is called.
+     * See {@link DispatcherType} and Servlet 3.0 specification, section 6.2.5.
+     * </p>
+     */
+    public DispatcherType[] dispatcher = { DispatcherType.REQUEST };
+
+    /**
+     * The filter initialization parameters as provided during registration of the filter.
+     */
+    public Map<String, String> initParams;
+
+    /**
+     * The {@link HttpContext} for the servlet.
+     */
+    public HttpContext context;
+
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,76 @@
+/*
+ * 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 java.util.Map;
+
+import javax.servlet.Servlet;
+
+import org.osgi.dto.DTO;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.runtime.dto.ServletDTO;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * Provides registration information for a {@link Servlet}, and is used to programmatically register {@link Servlet}s.
+ * <p>
+ * This class only provides information used at registration time, and as such differs slightly from {@link DTO}s like, {@link ServletDTO}.
+ * </p>
+ *
+ * TODO - we should move this to the same place as {@link ExtHttpServiceRuntime}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@ConsumerType
+public final class ServletInfo
+{
+    /**
+     * The name of the servlet.
+     */
+    public String name;
+
+    /**
+     * The request mappings for the servlet.
+     * <p>
+     * The specified patterns are used to determine whether a request is mapped to the servlet.
+     * </p>
+     */
+    public String[] patterns;
+
+    /**
+     * The error pages and/or codes.
+     */
+    public String[] errorPage;
+
+    /**
+     * Specifies whether the servlet supports asynchronous processing.
+     */
+    public boolean asyncSupported = false;
+
+    /**
+     * The servlet initialization parameters as provided during registration of the servlet.
+     */
+    public Map<String, String> initParams;
+
+    /**
+     * The {@link HttpContext} for the servlet.
+     */
+    public HttpContext context;
+
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java?rev=1655654&r1=1655653&r2=1655654&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceImpl.java Thu Jan 29 13:39:11 2015
@@ -17,7 +17,10 @@
 package org.apache.felix.http.base.internal.service;
 
 import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 
 import javax.servlet.Filter;
 import javax.servlet.Servlet;
@@ -32,6 +35,8 @@ import org.apache.felix.http.base.intern
 import org.apache.felix.http.base.internal.handler.HandlerRegistry;
 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;
 import org.osgi.framework.Bundle;
 import org.osgi.service.http.HttpContext;
 import org.osgi.service.http.NamespaceException;
@@ -53,16 +58,85 @@ public final class HttpServiceImpl imple
         this.contextManager = new ServletContextManager(this.bundle, context, servletAttributeListener, sharedContextAttributes);
     }
 
-    private ExtServletContext getServletContext(HttpContext context)
+    static Map<String, String> convertToMap(Dictionary dict)
     {
-        if (context == null)
+        Map<String, String> result = new HashMap<String, String>();
+        if (dict != null)
         {
-            context = createDefaultHttpContext();
+            Enumeration keyEnum = dict.keys();
+            while (keyEnum.hasMoreElements())
+            {
+                String key = String.valueOf(keyEnum.nextElement());
+                Object value = dict.get(key);
+                result.put(key, value == null ? null : String.valueOf(value));
+            }
         }
+        return result;
+    }
 
-        return this.contextManager.getServletContext(context);
+    static <T> boolean isEmpty(T[] array)
+    {
+        return array == null || array.length < 1;
     }
 
+    static boolean isEmpty(String str)
+    {
+        return str == null || "".equals(str.trim());
+    }
+
+    @Override
+    public HttpContext createDefaultHttpContext()
+    {
+        return new DefaultHttpContext(this.bundle);
+    }
+
+    public void registerFilter(Filter filter, FilterInfo filterInfo) throws ServletException
+    {
+        if (filter == null)
+        {
+            throw new IllegalArgumentException("Filter cannot be null!");
+        }
+        if (filterInfo == null)
+        {
+            throw new IllegalArgumentException("FilterInfo cannot be null!");
+        }
+        if (isEmpty(filterInfo.patterns) && isEmpty(filterInfo.regexs) && isEmpty(filterInfo.servletNames))
+        {
+            throw new IllegalArgumentException("FilterInfo must have at least one pattern or regex, or provide at least one servlet name!");
+        }
+        if (isEmpty(filterInfo.name))
+        {
+            filterInfo.name = filter.getClass().getName();
+        }
+
+        ExtServletContext servletContext = getServletContext(filterInfo.context);
+
+        try
+        {
+            FilterHandler handler = new FilterHandler(servletContext, filter, filterInfo);
+
+            synchronized (this)
+            {
+                if (this.localFilters.add(filter))
+                {
+                    this.handlerRegistry.addFilter(handler);
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            if (e instanceof ServletException)
+            {
+                throw (ServletException) e;
+            }
+            else
+            {
+                throw new ServletException("Failed to register filter " + filterInfo.name, e);
+            }
+        }
+    }
+
+    @Override
     public void registerFilter(Filter filter, String pattern, Dictionary initParams, int ranking, HttpContext context) throws ServletException
     {
         if (filter == null)
@@ -76,14 +150,80 @@ public final class HttpServiceImpl imple
         this.localFilters.add(filter);
     }
 
-    public void unregisterFilter(Filter filter)
+    @Override
+    public void registerResources(String alias, String name, HttpContext context) throws NamespaceException
     {
-        unregisterFilter(filter, true);
+        if (!isNameValid(name))
+        {
+            throw new IllegalArgumentException("Malformed resource name [" + name + "]");
+        }
+
+        try
+        {
+            Servlet servlet = new ResourceServlet(name);
+            registerServlet(alias, servlet, null, context);
+        }
+        catch (ServletException e)
+        {
+            SystemLogger.error("Failed to register resources", e);
+        }
     }
 
-    public void unregisterServlet(Servlet servlet)
+    public void registerServlet(Servlet servlet, ServletInfo servletInfo) throws ServletException, NamespaceException
     {
-        unregisterServlet(servlet, true);
+        if (servlet == null)
+        {
+            throw new IllegalArgumentException("Servlet cannot be null!");
+        }
+        if (servletInfo == null)
+        {
+            throw new IllegalArgumentException("ServletInfo cannot be null!");
+        }
+        if (isEmpty(servletInfo.patterns) && isEmpty(servletInfo.errorPage))
+        {
+            throw new IllegalArgumentException("ServletInfo must at least have one pattern or error page!");
+        }
+        if (isEmpty(servletInfo.name))
+        {
+            servletInfo.name = servlet.getClass().getName();
+        }
+
+        ExtServletContext servletContext = getServletContext(servletInfo.context);
+
+        try
+        {
+            ServletHandler handler = new ServletHandler(servletContext, servlet, servletInfo);
+
+            synchronized (this)
+            {
+                if (this.localServlets.add(servlet))
+                {
+                    this.handlerRegistry.addServlet(handler);
+                    if (servletInfo.errorPage != null && servletInfo.errorPage.length != 0)
+                    {
+                        for (String errorPage : servletInfo.errorPage)
+                        {
+                            this.handlerRegistry.addErrorServlet(errorPage, handler);
+                        }
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            if (e instanceof ServletException)
+            {
+                throw (ServletException) e;
+            }
+            else if (e instanceof NamespaceException)
+            {
+                throw (NamespaceException) e;
+            }
+            else
+            {
+                throw new ServletException("Failed to register servlet " + servletInfo.name, e);
+            }
+        }
     }
 
     public void registerServlet(String alias, Servlet servlet, Dictionary initParams, HttpContext context) throws ServletException, NamespaceException
@@ -103,24 +243,6 @@ public final class HttpServiceImpl imple
         this.localServlets.add(servlet);
     }
 
-    public void registerResources(String alias, String name, HttpContext context) throws NamespaceException
-    {
-        if (!isNameValid(name))
-        {
-            throw new IllegalArgumentException("Malformed resource name [" + name + "]");
-        }
-
-        try
-        {
-            Servlet servlet = new ResourceServlet(name);
-            registerServlet(alias, servlet, null, context);
-        }
-        catch (ServletException e)
-        {
-            SystemLogger.error("Failed to register resources", e);
-        }
-    }
-
     public void unregister(String alias)
     {
         final Servlet servlet = this.handlerRegistry.getServletByAlias(alias);
@@ -139,11 +261,6 @@ public final class HttpServiceImpl imple
         unregisterServlet(servlet);
     }
 
-    public HttpContext createDefaultHttpContext()
-    {
-        return new DefaultHttpContext(this.bundle);
-    }
-
     public void unregisterAll()
     {
         HashSet<Servlet> servlets = new HashSet<Servlet>(this.localServlets);
@@ -159,22 +276,26 @@ public final class HttpServiceImpl imple
         }
     }
 
-    private void unregisterFilter(Filter filter, final boolean destroy)
+    @Override
+    public void unregisterFilter(Filter filter)
     {
-        if (filter != null)
-        {
-            this.handlerRegistry.removeFilter(filter, destroy);
-            this.localFilters.remove(filter);
-        }
+        unregisterFilter(filter, true);
     }
 
-    private void unregisterServlet(Servlet servlet, final boolean destroy)
+    @Override
+    public void unregisterServlet(Servlet servlet)
     {
-        if (servlet != null)
+        unregisterServlet(servlet, true);
+    }
+
+    private ExtServletContext getServletContext(HttpContext context)
+    {
+        if (context == null)
         {
-            this.handlerRegistry.removeServlet(servlet, destroy);
-            this.localServlets.remove(servlet);
+            context = createDefaultHttpContext();
         }
+
+        return this.contextManager.getServletContext(context);
     }
 
     private boolean isNameValid(String name)
@@ -192,6 +313,24 @@ public final class HttpServiceImpl imple
         return true;
     }
 
+    private void unregisterFilter(Filter filter, final boolean destroy)
+    {
+        if (filter != null)
+        {
+            this.handlerRegistry.removeFilter(filter, destroy);
+            this.localFilters.remove(filter);
+        }
+    }
+
+    private void unregisterServlet(Servlet servlet, final boolean destroy)
+    {
+        if (servlet != null)
+        {
+            this.handlerRegistry.removeServlet(servlet, destroy);
+            this.localServlets.remove(servlet);
+        }
+    }
+    
     private boolean isAliasValid(String alias)
     {
         if (alias == null)

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,77 @@
+/*
+ * 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 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;
+    }
+
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/AbstractMapping.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/AbstractMapping.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/AbstractMapping.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/AbstractMapping.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,74 @@
+/*
+ * 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.whiteboard;
+
+import java.util.Hashtable;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+
+abstract class AbstractMapping
+{
+    private final Bundle bundle;
+    private HttpContext context;
+    private final Hashtable<String, String> initParams;
+    private boolean registered;
+
+    protected AbstractMapping(final Bundle bundle)
+    {
+        this.bundle = bundle;
+        this.context = null;
+        this.initParams = new Hashtable<String, String>();
+        this.registered = false;
+    }
+
+    public Bundle getBundle()
+    {
+        return bundle;
+    }
+
+    public void setContext(HttpContext context)
+    {
+        this.context = context;
+    }
+
+    public final HttpContext getContext()
+    {
+        return this.context;
+    }
+
+    public final Hashtable<String, String> getInitParams()
+    {
+        return this.initParams;
+    }
+
+    boolean isRegistered()
+    {
+        return registered;
+    }
+
+    void setRegistered(boolean registered)
+    {
+        this.registered = registered;
+    }
+
+    public abstract void register(HttpService httpService);
+
+    public abstract void unregister(HttpService httpService);
+
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/AbstractMapping.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/AbstractMapping.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/DefaultHttpContext.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/DefaultHttpContext.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/DefaultHttpContext.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/DefaultHttpContext.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,59 @@
+/*
+ * 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.whiteboard;
+
+import org.osgi.service.http.HttpContext;
+import org.osgi.framework.Bundle;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.net.URL;
+
+public final class DefaultHttpContext
+    implements HttpContext
+{
+    private Bundle bundle;
+
+    public DefaultHttpContext(Bundle bundle)
+    {
+        this.bundle = bundle;
+    }
+
+    public String getMimeType(String name)
+    {
+        return null;
+    }
+
+    public URL getResource(String name)
+    {
+        if (name.startsWith("/")) {
+            name = name.substring(1);
+        }
+
+        return this.bundle.getResource(name);
+    }
+
+    public boolean handleSecurity(HttpServletRequest req, HttpServletResponse res)
+    {
+        return true;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getClass().getSimpleName() + " (" + Integer.toHexString(System.identityHashCode(this)) + ")";
+    }
+}
\ No newline at end of file

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/DefaultHttpContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/DefaultHttpContext.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ExtenderManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ExtenderManager.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ExtenderManager.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ExtenderManager.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,453 @@
+/*
+ * 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.whiteboard;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+
+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.HttpContextManager.HttpContextHolder;
+import org.apache.felix.http.base.internal.whiteboard.tracker.FilterTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.ServletContextHelperTracker;
+import org.apache.felix.http.base.internal.whiteboard.tracker.ServletTracker;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.context.ServletContextHelper;
+import org.osgi.service.http.runtime.dto.ResourceDTO;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
+import org.osgi.util.tracker.ServiceTracker;
+
+@SuppressWarnings({ "deprecation" })
+public final class ExtenderManager
+{
+    static final String TYPE_FILTER = "f";
+    static final String TYPE_SERVLET = "s";
+    static final String TYPE_RESOURCE = "r";
+
+    /**
+     * Properties starting with this prefix are passed as servlet init parameters to the
+     * {@code init()} method of the servlet.
+     */
+    public static final String SERVLET_INIT_PREFIX = "servlet.init.";
+
+    /**
+     * Properties starting with this prefix are passed as filter
+     * init parameters to the {@code init()} method of the filter.
+     */
+    public static final String FILTER_INIT_PREFIX = "filter.init.";
+
+    private final Map<String, AbstractMapping> mapping;
+    private final HttpContextManager contextManager;
+
+    private final HttpService httpService;
+
+    private final ArrayList<ServiceTracker> trackers = new ArrayList<ServiceTracker>();
+
+    public ExtenderManager(final HttpService httpService, final BundleContext bundleContext)
+    {
+        this.mapping = new HashMap<String, AbstractMapping>();
+        this.contextManager = new HttpContextManager();
+        this.httpService = httpService;
+        addTracker(new FilterTracker(bundleContext, this));
+        addTracker(new ServletTracker(bundleContext, this));
+        addTracker(new ServletContextHelperTracker(bundleContext, this));
+    }
+
+    public void close()
+    {
+        for(final ServiceTracker t : this.trackers)
+        {
+            t.close();
+        }
+        this.trackers.clear();
+        this.unregisterAll();
+    }
+
+    private void addTracker(ServiceTracker tracker)
+    {
+        this.trackers.add(tracker);
+        tracker.open();
+    }
+
+    static boolean isEmpty(final String value)
+    {
+        return value == null || value.length() == 0;
+    }
+
+    static boolean isEmpty(final String[] value)
+    {
+        return value == null || value.length == 0;
+    }
+
+    private String getStringProperty(ServiceReference ref, String key)
+    {
+        Object value = ref.getProperty(key);
+        return (value instanceof String) ? (String) value : null;
+    }
+
+    private String[] getStringArrayProperty(ServiceReference ref, String key)
+    {
+        Object value = ref.getProperty(key);
+
+        if (value instanceof String)
+        {
+            return new String[] { (String) value };
+        }
+        else if (value instanceof String[])
+        {
+            return (String[]) value;
+        }
+        else if (value instanceof Collection<?>)
+        {
+            Collection<?> collectionValues = (Collection<?>) value;
+            String[] values = new String[collectionValues.size()];
+
+            int i = 0;
+            for (Object current : collectionValues)
+            {
+                values[i++] = current != null ? String.valueOf(current) : null;
+            }
+
+            return values;
+        }
+
+        return null;
+    }
+
+    private boolean getBooleanProperty(ServiceReference ref, String key)
+    {
+        Object value = ref.getProperty(key);
+        if (value instanceof String)
+        {
+            return Boolean.valueOf((String) value);
+        }
+        else if (value instanceof Boolean)
+        {
+            return ((Boolean) value).booleanValue();
+        }
+        return false;
+    }
+
+    private int getIntProperty(ServiceReference ref, String key, int defValue)
+    {
+        Object value = ref.getProperty(key);
+        if (value == null)
+        {
+            return defValue;
+        }
+
+        try
+        {
+            return Integer.parseInt(value.toString());
+        }
+        catch (Exception e)
+        {
+            return defValue;
+        }
+    }
+
+    private void addInitParams(ServiceReference ref, AbstractMapping mapping)
+    {
+        for (String key : ref.getPropertyKeys())
+        {
+            String prefixKey = null;
+
+            if (mapping instanceof FilterMapping && key.startsWith(FILTER_INIT_PREFIX))
+            {
+                prefixKey = FILTER_INIT_PREFIX;
+            }
+            else if (mapping instanceof ServletMapping && key.startsWith(SERVLET_INIT_PREFIX))
+            {
+                prefixKey = SERVLET_INIT_PREFIX;
+            }
+
+            if (prefixKey != null)
+            {
+                String paramKey = key.substring(prefixKey.length());
+                String paramValue = getStringProperty(ref, key);
+
+                if (paramValue != null)
+                {
+                    mapping.getInitParams().put(paramKey, paramValue);
+                }
+            }
+        }
+    }
+
+    public void add(ServletContextHelper service, ServiceReference ref)
+    {
+        String name = getStringProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME);
+        String path = getStringProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH);
+
+        // TODO - check if name and path are valid values
+        if (!isEmpty(name) && !isEmpty(path) )
+        {
+            Collection<AbstractMapping> mappings = this.contextManager.addContextHelper(ref.getBundle(), name, path, service);
+            for (AbstractMapping mapping : mappings)
+            {
+                registerMapping(mapping);
+            }
+        }
+        else
+        {
+            SystemLogger.debug("Ignoring ServletContextHelper Service " + ref + ", " + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + " is missing or empty");
+        }
+    }
+
+    public void addResource(final ServiceReference ref)
+    {
+        final String[] pattern = getStringArrayProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN);
+        final String prefix = getStringProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX);
+
+        if (!isEmpty(pattern))
+        {
+            if ( !isEmpty(prefix))
+            {
+                for(final String p : pattern)
+                {
+                    // TODO : check if p is empty - and then log?
+                    final ResourceDTO resourceDTO = new ResourceDTO();
+                    resourceDTO.patterns = new String[] {p};
+                    resourceDTO.prefix = prefix;
+                    final ResourceMapping mapping = new ResourceMapping(ref.getBundle(), resourceDTO);
+                    this.addMapping(TYPE_RESOURCE, ref, mapping);
+                }
+            }
+            else
+            {
+                SystemLogger.debug("Ignoring Resource Service " + ref + ", " + HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PREFIX + " is missing or empty");
+            }
+        }
+        else
+        {
+            SystemLogger.debug("Ignoring Resource Service " + ref + ", " + HttpWhiteboardConstants.HTTP_WHITEBOARD_RESOURCE_PATTERN + " is missing or empty");
+        }
+    }
+
+    public void removeResource(final ServiceReference ref)
+    {
+        this.removeMapping(TYPE_RESOURCE, ref);
+    }
+
+    public void remove(ServletContextHelper service)
+    {
+        Collection<AbstractMapping> mappings = this.contextManager.removeContextHelper(service);
+        if (mappings != null)
+        {
+            for (AbstractMapping mapping : mappings)
+            {
+                unregisterMapping(mapping);
+            }
+        }
+    }
+
+    private HttpContext getHttpContext(AbstractMapping mapping, ServiceReference ref)
+    {
+        Bundle bundle = ref.getBundle();
+        String contextName = getStringProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT);
+        if (!isEmpty(contextName))
+        {
+            return this.contextManager.getHttpContext(bundle, contextName, mapping, true);
+        }
+        return this.contextManager.getHttpContext(bundle, null, mapping);
+    }
+
+    private void ungetHttpContext(AbstractMapping mapping, ServiceReference ref)
+    {
+        Bundle bundle = ref.getBundle();
+        String contextName = getStringProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT);
+        if (!isEmpty(contextName))
+        {
+            this.contextManager.ungetHttpContext(bundle, contextName, mapping, true);
+            return;
+        }
+        this.contextManager.ungetHttpContext(bundle, null, mapping);
+    }
+
+    public void add(final Filter service, final ServiceReference ref)
+    {
+        FilterInfo filterInfo = new FilterInfo();
+        filterInfo.name = getStringProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_NAME);
+        if ( filterInfo.name == null || filterInfo.name.isEmpty() )
+        {
+            filterInfo.name = service.getClass().getName();
+        }
+        filterInfo.asyncSupported = getBooleanProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_ASYNC_SUPPORTED);
+        filterInfo.servletNames = getStringArrayProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_SERVLET);
+        filterInfo.patterns = getStringArrayProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN);
+        filterInfo.ranking = getIntProperty(ref, Constants.SERVICE_RANKING, 0);
+
+        String[] dispatcherNames = getStringArrayProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_DISPATCHER);
+        if (dispatcherNames != null && dispatcherNames.length > 0)
+        {
+            DispatcherType[] dispatchers = new DispatcherType[dispatcherNames.length];
+            for (int i = 0; i < dispatchers.length; i++)
+            {
+                dispatchers[i] = DispatcherType.valueOf(dispatcherNames[i].toUpperCase());
+            }
+            filterInfo.dispatcher = dispatchers;
+        }
+
+        if (isEmpty(filterInfo.patterns))
+        {
+            SystemLogger.debug("Ignoring Filter Service " + ref + ", " + HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN +
+                    " is missing or empty");
+            return;
+        }
+
+        FilterMapping mapping = new FilterMapping(ref.getBundle(), service, filterInfo);
+        filterInfo.context = getHttpContext(mapping, ref); // XXX
+        addInitParams(ref, mapping);
+        addMapping(TYPE_FILTER, ref, mapping);
+    }
+
+    public void add(Servlet service, ServiceReference ref)
+    {
+        ServletInfo servletInfo = new ServletInfo();
+        servletInfo.name = getStringProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_NAME);
+        if ( servletInfo.name == null || servletInfo.name.isEmpty() )
+        {
+            servletInfo.name = service.getClass().getName();
+        }
+        servletInfo.errorPage = getStringArrayProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ERROR_PAGE);
+        servletInfo.patterns = getStringArrayProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN);
+        servletInfo.asyncSupported = getBooleanProperty(ref, HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED);
+
+        if (isEmpty(servletInfo.patterns))
+        {
+            SystemLogger.debug("Ignoring Servlet Service " + ref + ", " + HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN +
+                    "is missing or empty");
+            return;
+        }
+
+        final ServletMapping mapping = new ServletMapping(ref.getBundle(), service, servletInfo);
+        servletInfo.context = getHttpContext(mapping, ref); // XXX
+        addInitParams(ref, mapping);
+        addMapping(TYPE_SERVLET, ref, mapping);
+    }
+
+    public void removeFilter(ServiceReference ref)
+    {
+        removeMapping(TYPE_FILTER, ref);
+    }
+
+    public void removeServlet(ServiceReference ref)
+    {
+        removeMapping(TYPE_SERVLET, ref);
+    }
+
+    private synchronized void unregisterAll()
+    {
+        AbstractMapping[] mappings = null;
+        HttpService service;
+        synchronized (this)
+        {
+            service = this.httpService;
+            if (service != null)
+            {
+                Collection<AbstractMapping> values = this.mapping.values();
+                mappings = values.toArray(new AbstractMapping[values.size()]);
+            }
+        }
+        if (mappings != null)
+        {
+            for (AbstractMapping mapping : mappings)
+            {
+                mapping.unregister(service);
+            }
+        }
+    }
+
+    private synchronized void addMapping(final String servType, ServiceReference ref, AbstractMapping mapping)
+    {
+        this.mapping.put(ref.getProperty(Constants.SERVICE_ID).toString().concat(servType), mapping);
+        this.registerMapping(mapping);
+    }
+
+    private synchronized void removeMapping(final String servType, ServiceReference ref)
+    {
+        AbstractMapping mapping = this.mapping.remove(ref.getProperty(Constants.SERVICE_ID).toString().concat(servType));
+        if (mapping != null)
+        {
+            ungetHttpContext(mapping, ref);
+            unregisterMapping(mapping);
+        }
+    }
+
+    private void registerMapping(AbstractMapping mapping)
+    {
+        HttpService httpService = this.httpService;
+        if (httpService != null)
+        {
+            mapping.register(httpService);
+        }
+    }
+
+    private void unregisterMapping(AbstractMapping mapping)
+    {
+        HttpService httpService = this.httpService;
+        if (httpService != null)
+        {
+            mapping.unregister(httpService);
+        }
+    }
+
+    /**
+     * Returns
+     * {@link org.apache.felix.http.base.internal.whiteboard.whiteboard.internal.manager.HttpContextManager.HttpContextHolder}
+     * instances of HttpContext services.
+     *
+     * @return
+     */
+    Map<String, HttpContextHolder> getHttpContexts()
+    {
+        return this.contextManager.getHttpContexts();
+    }
+
+    /**
+     * Returns {@link AbstractMapping} instances for which there is no
+     * registered HttpContext as desired by the context ID.
+     */
+    Map<String, Set<AbstractMapping>> getOrphanMappings()
+    {
+        return this.contextManager.getOrphanMappings();
+    }
+
+    /**
+     * Returns mappings indexed by there owning OSGi service.
+     */
+    Map<String, AbstractMapping> getMappings()
+    {
+        synchronized (this)
+        {
+            return new HashMap<String, AbstractMapping>(this.mapping);
+        }
+    }
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ExtenderManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ExtenderManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FilterMapping.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FilterMapping.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FilterMapping.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FilterMapping.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,110 @@
+/*
+ * 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.whiteboard;
+
+import javax.servlet.Filter;
+
+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.service.HttpServiceImpl;
+import org.osgi.framework.Bundle;
+import org.osgi.service.http.HttpService;
+
+public final class FilterMapping extends AbstractMapping
+{
+    private final Filter filter;
+    private final FilterInfo filterInfo;
+
+    public FilterMapping(Bundle bundle, Filter filter, FilterInfo filterInfo)
+    {
+        super(bundle);
+        this.filter = filter;
+        this.filterInfo = filterInfo;
+    }
+
+    @Override
+    public void register(HttpService httpService)
+    {
+        if (!isRegistered() && (httpService instanceof HttpServiceImpl) && getContext() != null)
+        {
+            register((HttpServiceImpl) httpService);
+        }
+        else
+        {
+            // Warn the user that something strange is going on...
+            SystemLogger.warning("Unable to register filter for " + this.filterInfo.name + ", as no ExtHttpService seems to be present!", null);
+        }
+    }
+
+    @Override
+    public void unregister(HttpService httpService)
+    {
+        if (isRegistered() && (httpService instanceof HttpServiceImpl))
+        {
+            unregister((HttpServiceImpl) httpService);
+        }
+        else
+        {
+            // Warn the user that something strange is going on...
+            SystemLogger.warning("Unable to unregister filter for " + this.filterInfo.name + ", as no ExtHttpService seems to be present!", null);
+        }
+    }
+
+    Filter getFilter()
+    {
+        return filter;
+    }
+
+    private void register(HttpServiceImpl httpService)
+    {
+        if (!isRegistered() && getContext() != null)
+        {
+            try
+            {
+                httpService.registerFilter(this.filter, this.filterInfo);
+                setRegistered(true);
+            }
+            catch (Exception e)
+            {
+                // Warn that something might have gone astray...
+                SystemLogger.warning("Failed to register filter for " + this.filterInfo.name, null);
+                SystemLogger.debug("Failed to register filter for " + this.filterInfo.name + "; details:", e);
+            }
+        }
+    }
+
+    private void unregister(HttpServiceImpl httpService)
+    {
+        if (isRegistered())
+        {
+            try
+            {
+                httpService.unregisterFilter(this.filter);
+            }
+            catch (Exception e)
+            {
+                // Warn that something might have gone astray...
+                SystemLogger.debug("Failed to unregister filter for " + this.filterInfo.name, e);
+            }
+            finally
+            {
+                // Best effort: avoid mappings that are registered which is reality aren't registered...
+                setRegistered(false);
+            }
+        }
+    }
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FilterMapping.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FilterMapping.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,71 @@
+/*
+ * 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.whiteboard;
+
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.context.ServletContextHelper;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Set;
+
+public class HttpContextBridge extends ServletContextHelper implements HttpContext {
+
+    private final ServletContextHelper delegatee;
+
+    HttpContextBridge(final ServletContextHelper delegatee)
+    {
+        this.delegatee = delegatee;
+    }
+
+    @Override
+    public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException
+    {
+        return delegatee.handleSecurity(request, response);
+    }
+
+    @Override
+    public URL getResource(String name)
+    {
+        return delegatee.getResource(name);
+    }
+
+    @Override
+    public String getMimeType(String name)
+    {
+        return delegatee.getMimeType(name);
+    }
+
+    @Override
+    public Set<String> getResourcePaths(String path)
+    {
+        return delegatee.getResourcePaths(path);
+    }
+
+    @Override
+    public String getRealPath(String path)
+    {
+        return delegatee.getRealPath(path);
+    }
+
+    public ServletContextHelper getDelegatee()
+    {
+        return delegatee;
+    }
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextBridge.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextManager.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextManager.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextManager.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,357 @@
+/*
+ * 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.whiteboard;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.http.base.internal.logger.SystemLogger;
+import org.osgi.framework.Bundle;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.context.ServletContextHelper;
+
+public final class HttpContextManager
+{
+    /**
+     * HttpContextHolders indexed by context ID fully configured
+     * with an HttpContext and optional servlets and filters.
+     * <p>
+     * The context ID either includes the bundle ID as the first part of the
+     * name, such as <i>123-sample.context</i> in the case of non-shared
+     * contexts. IDs of shared contexts are prefixed with the fixed string
+     * <code>shared</code> to not mix them with per-bundle contexts.
+     */
+    private final HashMap<String, HttpContextHolder> idMap;
+
+    /**
+     * Reverse mapping of HttpContext services to the context ID or
+     * name with which they are registered.
+     */
+    private final HashMap<HttpContext, String> contextMap;
+
+    /**
+     * Mapping of registered ServletContextHelper services to the
+     * HttpContext stored in <code>contextMap</code>.
+     */
+    private final HashMap<ServletContextHelper, HttpContext> helperMap;
+
+    /**
+     * Map of servlets and filters registered referring to unregistered
+     * contexts as of yet.
+     */
+    private final HashMap<String, Set<AbstractMapping>> orphanMappings;
+
+    public HttpContextManager()
+    {
+        this.idMap = new HashMap<String, HttpContextHolder>();
+        this.contextMap = new HashMap<HttpContext, String>();
+        this.helperMap = new HashMap<ServletContextHelper, HttpContext>();
+        this.orphanMappings = new HashMap<String, Set<AbstractMapping>>();
+    }
+
+    private static String createId(Bundle bundle, String contextId, boolean isContextHelper)
+    {
+        if (isContextHelper)
+        {
+            return "servletcontexthelper-" + ((contextId == null) ? "" : contextId);
+        }
+        if (bundle != null)
+        {
+            return bundle.getBundleId() + "-" + ((contextId == null) ? "" : contextId);
+        }
+
+        return createId(contextId);
+    }
+
+    private static String createId(String contextId)
+    {
+        return "shared-" + ((contextId == null) ? "" : contextId);
+    }
+
+    private static String getContextId(String id)
+    {
+        final int dash = id.indexOf('-');
+        return (dash < 0) ? id : id.substring(dash + 1);
+    }
+
+    public synchronized HttpContext getHttpContext(Bundle bundle, String contextId, AbstractMapping mapping)
+    {
+        return getHttpContext(bundle, contextId, mapping, false);
+    }
+
+    public synchronized HttpContext getHttpContext(Bundle bundle, String contextId, AbstractMapping mapping,
+                                                   boolean isContextHelper)
+    {
+        // per-bundle context
+        String id = createId(bundle, contextId, isContextHelper);
+        HttpContextHolder holder = this.idMap.get(id);
+
+        // shared context
+        if (holder == null)
+        {
+            id = createId(contextId);
+            holder = this.idMap.get(id);
+        }
+
+        // no context yet, put the mapping on hold
+        if (holder == null)
+        {
+            // care for default context if no context ID
+            if (ExtenderManager.isEmpty(contextId))
+            {
+                addHttpContext(bundle, "", new DefaultHttpContext(bundle));
+                return getHttpContext(bundle, "", mapping);
+            }
+
+            // otherwise context is not here yet
+            Set<AbstractMapping> orphaned = this.orphanMappings.get(contextId);
+            if (orphaned == null)
+            {
+                orphaned = new HashSet<AbstractMapping>();
+                this.orphanMappings.put(contextId, orphaned);
+            }
+            if (contextId != null)
+            {
+                // Only log something when an actual context ID is used. Should solve FELIX-4307...
+                SystemLogger.debug("Holding off mapping with unregistered context with id [" + contextId + "]");
+            }
+            orphaned.add(mapping);
+            return null;
+        }
+
+        // otherwise use the context
+        if (contextId != null)
+        {
+            // Only log something when an actual context ID is used. Should solve FELIX-4307...
+            SystemLogger.debug("Reusing context with id [" + contextId + "]");
+        }
+
+        holder.addMapping(mapping);
+        return holder.getContext();
+    }
+
+    public synchronized void ungetHttpContext(Bundle bundle, String contextId, AbstractMapping mapping)
+    {
+        ungetHttpContext(bundle, contextId, mapping, false);
+    }
+
+    public synchronized void ungetHttpContext(Bundle bundle, String contextId,
+                                              AbstractMapping mapping, boolean isContextHelper)
+    {
+        // per-bundle context
+        String id = createId(bundle, contextId, isContextHelper);
+        HttpContextHolder context = this.idMap.get(id);
+
+        // shared context
+        if (context == null && !isContextHelper)
+        {
+            id = createId(contextId);
+            context = this.idMap.get(id);
+        }
+
+        // remove the mapping if there is a mapped context
+        if (context != null)
+        {
+            context.removeMapping(mapping);
+        }
+        else
+        {
+            Set<AbstractMapping> orphans = this.orphanMappings.get(contextId);
+            if (orphans != null)
+            {
+                orphans.remove(mapping);
+                if (orphans.isEmpty())
+                {
+                    this.orphanMappings.remove(contextId);
+                }
+            }
+
+            // it is not expected but make sure there is no reference
+            mapping.setContext(null);
+        }
+    }
+
+    public synchronized Collection<AbstractMapping> addHttpContext(Bundle bundle, String contextId, HttpContext context)
+    {
+        String id = createId(bundle, contextId, false);
+        HttpContextHolder holder = new HttpContextHolder(context);
+
+        Set<AbstractMapping> orphans = this.orphanMappings.remove(contextId);
+        if (orphans != null)
+        {
+            for (Iterator<AbstractMapping> mi = orphans.iterator(); mi.hasNext();)
+            {
+                AbstractMapping mapping = mi.next();
+                if (bundle == null || bundle.equals(mapping.getBundle()))
+                {
+                    holder.addMapping(mapping);
+                    mi.remove();
+                }
+            }
+
+            // put any remaining orphans back
+            if (!orphans.isEmpty())
+            {
+                this.orphanMappings.put(contextId, orphans);
+            }
+        }
+
+        this.idMap.put(id, holder);
+        this.contextMap.put(context, id);
+        
+        // return a copy to prevent concurrent modification
+        return new HashSet<AbstractMapping>(holder.getMappings());
+    }
+
+    public synchronized Collection<AbstractMapping> addContextHelper(Bundle bundle, String contextName, String contextPath,
+                                                                     ServletContextHelper contextHelper)
+    {
+        String id = createId(bundle, contextName, true);
+        HttpContextHolder holder = new HttpContextHolder(contextHelper, contextPath);
+
+        Set<AbstractMapping> orphans = this.orphanMappings.remove(contextName);
+        if (orphans != null)
+        {
+            for (Iterator<AbstractMapping> mi = orphans.iterator(); mi.hasNext();)
+            {
+                AbstractMapping mapping = mi.next();
+                if (bundle == null || bundle.equals(mapping.getBundle()))
+                {
+                    holder.addMapping(mapping);
+                    mi.remove();
+                }
+            }
+
+            // put any remaining orphans back
+            if (!orphans.isEmpty())
+            {
+                this.orphanMappings.put(contextName, orphans);
+            }
+        }
+
+        this.idMap.put(id, holder);
+        this.contextMap.put(holder.getContext(), id);
+        this.helperMap.put(contextHelper, holder.getContext());
+
+        return holder.getMappings();
+    }
+
+    public synchronized Collection<AbstractMapping> removeHttpContext(HttpContext context)
+    {
+        String id = this.contextMap.remove(context);
+        if (id != null)
+        {
+            HttpContextHolder holder = this.idMap.remove(id);
+            if (holder != null)
+            {
+                Set<AbstractMapping> mappings = holder.getMappings();
+                if (mappings != null && !mappings.isEmpty())
+                {
+                    // keep the orphans around
+                    final String contextId = getContextId(id);
+                    Set<AbstractMapping> orphans = this.orphanMappings.get(contextId);
+                    if (orphans == null)
+                    {
+                        orphans = new HashSet<AbstractMapping>();
+                        this.orphanMappings.put(getContextId(id), orphans);
+                    }
+
+                    for (AbstractMapping mapping : mappings)
+                    {
+                        mapping.setContext(null);
+                        orphans.add(mapping);
+                    }
+                }
+                return mappings;
+            }
+        }
+        return null;
+    }
+
+    public synchronized Collection<AbstractMapping> removeContextHelper(ServletContextHelper contextHelper)
+    {
+        HttpContext context = this.helperMap.remove(contextHelper);
+        if (context != null)
+        {
+            return removeHttpContext(context);
+        }
+        return null;
+    }
+
+    synchronized Map<String, HttpContextHolder> getHttpContexts()
+    {
+        return new HashMap<String, HttpContextHolder>(this.idMap);
+    }
+
+    synchronized Map<String, Set<AbstractMapping>> getOrphanMappings()
+    {
+        return new HashMap<String, Set<AbstractMapping>>(this.orphanMappings);
+    }
+
+    static class HttpContextHolder
+    {
+        private final HttpContext context;
+        private final Set<AbstractMapping> mappings;
+        private final String path;
+
+        HttpContextHolder(final HttpContext context)
+        {
+            this.context = context;
+            this.mappings = new HashSet<AbstractMapping>();
+            this.path = null;
+        }
+
+        HttpContextHolder(final ServletContextHelper context,
+                          final String path)
+        {
+            this.context = new HttpContextBridge(context);
+            this.mappings = new HashSet<AbstractMapping>();
+            this.path = path;
+        }
+
+        public HttpContext getContext()
+        {
+            return context;
+        }
+
+        public String getPath()
+        {
+            return path;
+        }
+
+        void addMapping(AbstractMapping mapping)
+        {
+            this.mappings.add(mapping);
+            mapping.setContext(getContext());
+        }
+
+        void removeMapping(AbstractMapping mapping)
+        {
+            mapping.setContext(null);
+            this.mappings.remove(mapping);
+        }
+
+        public Set<AbstractMapping> getMappings()
+        {
+            return mappings;
+        }
+    }
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/HttpContextManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ResourceMapping.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ResourceMapping.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ResourceMapping.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ResourceMapping.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,59 @@
+/*
+ * 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.whiteboard;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+import org.osgi.service.http.runtime.dto.ResourceDTO;
+
+public final class ResourceMapping extends AbstractMapping
+{
+    private final ResourceDTO dto;
+
+    public ResourceMapping(final Bundle bundle, final ResourceDTO resourceDTO)
+    {
+        super(bundle);
+        this.dto = resourceDTO;
+    }
+
+    @Override
+    public void register(final HttpService httpService)
+    {
+        if (!isRegistered() && getContext() != null)
+        {
+            try {
+                httpService.registerResources(this.dto.patterns[0], this.dto.prefix, this.getContext());
+                this.setRegistered(true);
+            }
+            catch (final NamespaceException e)
+            {
+                // TODO Handle exception
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public void unregister(final HttpService httpService)
+    {
+        if (isRegistered())
+        {
+            httpService.unregister(this.dto.patterns[0]);
+        }
+    }
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ResourceMapping.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ResourceMapping.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletMapping.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletMapping.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletMapping.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletMapping.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,85 @@
+/*
+ * 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.whiteboard;
+
+import javax.servlet.Servlet;
+
+import org.apache.felix.http.base.internal.logger.SystemLogger;
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.service.HttpServiceImpl;
+import org.osgi.framework.Bundle;
+import org.osgi.service.http.HttpService;
+
+public final class ServletMapping extends AbstractMapping
+{
+    private final Servlet servlet;
+    private final ServletInfo servletInfo;
+
+    public ServletMapping(Bundle bundle, Servlet servlet, ServletInfo servletInfo)
+    {
+        super(bundle);
+        this.servlet = servlet;
+        this.servletInfo = servletInfo;
+    }
+
+    @Override
+    public void register(HttpService httpService)
+    {
+        if (!isRegistered() && (httpService instanceof HttpServiceImpl) && getContext() != null)
+        {
+            this.servletInfo.context = getContext(); // XXX
+            try
+            {
+                ((HttpServiceImpl) httpService).registerServlet(this.servlet, this.servletInfo);
+                setRegistered(true);
+            }
+            catch (Exception e)
+            {
+                // Warn that something might have gone astray...
+                SystemLogger.warning("Failed to register servlet for " + this.servletInfo.name, e);
+            }
+            setRegistered(true);
+        }
+    }
+
+    @Override
+    public void unregister(HttpService httpService)
+    {
+        if (isRegistered() && (httpService instanceof HttpServiceImpl))
+        {
+            try
+            {
+                ((HttpServiceImpl) httpService).unregisterServlet(this.servlet);
+            }
+            catch (Exception e)
+            {
+                // Warn that something might have gone astray...
+                SystemLogger.debug("Failed to unregister servlet for " + this.servletInfo.name, e);
+            }
+            finally
+            {
+                // Best effort: avoid mappings that are registered which is reality aren't registered...
+                setRegistered(false);
+            }
+        }
+    }
+
+    Servlet getServlet()
+    {
+        return this.servlet;
+    }
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletMapping.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ServletMapping.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/AbstractTracker.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/AbstractTracker.java?rev=1655654&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/AbstractTracker.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/AbstractTracker.java Thu Jan 29 13:39:11 2015
@@ -0,0 +1,65 @@
+/*
+ * 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.whiteboard.tracker;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public abstract class AbstractTracker<T> extends ServiceTracker
+{
+    public AbstractTracker(final BundleContext context, final Class<T> clz)
+    {
+        super(context, clz.getName(), null);
+    }
+
+    public AbstractTracker(final BundleContext context, final Filter filter)
+    {
+        super(context, filter, null);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final Object addingService(final ServiceReference ref)
+    {
+        T service = (T) super.addingService(ref);
+        added(service, ref);
+        return service;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final void modifiedService(final ServiceReference ref, final Object service)
+    {
+        modified( (T)service, ref);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final void removedService(final ServiceReference ref, final Object service)
+    {
+        super.removedService(ref, service);
+        removed((T) service, ref);
+    }
+
+    protected abstract void modified(T service, ServiceReference ref);
+
+    protected abstract void added(T service, ServiceReference ref);
+
+    protected abstract void removed(T service, ServiceReference ref);
+}

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/AbstractTracker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/AbstractTracker.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url



Mime
View raw message