Author: jawi
Date: Tue Mar 10 10:45:02 2015
New Revision: 1665462

URL: http://svn.apache.org/r1665462
Log:
FELIX-4541 - Applied patch from Raluca:

- add integration tests for registrations with multiple patterns;
- implement support for registration of patterns using service rankings;
- some dings and dents fixed in the code.


Added:
    
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/HttpWhiteboardTargetTest.java
   (with props)
    
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/ServletPatternTest.java
   (with props)
Removed:
    
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/HttpWhiteboardTest.java
Modified:
    
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
    
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerMapping.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/PerContextHandlerRegistry.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/runtime/AbstractInfo.java
    
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java
    
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
    
felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistryTest.java

Modified: 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java?rev=1665462&r1=1665461&r2=1665462&view=diff
==============================================================================
--- 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
 (original)
+++ 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/HttpServiceController.java
 Tue Mar 10 10:45:02 2015
@@ -47,7 +47,7 @@ public final class HttpServiceController
     public HttpServiceController(final BundleContext bundleContext)
     {
         this.bundleContext = bundleContext;
-        this.registry = new HandlerRegistry();
+        this.registry = new HandlerRegistry(this.bundleContext);
         this.dispatcher = new Dispatcher(this.registry);
         this.plugin = new HttpServicePlugin(bundleContext, registry);
         this.httpServiceFactory = new HttpServiceFactory(this.bundleContext, 
this.registry);

Modified: 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerMapping.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerMapping.java?rev=1665462&r1=1665461&r2=1665462&view=diff
==============================================================================
--- 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerMapping.java
 (original)
+++ 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerMapping.java
 Tue Mar 10 10:45:02 2015
@@ -18,175 +18,185 @@
  */
 package org.apache.felix.http.base.internal.handler;
 
+import static java.util.Collections.unmodifiableCollection;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.felix.http.base.internal.util.PatternUtil;
+
 /**
  * Represents a Map-like structure that can map path-patterns to 
servlet/filter handlers, allowing
  * for easy access to those handlers, based on the match rules defined in 
section 12.1 of Servlet
  * 3.0 specification.
- *
+ * <p>
+ * {@link HandlerMapping} instances are immutable.
+ * 
  * @author <a href="mailto:[email protected]";>Felix Project Team</a>
  */
-public class HandlerMapping<V extends AbstractHandler>
+final class HandlerMapping<V extends AbstractHandler<V>>
 {
+    private final SortedMap<Pattern, Set<V>> exactMap;
+    private final SortedMap<Pattern, Set<V>> wildcardMap;
+    private final Set<V> mappedHandlers;
+
+    /**
+     * Creates a new, empty, {@link HandlerMapping} instance.
+     */
+    HandlerMapping()
+    {
+        this(Collections.<Pattern, Collection<V>>emptyMap());
+    }
+
     /**
-     * Compares {@link Pattern}s based on a set of simple rules:
-     * <ol>
-     * <li>exact matches go first;</li>
-     * <li>followed by wildcard path matches;</li>
-     * <li>lastly all wildcard extension matches.</li>
-     * </ol>
-     * <p>
-     * Equal matches will first be sorted on length in descending order 
(longest patterns first),
-     * and in case of equal lengths, they are sorted in natural (ascending) 
order.
-     * </p>
+     * Creates a new {@link HandlerMapping} instance for the given elements.
+     *
+     * @param mappings the elements to map.
      */
-    static class PatternComparator implements Comparator<Pattern>
+    private HandlerMapping(Map<Pattern, Collection<V>> mappings)
     {
-        @Override
-        public int compare(Pattern p1, Pattern p2)
+        this.exactMap = new TreeMap<Pattern, 
Set<V>>(PatternUtil.PatternComparator.INSTANCE);
+        this.wildcardMap = new TreeMap<Pattern, 
Set<V>>(PatternUtil.PatternComparator.INSTANCE);
+        this.mappedHandlers = new TreeSet<V>();
+
+        for (Map.Entry<Pattern, Collection<V>> mapping : mappings.entrySet())
         {
-            String ps1 = p1.pattern();
-            String ps2 = p2.pattern();
+            Pattern pattern = mapping.getKey();
+            Collection<V> handlers = mapping.getValue();
 
-            // Sorts wildcard path matches before wildcard extension matches...
-            int r;
-            if (isWildcardPath(ps1))
-            {
-                if (isWildcardPath(ps2))
-                {
-                    // Descending on length...
-                    r = ps2.length() - ps1.length();
-                }
-                else
-                {
-                    // Exact matches go first...
-                    r = isWildcardExtension(ps2) ? -1 : 1;
-                }
-            }
-            else if (isWildcardExtension(ps1))
+            mappedHandlers.addAll(handlers);
+
+            if (PatternUtil.isWildcardPattern(pattern))
             {
-                if (isWildcardExtension(ps2))
-                {
-                    // Descending on length...
-                    r = ps2.length() - ps1.length();
-                }
-                else
+                Set<V> vs = this.wildcardMap.get(pattern);
+                if (vs == null)
                 {
-                    // Wildcard paths & exact matches go first...
-                    r = 1;
+                    vs = new TreeSet<V>();
+                    this.wildcardMap.put(pattern, vs);
                 }
+                vs.addAll(handlers);
             }
             else
             {
-                if (isWildcardExtension(ps2) || isWildcardPath(ps2))
-                {
-                    // Exact matches go first...
-                    r = -1;
-                }
-                else
+                Set<V> vs = this.exactMap.get(pattern);
+                if (vs == null)
                 {
-                    // Descending on length...
-                    r = ps2.length() - ps1.length();
+                    vs = new TreeSet<V>();
+                    this.exactMap.put(pattern, vs);
                 }
+                vs.addAll(handlers);
             }
-
-            if (r == 0)
-            {
-                // In case of a draw, ensure we sort in a predictable 
(ascending) order...
-                r = ps1.compareTo(ps2);
-            }
-
-            return r;
         }
+    }
 
-        private boolean isWildcardExtension(String p)
+    /**
+     * Returns a new {@link HandlerMapping} instance with a mapping for the
+     * given handler.
+     *
+     * @param handler the handler to be added to the mapping.
+     * @return a new {@link HandlerMapping} instance with a mapping for the
+     *         given handler.
+     */
+    HandlerMapping<V> add(V handler)
+    {
+        Map<Pattern, V> mappings = new TreeMap<Pattern, 
V>(PatternUtil.PatternComparator.INSTANCE);
+        for (Pattern pattern : handler.getPatterns())
         {
-            return p.startsWith("^(.*");
+            mappings.put(pattern, handler);
         }
+        return add(mappings);
+    }
 
-        private boolean isWildcardPath(String p)
+    HandlerMapping<V> add(Map<Pattern, V> mappings)
+    {
+        Map<Pattern, Collection<V>> newMappings = getAllMappings();
+        for (Map.Entry<Pattern, V> mapping : mappings.entrySet())
         {
-            return p.startsWith("^(/");
+            if (!newMappings.containsKey(mapping.getKey()))
+            {
+                newMappings.put(mapping.getKey(), new TreeSet<V>());
+            }
+            newMappings.get(mapping.getKey()).add(mapping.getValue());
         }
+        return new HandlerMapping<V>(newMappings);
     }
 
-    private final SortedMap<Pattern, List<V>> exactMap;
-    private final SortedMap<Pattern, List<V>> wildcardMap;
-    private final Set<V> all;
-
     /**
-     * Creates a new, empty, {@link HandlerMapping} instance.
+     * Returns a new {@link HandlerMapping} instance without a mapping for the
+     * given handler.
+     *
+     * @param subject the handled element to be removed from the mapping
+     * @return a new {@link HandlerMapping} instance without a mapping for the
+     *         given handler.
      */
-    public HandlerMapping()
+    HandlerMapping<V> remove(V handler)
     {
-        this(Collections.<V> emptyList());
+        Map<Pattern, V> mappings = new TreeMap<Pattern, 
V>(PatternUtil.PatternComparator.INSTANCE);
+        for (Pattern pattern : handler.getPatterns())
+        {
+            mappings.put(pattern, handler);
+        }
+        return remove(mappings);
     }
 
-    /**
-     * Creates a new {@link HandlerMapping} instance for the given elements.
-     *
-     * @param elements the elements to map, cannot be <code>null</code>.
-     */
-    public HandlerMapping(Collection<V> elements)
+    HandlerMapping<V> remove(Map<Pattern, V> mappings)
     {
-        this.exactMap = new TreeMap<Pattern, List<V>>(new PatternComparator());
-        this.wildcardMap = new TreeMap<Pattern, List<V>>(new 
PatternComparator());
-        this.all = new HashSet<V>(elements);
-
-        for (V element : elements)
+        Map<Pattern, Collection<V>> newMappings = getAllMappings();
+        for (Map.Entry<Pattern, V> mapping : mappings.entrySet())
         {
-            for (Pattern pattern : element.getPatterns())
+            Collection<V> mappedHandlers = newMappings.get(mapping.getKey());
+            if (mappedHandlers == null)
             {
-                if (isWildcardPattern(pattern))
-                {
-                    List<V> vs = this.wildcardMap.get(pattern);
-                    if (vs == null)
-                    {
-                        vs = new ArrayList<V>();
-                        this.wildcardMap.put(pattern, vs);
-                    }
-                    if (!vs.contains(element))
-                    {
-                        vs.add(element);
-                    }
-                }
-                else
-                {
-                    List<V> vs = this.exactMap.get(pattern);
-                    if (vs == null)
-                    {
-                        vs = new ArrayList<V>();
-                        this.exactMap.put(pattern, vs);
-                    }
-                    if (!vs.contains(element))
-                    {
-                        vs.add(element);
-                    }
-                }
+                continue;
+            }
+            mappedHandlers.remove(mapping.getValue());
+            if (mappedHandlers.isEmpty())
+            {
+                newMappings.remove(mapping.getKey());
             }
         }
+        return new HandlerMapping<V>(newMappings);
+    }
+
+    private Map<Pattern, Collection<V>> getAllMappings()
+    {
+        Map<Pattern, Collection<V>> newMappings = new TreeMap<Pattern, 
Collection<V>>(PatternUtil.PatternComparator.INSTANCE);
+        newMappings.putAll(exactMap);
+        newMappings.putAll(wildcardMap);
+        return newMappings;
     }
 
     /**
-     * Returns all mapped elements.
-     *
-     * @return a collection of mapped elements, never <code>null</code>.
+     * Returns all mapped handlers.
+     * 
+     * @return the handlers contained in this mapping. The returned
+     *         <code>Collection</code> is unmodifiable and never
+     *         <code>null</code>.
+     */
+    Collection<V> values()
+    {
+        return unmodifiableCollection(mappedHandlers);
+    }
+
+    /**
+     * Returns whether this mapping contains the specified handler.
+     * 
+     * @return <code>true</code> if the handlers contains the specified 
handler,
+     *         <code>false</code> otherwise
      */
-    public Collection<V> getAllElements()
+    boolean contains(V handler)
     {
-        return this.all;
+        return mappedHandlers.contains(handler);
     }
 
     /**
@@ -195,7 +205,7 @@ public class HandlerMapping<V extends Ab
      * @param path the path that should match, cannot be <code>null</code>.
      * @return a {@link Collection} of all matching handlers, never 
<code>null</code>.
      */
-    public List<V> getAllMatches(String path)
+    List<V> getAllMatches(String path)
     {
         return getAllMatches(path, false /* firstOnly */);
     }
@@ -213,7 +223,7 @@ public class HandlerMapping<V extends Ab
      * @param path the path that should match, cannot be <code>null</code>.
      * @return the best matching handler for the given path, or 
<code>null</code> in case no handler matched.
      */
-    public V getBestMatch(String path)
+    V getBestMatch(String path)
     {
         List<V> allMatches = getAllMatches(path, true /* firstOnly */);
         return allMatches.isEmpty() ? null : allMatches.get(0);
@@ -221,17 +231,18 @@ public class HandlerMapping<V extends Ab
 
     /**
      * Returns the (first) handler identified by the given name.
+     *
      * @param name the name of the handler to return, can be <code>null</code> 
in which case this method will return <code>null</code>.
      * @return the element with the given name, or <code>null</code> if not 
found, or the given argument was <code>null</code>.
      */
-    public V getByName(String name)
+    V getByName(String name)
     {
         if (name == null)
         {
             return null;
         }
 
-        for (V element : this.all)
+        for (V element : this.mappedHandlers)
         {
             if (name.equals(element.getName()))
             {
@@ -245,11 +256,11 @@ public class HandlerMapping<V extends Ab
     /**
      * Provides information on whether there are elements mapped or not.
      *
-     * @return <code>true</code> if there is at least one element mapped, 
<code>false</code> otherwise.
+     * @return <code>false</code> if there is at least one element mapped, 
<code>true</code> otherwise.
      */
-    public boolean hasElements()
+    boolean isEmpty()
     {
-        return !this.all.isEmpty();
+        return this.mappedHandlers.isEmpty();
     }
 
     /**
@@ -265,60 +276,45 @@ public class HandlerMapping<V extends Ab
     {
         path = (path == null) ? "" : path.trim();
 
-        List<V> result = new ArrayList<V>();
+        Set<V> result = new TreeSet<V>();
         // Look for exact matches only, that is, those patterns without 
wildcards...
-        for (Entry<Pattern, List<V>> entry : this.exactMap.entrySet())
+        for (Entry<Pattern, Set<V>> entry : this.exactMap.entrySet())
         {
             Matcher matcher = entry.getKey().matcher(path);
             // !!! we should always match the *entire* pattern, instead of the 
longest prefix...
             if (matcher.matches())
             {
-                List<V> vs = entry.getValue();
+                Set<V> vs = entry.getValue();
                 for (V v : vs)
                 {
-                    if (!result.contains(v))
-                    {
-                        result.add(v);
-                    }
-
+                    result.add(v);
                     if (firstOnly)
                     {
-                        return result;
+                        return new ArrayList<V>(result);
                     }
                 }
             }
         }
 
         // Try to apply the wildcard patterns...
-        for (Entry<Pattern, List<V>> entry : this.wildcardMap.entrySet())
+        for (Entry<Pattern, Set<V>> entry : this.wildcardMap.entrySet())
         {
             Matcher matcher = entry.getKey().matcher(path);
             if (matcher.find(0))
             {
-                List<V> vs = entry.getValue();
+                Set<V> vs = entry.getValue();
                 for (V v : vs)
                 {
-                    if (!result.contains(v))
-                    {
-                        result.add(v);
-                    }
+                    result.add(v);
 
                     if (firstOnly)
                     {
-                        return result;
+                        break;
                     }
                 }
             }
         }
 
-        // Make sure the results are properly sorted...
-        Collections.sort(result);
-
-        return result;
-    }
-
-    static boolean isWildcardPattern(Pattern p)
-    {
-        return p.pattern().contains(".*");
+        return new ArrayList<V>(result);
     }
 }

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=1665462&r1=1665461&r2=1665462&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
 Tue Mar 10 10:45:02 2015
@@ -26,6 +26,7 @@ import javax.servlet.DispatcherType;
 
 import org.apache.felix.http.base.internal.runtime.HandlerRuntime;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
+import org.osgi.framework.BundleContext;
 
 /**
  * Registry for all services.
@@ -36,16 +37,22 @@ import org.apache.felix.http.base.intern
 public final class HandlerRegistry
 {
     private static FilterHandler[] EMPTY_FILTER_HANDLER = new FilterHandler[0];
+    private final BundleContext bundleContext;
 
     /** Current list of context registrations. */
     private volatile List<PerContextHandlerRegistry> registrations = 
Collections.emptyList();
 
+    public HandlerRegistry(BundleContext bundleContext)
+    {
+       this.bundleContext = bundleContext;
+    }
+    
     /**
      * Register default context registry for Http Service
      */
     public void init()
     {
-        this.add(new PerContextHandlerRegistry());
+        this.add(new PerContextHandlerRegistry(this.bundleContext));
     }
 
     /**
@@ -74,7 +81,7 @@ public final class HandlerRegistry
      */
     public void add(@Nonnull ServletContextHelperInfo info)
     {
-        this.add(new PerContextHandlerRegistry(info));
+        this.add(new PerContextHandlerRegistry(info, this.bundleContext));
     }
 
     /**

Modified: 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java?rev=1665462&r1=1665461&r2=1665462&view=diff
==============================================================================
--- 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
 (original)
+++ 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
 Tue Mar 10 10:45:02 2015
@@ -23,26 +23,43 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
 
+import javax.annotation.Nonnull;
 import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 import javax.servlet.Servlet;
 import javax.servlet.ServletException;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.HandlerRuntime;
 import org.apache.felix.http.base.internal.runtime.HandlerRuntime.ErrorPage;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.service.ResourceServlet;
+import org.apache.felix.http.base.internal.util.PatternUtil;
+import org.apache.felix.http.base.internal.whiteboard.ContextHandler;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceObjects;
 
 public final class PerContextHandlerRegistry implements 
Comparable<PerContextHandlerRegistry>
 {
-    private final Map<Servlet, ServletHandler> servletMap = new 
HashMap<Servlet, ServletHandler>();
+       private final BundleContext bundleContext;
+
     private final Map<Filter, FilterHandler> filterMap = new HashMap<Filter, 
FilterHandler>();
-    private final Map<String, Servlet> servletPatternMap = new HashMap<String, 
Servlet>();
+
     private volatile HandlerMapping<ServletHandler> servletMapping = new 
HandlerMapping<ServletHandler>();
     private volatile HandlerMapping<FilterHandler> filterMapping = new 
HandlerMapping<FilterHandler>();
     private final ErrorsMapping errorsMapping = new ErrorsMapping();
+    
+    private SortedMap<Pattern, SortedSet<ServletHandler>> 
patternToServletHandler = new TreeMap<Pattern, 
SortedSet<ServletHandler>>(PatternUtil.PatternComparator.INSTANCE);
+    private Map<ServletHandler, Integer> servletHandlerToUses = new 
HashMap<ServletHandler, Integer>();
+    private final SortedSet<ServletHandler> allServletHandlers = new 
TreeSet<ServletHandler>();
 
     private final long serviceId;
 
@@ -52,18 +69,20 @@ public final class PerContextHandlerRegi
 
     private final String prefix;
 
-    public PerContextHandlerRegistry() {
+    public PerContextHandlerRegistry(BundleContext bundleContext) {
         this.serviceId = 0;
         this.ranking = Integer.MAX_VALUE;
         this.path = "/";
         this.prefix = null;
+        this.bundleContext = bundleContext;
     }
 
-    public PerContextHandlerRegistry(final ServletContextHelperInfo info)
+    public PerContextHandlerRegistry(final ServletContextHelperInfo info, 
BundleContext bundleContext)
     {
         this.serviceId = info.getServiceId();
         this.ranking = info.getRanking();
         this.path = info.getPath();
+        this.bundleContext = bundleContext;
         if ( this.path.equals("/") )
         {
                prefix = null;
@@ -76,15 +95,14 @@ public final class PerContextHandlerRegi
 
     public synchronized void addFilter(FilterHandler handler) throws 
ServletException
     {
-        if (this.filterMap.containsKey(handler.getFilter()))
-        {
-            throw new ServletException("Filter instance already registered");
-        }
+       if(this.filterMapping.contains(handler))
+       {
+               throw new ServletException("Filter instance already 
registered");
+       }
 
         handler.init();
+        this.filterMapping = this.filterMapping.add(handler);
         this.filterMap.put(handler.getFilter(), handler);
-
-        updateFilterMapping();
     }
 
     @Override
@@ -109,35 +127,147 @@ public final class PerContextHandlerRegi
      */
     public synchronized void addServlet(final ServletHandler handler) throws 
ServletException
     {
-        // Can be null in case of error-handling servlets...
-        String[] patterns = handler.getServletInfo().getPatterns();
-        int length = patterns == null ? 0 : patterns.length;
-
-        for (int i = 0; i < length; i++)
-        {
-            final String pattern = patterns[i];
-            if (this.servletPatternMap.containsKey(pattern))
-            {
-                throw new ServletException("Servlet instance " + 
handler.getName() + " already registered");
-            }
-            this.servletPatternMap.put(pattern, handler.getServlet());
-        }
-
-        patterns = handler.getServletInfo().getErrorPage();
-        if ( patterns != null )
-        {
-            for(final String errorPage : patterns)
-            {
-                this.errorsMapping.addErrorServlet(errorPage, handler);
-            }
-        }
-        handler.init();
-        this.servletMap.put(handler.getServlet(), handler);
-
-        updateServletMapping();
+       Pattern[] patterns = handler.getPatterns();
+       String[] errorPages = handler.getServletInfo().getErrorPage();
+       
+       if(patterns.length > 0 && errorPages != null)
+       {
+               throw new ServletException("Servlet instance " + 
handler.getName() + " has both patterns and errorPage set");
+       }
+       
+       SortedMap<Pattern, ServletHandler> toAdd = new TreeMap<Pattern, 
ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
+       SortedMap<Pattern, ServletHandler> toRemove = new TreeMap<Pattern, 
ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
+       
+       this.servletHandlerToUses.put(handler, new Integer(0));
+       
+       for (Pattern p : patterns) 
+       {
+               ServletHandler prevHandler = null;
+
+               if( !this.patternToServletHandler.containsKey(p))
+               {
+                       this.patternToServletHandler.put(p, new 
TreeSet<ServletHandler>());
+               }
+               else
+               {
+                       prevHandler = 
this.patternToServletHandler.get(p).first();
+               }
+               
+               this.patternToServletHandler.get(p).add(handler);
+               
+            if ( handler.equals(this.patternToServletHandler.get(p).first()))
+            {
+               useServletHandler(handler);
+               if (!handler.isWhiteboardService())
+               {
+                       handler.init();
+               }
+               increaseUseCount(handler);
+
+               if (prevHandler != null)
+               {
+                       decreaseUseCount(prevHandler);
+                       toRemove.put(p, prevHandler);
+               }
+               toAdd.put(p, handler);
+            }
+       }
+       
+       this.servletMapping = this.servletMapping.remove(toRemove);
+       this.servletMapping = this.servletMapping.add(toAdd);
+       this.allServletHandlers.add(handler);
+       
+       if(errorPages != null)
+       {
+               for(String errorPage : errorPages)
+               {
+                       this.errorsMapping.addErrorServlet(errorPage, handler);
+               }
+       }
     }
 
-    public ErrorsMapping getErrorsMapping()
+    /**
+     * Ensures the servlet handler contains a valid servlet object.
+     * It gets one from the ServiceRegistry if the servlet handler was added 
by the whiteboard implementation
+     * and the object was not yet retrieved.
+     * 
+     * @param handler
+     * @throws ServletException
+     */
+    private void useServletHandler(ServletHandler handler) throws 
ServletException 
+    {
+       if( (!handler.isWhiteboardService()) || (handler.getServlet() != null) )
+       {
+               return;
+       }
+       
+       // isWhiteboardService && servlet == null
+       boolean isResource = handler.getServletInfo().isResource();
+       final ServiceObjects<Servlet> so = 
this.bundleContext.getServiceObjects(handler.getServletInfo().getServiceReference());
+       
+       Servlet servlet = getServiceObject(so, handler, isResource);
+       handler.setServlet(servlet);
+       
+       try {
+                       handler.init();
+               } catch (ServletException e) {
+                       ungetServiceObject(so, servlet, isResource);
+                       throw e;
+               }
+       }
+       
+       private Servlet getServiceObject(ServiceObjects<Servlet> so, 
ServletHandler handler, boolean isResource)
+       {
+               if(isResource) 
+               {
+                       return new 
ResourceServlet(handler.getServletInfo().getPrefix());
+               }
+               if(so != null)
+               {
+                       return so.getService();
+               }
+               return null;
+       }
+       
+       private void ungetServiceObject(ServiceObjects<Servlet> so, Servlet 
servlet, boolean isResource)
+       {
+               if(isResource || (so == null))
+               {
+                       return;
+               }
+               so.ungetService(servlet);
+       }
+
+       private void increaseUseCount(ServletHandler handler) 
+       {
+               Integer uses = this.servletHandlerToUses.get(handler);
+               if(uses != null)
+               {
+                       int newUsesValue = uses.intValue() + 1;
+                       this.servletHandlerToUses.put(handler, new 
Integer(newUsesValue));
+               }
+       }
+       
+       private void decreaseUseCount(@Nonnull ServletHandler handler)
+       {
+               Integer uses = this.servletHandlerToUses.get(handler);
+               if(uses != null)
+               {
+                       int newUsesValue = uses.intValue() - 1;
+                       if(newUsesValue == 0 && handler.isWhiteboardService())
+                       {               
+                               // if the servlet is no longer used and it is 
registered as a whiteboard service
+                               // call destroy, unget the service object and 
set the servlet in the handler to null
+                               handler.destroy();
+                               ServiceObjects<Servlet> so = 
this.bundleContext.getServiceObjects(handler.getServletInfo().getServiceReference());
+                               ungetServiceObject(so, handler.getServlet(), 
handler.getServletInfo().isResource());
+                               handler.setServlet(null);
+                       }
+                       this.servletHandlerToUses.put(handler, new 
Integer(newUsesValue));      
+               }
+       }
+
+       public ErrorsMapping getErrorsMapping()
     {
         return this.errorsMapping;
     }
@@ -160,7 +290,7 @@ public final class PerContextHandlerRegi
 
         String servletName = (servletHandler != null) ? 
servletHandler.getName() : null;
         // TODO this is not the most efficient/fastest way of doing this...
-        for (FilterHandler filterHandler : this.filterMapping.getAllElements())
+        for (FilterHandler filterHandler : this.filterMapping.values())
         {
             if (referencesServletByName(filterHandler, servletName))
             {
@@ -193,27 +323,26 @@ public final class PerContextHandlerRegi
 
     public synchronized void removeAll()
     {
-        for (Iterator<ServletHandler> it = servletMap.values().iterator(); 
it.hasNext(); )
+        Collection<ServletHandler> servletHandlers = servletMapping.values();
+        Collection<FilterHandler> filterHandlers = filterMapping.values();
+
+        this.servletMapping = new HandlerMapping<ServletHandler>();
+        this.filterMapping = new HandlerMapping<FilterHandler>();
+
+        for (ServletHandler handler : servletHandlers)
         {
-            ServletHandler handler = it.next();
-            it.remove();
             handler.destroy();
         }
 
-        for (Iterator<FilterHandler> it = filterMap.values().iterator(); 
it.hasNext(); )
+        for (FilterHandler handler : filterHandlers)
         {
-            FilterHandler handler = it.next();
-            it.remove();
             handler.destroy();
         }
 
-        this.servletMap.clear();
-        this.filterMap.clear();
-        this.servletPatternMap.clear();
         this.errorsMapping.clear();
-
-        updateServletMapping();
-        updateFilterMapping();
+        this.allServletHandlers.clear();
+        //this.servletMap.clear();
+        this.filterMap.clear();
     }
 
     public synchronized void removeFilter(Filter filter, final boolean destroy)
@@ -221,7 +350,7 @@ public final class PerContextHandlerRegi
         FilterHandler handler = this.filterMap.remove(filter);
         if (handler != null)
         {
-            updateFilterMapping();
+            this.filterMapping = this.filterMapping.remove(handler);
             if (destroy)
             {
                 handler.destroy();
@@ -231,76 +360,123 @@ public final class PerContextHandlerRegi
 
     public synchronized Filter removeFilter(final FilterInfo filterInfo, final 
boolean destroy)
     {
-        for(final FilterHandler handler : this.filterMap.values())
+        FilterHandler handler = getFilterHandler(filterInfo);
+
+        if (handler == null)
         {
-            if ( handler.getFilterInfo().compareTo(filterInfo) == 0)
-            {
-                this.filterMap.remove(handler.getFilter());
-                updateFilterMapping();
-                if (destroy)
-                {
-                    handler.destroy();
-                }
-                return handler.getFilter();
-            }
+            return null;
         }
-        return null;
+
+        this.filterMapping = this.filterMapping.remove(handler);
+
+        if (destroy)
+        {
+            handler.destroy();
+        }
+        return handler.getFilter();
     }
 
-    public synchronized Servlet removeServlet(ServletInfo servletInfo, final 
boolean destroy)
+    private FilterHandler getFilterHandler(final FilterInfo filterInfo)
     {
-        for(final ServletHandler handler : this.servletMap.values())
+        for(final FilterHandler handler : this.filterMap.values())
         {
-            if ( handler.getServletInfo().compareTo(servletInfo) == 0 )
+            if ( handler.getFilterInfo().compareTo(filterInfo) == 0)
             {
-                this.servletMap.remove(handler.getServlet());
-                updateServletMapping();
-
-                // Can be null in case of error-handling servlets...
-                String[] patterns = handler.getServletInfo().getPatterns();
-                int length = patterns == null ? 0 : patterns.length;
-
-                for (int i = 0; i < length; i++)
-                {
-                    this.servletPatternMap.remove(patterns[i]);
-                }
-
-                this.errorsMapping.removeServlet(handler.getServlet());
-
-                if (destroy)
-                {
-                    handler.destroy();
-                }
-                return handler.getServlet();
+                return handler;
             }
         }
         return null;
     }
-
+    
+    public synchronized Servlet removeServlet(ServletInfo servletInfo, final 
boolean destroy)
+    {
+       ServletHandler handler = getServletHandler(servletInfo);
+       
+       Pattern[] patterns = (handler == null) ? new Pattern[0] : 
handler.getPatterns();
+       SortedMap<Pattern, ServletHandler> toAdd = new TreeMap<Pattern, 
ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
+       SortedMap<Pattern, ServletHandler> toRemove = new TreeMap<Pattern, 
ServletHandler>(PatternUtil.PatternComparator.INSTANCE);
+
+       for(Pattern p : patterns)
+       {               
+               SortedSet<ServletHandler> handlers = 
this.patternToServletHandler.get(p);
+               if(handlers != null && (!handlers.isEmpty()))
+               {
+                       if(handlers.first().equals(handler))
+                       {
+                               toRemove.put(p, handler);
+                       }
+                       handlers.remove(handler);
+                       
+                       ServletHandler activeHandler = null;
+                       if( !handlers.isEmpty() )
+                       {
+                               activeHandler = handlers.first();
+                               
+                               try {
+                                       useServletHandler(activeHandler);
+                                               increaseUseCount(activeHandler);
+                                               toAdd.put(p, activeHandler);
+                                       } catch (ServletException e) {
+                                               // TODO: next servlet handling 
this pattern could not be initialized, it belongs to failure DTOs
+                                       }
+                       }
+                       else 
+                       {
+                               this.patternToServletHandler.remove(p);
+                               }
+               }
+       }
+       
+       Servlet servlet = null;
+       if(handler != null)
+       {
+               servlet = handler.getServlet();
+               if(destroy)
+               {
+                       servlet.destroy();
+               }
+               if(handler.isWhiteboardService())
+               {
+                       ServiceObjects<Servlet> so = 
this.bundleContext.getServiceObjects(handler.getServletInfo().getServiceReference());
+                       ungetServiceObject(so, servlet, 
servletInfo.isResource());
+               }
+       }
+       
+       this.servletHandlerToUses.remove(handler);
+       
+               this.servletMapping = this.servletMapping.remove(toRemove);
+               this.servletMapping = this.servletMapping.add(toAdd);
+
+               return servlet;
+    }
+
+    private ServletHandler getServletHandler(final ServletInfo servletInfo)
+    {
+       Iterator<ServletHandler> it = this.allServletHandlers.iterator();
+       while(it.hasNext())
+       {
+               ServletHandler handler = it.next();
+               if(handler.getServletInfo().compareTo(servletInfo) == 0)
+               {
+                       return handler;
+               }
+       }
+       return null;
+    }
+    
     public synchronized void removeServlet(Servlet servlet, final boolean 
destroy)
     {
-        ServletHandler handler = this.servletMap.remove(servlet);
-        if (handler != null)
-        {
-            updateServletMapping();
-
-            // Can be null in case of error-handling servlets...
-            String[] patterns = handler.getServletInfo().getPatterns();
-            int length = patterns == null ? 0 : patterns.length;
-
-            for (int i = 0; i < length; i++)
-            {
-                this.servletPatternMap.remove(patterns[i]);
-            }
-
-            this.errorsMapping.removeServlet(servlet);
-
-            if (destroy)
-            {
-                handler.destroy();
-            }
-        }
+       Iterator<ServletHandler> it = this.allServletHandlers.iterator();
+       while(it.hasNext())
+       {
+               ServletHandler handler = it.next();
+               if(handler.getServlet() == servlet) 
+               {
+                       removeServlet(handler.getServletInfo(), destroy);
+               }
+       }
     }
+    
 
     private boolean referencesDispatcherType(FilterHandler handler, 
DispatcherType dispatcherType)
     {
@@ -321,16 +497,6 @@ public final class PerContextHandlerRegi
         return false;
     }
 
-    private void updateFilterMapping()
-    {
-        this.filterMapping = new 
HandlerMapping<FilterHandler>(this.filterMap.values());
-    }
-
-    private void updateServletMapping()
-    {
-        this.servletMapping = new 
HandlerMapping<ServletHandler>(this.servletMap.values());
-    }
-
     public String isMatching(final String requestURI)
     {
         if ( requestURI.equals(this.path) )
@@ -365,9 +531,13 @@ public final class PerContextHandlerRegi
 
         List<ServletHandler> servletHandlers = new ArrayList<ServletHandler>();
         List<ServletHandler> resourceHandlers = new 
ArrayList<ServletHandler>();
-        for (ServletHandler servletHandler : servletMap.values())
-        {
-            if (servletHandler.getServletInfo().isResource())
+        
+        Iterator<ServletHandler> it = this.allServletHandlers.iterator();
+        while(it.hasNext())
+        {
+               ServletHandler servletHandler = it.next();
+               
+               if (servletHandler.getServletInfo().isResource())
             {
                 resourceHandlers.add(servletHandler);
             }
@@ -378,5 +548,5 @@ public final class PerContextHandlerRegi
         }
 
         return new HandlerRuntime(servletHandlers, filterHandlers, 
resourceHandlers, errorPages, serviceId);
-    }
+    }    
 }

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=1665462&r1=1665461&r2=1665462&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
 Tue Mar 10 10:45:02 2015
@@ -36,24 +36,37 @@ import org.apache.felix.http.base.intern
 /**
  * @author <a href="mailto:[email protected]";>Felix Project Team</a>
  */
-public final class ServletHandler extends AbstractHandler<ServletHandler>
+public class ServletHandler extends AbstractHandler<ServletHandler>
 {
     private final ServletInfo servletInfo;
 
-    private final Servlet servlet;
+    private Servlet servlet;
 
     private final Pattern[] patterns;
 
     private final long contextServiceId;
+    
+    private final boolean isWhiteboardService;
 
     public ServletHandler(final ServletContextHelperInfo contextInfo,
                           final ExtServletContext context,
                           final ServletInfo servletInfo,
                           final Servlet servlet)
     {
-        super(context, servletInfo.getInitParameters(), servletInfo.getName());
+       this(contextInfo, context, servletInfo, servlet, false);
+    }
+    
+    public ServletHandler(final ServletContextHelperInfo contextInfo,
+            final ExtServletContext context,
+            final ServletInfo servletInfo,
+            final Servlet servlet, 
+            final boolean isWhiteboardService)
+    {
+       super(context, servletInfo.getInitParameters(), servletInfo.getName());
+       
         this.servlet = servlet;
         this.servletInfo = servletInfo;
+        this.isWhiteboardService = isWhiteboardService;
 
         // Can be null in case of error-handling servlets...
         String[] patterns = this.servletInfo.getPatterns();
@@ -74,6 +87,7 @@ public final class ServletHandler extend
             this.contextServiceId = 0;
         }
     }
+    
 
     @Override
     public int compareTo(final ServletHandler other)
@@ -111,6 +125,16 @@ public final class ServletHandler extend
     {
         return this.servlet;
     }
+    
+    void setServlet(Servlet servlet)
+    {
+       this.servlet = servlet;
+    }
+    
+    public boolean isWhiteboardService()
+    {
+       return this.isWhiteboardService;
+    }
 
     @Override
     public Pattern[] getPatterns()

Modified: 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java?rev=1665462&r1=1665461&r2=1665462&view=diff
==============================================================================
--- 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
 (original)
+++ 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/AbstractInfo.java
 Tue Mar 10 10:45:02 2015
@@ -118,14 +118,17 @@ public abstract class AbstractInfo<T> im
         }
         else if (value instanceof String[])
         {
-            final String[] arr = (String[]) value;
-            for(int i=0; i<arr.length; i++)
+               final String[] arr = (String[]) value;
+               String[] values = new String[arr.length];
+               
+            for(int i=0, j=0; i<arr.length; i++)
             {
                 if ( arr[i] != null )
                 {
-                    arr[i] = arr[i].trim();
+                    values[j++] = arr[i].trim();
                 }
             }
+            return values;
         }
         else if (value instanceof Collection<?>)
         {

Modified: 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java?rev=1665462&r1=1665461&r2=1665462&view=diff
==============================================================================
--- 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java
 (original)
+++ 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/PatternUtil.java
 Tue Mar 10 10:45:02 2015
@@ -18,7 +18,15 @@
  */
 package org.apache.felix.http.base.internal.util;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.SortedSet;
 import java.util.StringTokenizer;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Some convenience utilities to deal with path patterns.
@@ -111,4 +119,93 @@ public class PatternUtil
 
         return valid;
     }
+
+    /**
+     * Compares {@link Pattern}s based on a set of simple rules:
+     * <ol>
+     * <li>exact matches go first;</li>
+     * <li>followed by wildcard path matches;</li>
+     * <li>lastly all wildcard extension matches.</li>
+     * </ol>
+     * <p>
+     * Equal matches will first be sorted on length in descending order 
(longest patterns first),
+     * and in case of equal lengths, they are sorted in natural (ascending) 
order.
+     * </p>
+     */
+    public enum PatternComparator implements Comparator<Pattern>
+    {
+       INSTANCE;
+       
+        @Override
+        public int compare(Pattern p1, Pattern p2)
+        {
+            String ps1 = p1.pattern();
+            String ps2 = p2.pattern();
+
+            // Sorts wildcard path matches before wildcard extension matches...
+            int r;
+            if (isWildcardPath(ps1))
+            {
+                if (isWildcardPath(ps2))
+                {
+                    // Descending on length...
+                    r = ps2.length() - ps1.length();
+                }
+                else
+                {
+                    // Exact matches go first...
+                    r = isWildcardExtension(ps2) ? -1 : 1;
+                }
+            }
+            else if (isWildcardExtension(ps1))
+            {
+                if (isWildcardExtension(ps2))
+                {
+                    // Descending on length...
+                    r = ps2.length() - ps1.length();
+                }
+                else
+                {
+                    // Wildcard paths & exact matches go first...
+                    r = 1;
+                }
+            }
+            else
+            {
+                if (isWildcardExtension(ps2) || isWildcardPath(ps2))
+                {
+                    // Exact matches go first...
+                    r = -1;
+                }
+                else
+                {
+                    // Descending on length...
+                    r = ps2.length() - ps1.length();
+                }
+            }
+
+            if (r == 0)
+            {
+                // In case of a draw, ensure we sort in a predictable 
(ascending) order...
+                r = ps1.compareTo(ps2);
+            }
+
+            return r;
+        }
+
+        private boolean isWildcardExtension(String p)
+        {
+            return p.startsWith("^(.*");
+        }
+
+        private boolean isWildcardPath(String p)
+        {
+            return p.startsWith("^(/");
+        }
+    }
+
+    public static boolean isWildcardPattern(Pattern p)
+    {
+        return p.pattern().contains(".*");
+    }
 }

Modified: 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java?rev=1665462&r1=1665461&r2=1665462&view=diff
==============================================================================
--- 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
 (original)
+++ 
felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
 Tue Mar 10 10:45:02 2015
@@ -57,29 +57,21 @@ public final class WhiteboardHttpService
     public void registerServlet(@Nonnull final ContextHandler contextHandler,
             @Nonnull final ServletInfo servletInfo)
     {
-        final ServiceObjects<Servlet> so = 
this.bundleContext.getServiceObjects(servletInfo.getServiceReference());
-        if ( so != null )
-        {
-            final Servlet servlet = so.getService();
-            // TODO create failure DTO if null
-            if ( servlet != null )
-            {
-                final ServletHandler handler = new 
ServletHandler(contextHandler.getContextInfo(),
-                        
contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
-                        servletInfo,
-                        servlet);
-                try {
-                    final PerContextHandlerRegistry registry = 
this.handlerRegistry.getRegistry(contextHandler.getContextInfo());
-                    if (registry != null )
-                    {
-                        registry.addServlet(handler);
-                    }
-                } catch (final ServletException e) {
-                    so.ungetService(servlet);
-                    // TODO create failure DTO
-                }
-            }
-        }
+       final PerContextHandlerRegistry registry = 
this.handlerRegistry.getRegistry(contextHandler.getContextInfo());
+       if (registry != null)
+       {
+               try {
+                       ServletHandler handler = new 
ServletHandler(contextHandler.getContextInfo(), 
+                                       
contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
 
+                                       servletInfo, 
+                                       null, 
+                                       true);
+                       
+                       registry.addServlet(handler);
+                       } catch (ServletException e) {
+                               // TODO create failure DTO
+                       }
+       }
     }
 
     /**
@@ -92,11 +84,7 @@ public final class WhiteboardHttpService
         final PerContextHandlerRegistry registry = 
this.handlerRegistry.getRegistry(contextHandler.getContextInfo());
         if (registry != null )
         {
-            final Servlet instance = registry.removeServlet(servletInfo, true);
-            if ( instance != null )
-            {
-                
this.bundleContext.getServiceObjects(servletInfo.getServiceReference()).ungetService(instance);
-            }
+            registry.removeServlet(servletInfo, true);
         }
         
contextHandler.ungetServletContext(servletInfo.getServiceReference().getBundle());
     }
@@ -156,22 +144,23 @@ public final class WhiteboardHttpService
     public void registerResource(@Nonnull final ContextHandler contextHandler,
             @Nonnull final ResourceInfo resourceInfo)
     {
-        final ServletInfo servletInfo = new ServletInfo(resourceInfo);
-
-        final Servlet servlet = new ResourceServlet(resourceInfo.getPrefix());
-        final ServletHandler handler = new 
ServletHandler(contextHandler.getContextInfo(),
-                
contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
-                servletInfo,
-                servlet);
-        try {
-            final PerContextHandlerRegistry registry = 
this.handlerRegistry.getRegistry(contextHandler.getContextInfo());
-            if (registry != null )
-            {
-                registry.addServlet(handler);
-            }
-        } catch (ServletException e) {
-            // TODO create failure DTO
-        }
+       final ServletInfo servletInfo = new ServletInfo(resourceInfo);
+       
+       final ServletHandler handler = new 
ServletHandler(contextHandler.getContextInfo(),
+                       
contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
+                       servletInfo,
+                       null,
+                       true);
+ 
+       try {
+               final PerContextHandlerRegistry registry = 
this.handlerRegistry.getRegistry(contextHandler.getContextInfo());   
+               if(registry != null)
+               {
+                               registry.addServlet(handler);
+               }
+       } catch (ServletException e) {
+               // TODO create failure DTO
+       }
     }
 
     /**

Modified: 
felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistryTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistryTest.java?rev=1665462&r1=1665461&r2=1665462&view=diff
==============================================================================
--- 
felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistryTest.java
 (original)
+++ 
felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistryTest.java
 Tue Mar 10 10:45:02 2015
@@ -35,10 +35,10 @@ public class PerContextHandlerRegistryTe
     @Test public void testPathOrdering()
     {
         final List<PerContextHandlerRegistry> list = new 
ArrayList<PerContextHandlerRegistry>();
-        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 1L, 0)));
-        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/foo", 2L, 0)));
-        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 3L, 0)));
-        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/bar", 4L, 0)));
+        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 1L, 0), null));
+        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/foo", 2L, 0), null));
+        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 3L, 0), null));
+        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/bar", 4L, 0), null));
 
         Collections.sort(list);
 
@@ -51,10 +51,10 @@ public class PerContextHandlerRegistryTe
     @Test public void testRankingOrdering()
     {
         final List<PerContextHandlerRegistry> list = new 
ArrayList<PerContextHandlerRegistry>();
-        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 1L, 0)));
-        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 2L, 0)));
-        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 3L, -30)));
-        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 4L, 50)));
+        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 1L, 0), null));
+        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 2L, 0), null));
+        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 3L, -30), null));
+        list.add(new 
PerContextHandlerRegistry(createServletContextHelperInfo("/", 4L, 50), null));
 
         Collections.sort(list);
 
@@ -77,8 +77,8 @@ public class PerContextHandlerRegistryTe
 
     private void testSymetry(String path, String otherPath, long id, long 
otherId, int ranking, int otherRanking)
     {
-        PerContextHandlerRegistry handlerRegistry = new 
PerContextHandlerRegistry(createServletContextHelperInfo(path, id, ranking));
-        PerContextHandlerRegistry other = new 
PerContextHandlerRegistry(createServletContextHelperInfo(otherPath, otherId, 
otherRanking));
+        PerContextHandlerRegistry handlerRegistry = new 
PerContextHandlerRegistry(createServletContextHelperInfo(path, id, ranking), 
null);
+        PerContextHandlerRegistry other = new 
PerContextHandlerRegistry(createServletContextHelperInfo(otherPath, otherId, 
otherRanking), null);
 
         assertEquals(handlerRegistry.compareTo(other), 
-other.compareTo(handlerRegistry));
     }
@@ -96,9 +96,9 @@ public class PerContextHandlerRegistryTe
             long highId, long midId, long lowId,
             int highRanking, int midRanking, int lowRanking)
     {
-        PerContextHandlerRegistry high = new 
PerContextHandlerRegistry(createServletContextHelperInfo(highPath, highId, 
highRanking));
-        PerContextHandlerRegistry mid = new 
PerContextHandlerRegistry(createServletContextHelperInfo(midPath, midId, 
midRanking));
-        PerContextHandlerRegistry low = new 
PerContextHandlerRegistry(createServletContextHelperInfo(lowPath, lowId, 
lowRanking));
+        PerContextHandlerRegistry high = new 
PerContextHandlerRegistry(createServletContextHelperInfo(highPath, highId, 
highRanking), null);
+        PerContextHandlerRegistry mid = new 
PerContextHandlerRegistry(createServletContextHelperInfo(midPath, midId, 
midRanking), null);
+        PerContextHandlerRegistry low = new 
PerContextHandlerRegistry(createServletContextHelperInfo(lowPath, lowId, 
lowRanking), null);
 
         assertEquals(1, high.compareTo(mid));
         assertEquals(1, mid.compareTo(low));

Added: 
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/HttpWhiteboardTargetTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/HttpWhiteboardTargetTest.java?rev=1665462&view=auto
==============================================================================
--- 
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/HttpWhiteboardTargetTest.java
 (added)
+++ 
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/HttpWhiteboardTargetTest.java
 Tue Mar 10 10:45:02 2015
@@ -0,0 +1,391 @@
+/*
+ * 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.itest;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
+
+@RunWith(JUnit4TestRunner.class)
+public class HttpWhiteboardTargetTest extends BaseIntegrationTest
+{
+       
+       private static final String SERVICE_HTTP_PORT = 
"org.osgi.service.http.port"; 
+       
+       /**]
+        * Test that a servlet with the org.osgi.http.whiteboard.target 
property not set
+        * is registered with the whiteboard
+        */
+       @Test
+       public void testServletNoTargetProperty() throws Exception
+       {
+               CountDownLatch initLatch = new CountDownLatch(1);
+               CountDownLatch destroyLatch = new CountDownLatch(1);
+               
+               TestServlet servlet = new TestServlet(initLatch, destroyLatch) 
+               {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException 
+                       {
+                               resp.getWriter().print("It works!");
+                               resp.flushBuffer();
+                       }
+               };
+               
+               Dictionary<String, Object> props = new Hashtable<String, 
Object>();
+               
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, 
"/servletAlias");
+               
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servletName");
+               
+               ServiceRegistration<?> reg = 
m_context.registerService(Servlet.class.getName(), servlet, props);
+
+               try {
+                       assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+                       URL testURL = createURL("/servletAlias");
+            assertContent("It works!", testURL);            
+               } finally {
+                               reg.unregister();       
+               }
+               assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+       }
+       
+       /**
+        * Test that a servlet with the org.osgi.http.whiteboard.target 
property matching the 
+        * HttpServiceRuntime properties is registered with the whiteboard. 
+        * 
+        * In the current implementation the HttpServiceRuntime properties are 
the same as the
+        * HttpService properties. 
+        * 
+        */
+       @Test
+       public void testServletTargetMatchPort() throws Exception 
+       {
+               CountDownLatch initLatch = new CountDownLatch(1);
+               CountDownLatch destroyLatch = new CountDownLatch(1);
+               
+               TestServlet servlet = new TestServlet(initLatch, destroyLatch)
+               {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException 
+                       {
+                               resp.getWriter().print("matchingServlet");
+                               resp.flushBuffer();
+                       }
+               };
+               
+               Dictionary<String, Object> props = new Hashtable<String, 
Object>();
+               
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, 
"/servletAlias");
+               
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servletName");
+               props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, "(" + 
SERVICE_HTTP_PORT + "=8080" + ")");
+               
+               ServiceRegistration<?> reg = 
m_context.registerService(Servlet.class.getName(), servlet, props);
+               
+               try {
+                       assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+                       URL testURL = createURL("/servletAlias");
+            assertContent("matchingServlet", testURL);            
+               } finally {
+                       reg.unregister();
+               }
+               
+               assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));            
+       }
+       
+       /**
+        * Test that a servlet with the org.osgi.http.whiteboard.target 
property not matching
+        * the properties of the HttpServiceRuntime is not registered with the 
whiteboard.
+        * 
+        */
+       @Test
+       public void testServletTargetNotMatchPort() throws Exception 
+       {
+               CountDownLatch initLatch = new CountDownLatch(1);
+               CountDownLatch destroyLatch = new CountDownLatch(1);
+
+               TestServlet nonMatchingServlet = new TestServlet(initLatch, 
destroyLatch) 
+               {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException 
+                       {
+                               resp.getWriter().print("nonMatchingServlet");
+                               resp.flushBuffer();
+                       }
+               };
+               
+               Dictionary<String, Object> props = new Hashtable<String, 
Object>();
+               
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, 
"/servletAlias");
+               
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servletName");
+               props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, "(" + 
SERVICE_HTTP_PORT + "=8282" + ")");
+               
+               ServiceRegistration<?> reg = 
m_context.registerService(Servlet.class.getName(), nonMatchingServlet, props);
+               
+               try {
+                       // the servlet will not be registered, its init method 
will not be called, await must return false due to timeout
+                       assertFalse(initLatch.await(5, TimeUnit.SECONDS));
+                       URL testURL = createURL("/servletAlias");
+                       assertResponseCode(404, testURL);
+               } finally {
+                       reg.unregister();
+               }
+       }       
+       
+       /**
+        * Test that a filter with no target property set is correctly 
registered with the whiteboard
+        * 
+        */
+       @Test
+       public void testFilterNoTargetProperty() throws Exception
+       {
+               CountDownLatch initLatch = new CountDownLatch(3);
+               CountDownLatch destroyLatch = new CountDownLatch(3);
+               
+               TestServlet servlet1 = new TestServlet(initLatch, destroyLatch)
+               {
+                       private static final long serialVersionUID = 1L;
+                       
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException
+                       {
+                               resp.getWriter().print("servlet1");
+                               resp.flushBuffer();
+                       }
+               };
+               Dictionary<String, Object> props1 = new Hashtable<String, 
Object>();
+               
props1.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, 
"/servlet/1");
+               
props1.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servlet1");
+               props1.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, "(" 
+ SERVICE_HTTP_PORT + "=8080" + ")");
+               
+               TestServlet servlet2 = new TestServlet(initLatch, destroyLatch)
+               {
+                       private static final long serialVersionUID = 1L;
+                       
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException
+                       {
+                               resp.getWriter().print("servlet2");
+                               resp.flushBuffer();
+                       }
+               };
+               Dictionary<String, Object> props2 = new Hashtable<String, 
Object>();
+               
props2.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, 
"/servlet/2");
+               
props2.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servle2");
+               props2.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, "(" 
+ SERVICE_HTTP_PORT + "=8080" + ")");
+               
+               TestFilter filter = new TestFilter(initLatch, destroyLatch) 
+               {
+                       @Override
+                       protected void filter(HttpServletRequest req, 
HttpServletResponse resp, FilterChain chain) throws IOException, 
ServletException
+                       {
+                               String param = req.getParameter("param");
+                               if("forbidden".equals(param))
+                               {
+                                       resp.reset();
+                                       resp.sendError(SC_FORBIDDEN);
+                                       resp.flushBuffer();
+                               } 
+                               else 
+                               {
+                                       chain.doFilter(req, resp);
+                               }
+                       }
+               };
+
+               Dictionary<String, Object> props = new Hashtable<String, 
Object>();
+               
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN, "/servlet/1");
+               
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servletName");
+
+               ServiceRegistration<?> reg1 = 
m_context.registerService(Servlet.class.getName(), servlet1, props1);
+               ServiceRegistration<?> reg2 = 
m_context.registerService(Servlet.class.getName(), servlet2, props2);
+               ServiceRegistration<?> reg = 
m_context.registerService(Filter.class.getName(), filter, props);
+               
+               assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+               
+               assertResponseCode(SC_FORBIDDEN, 
createURL("/servlet/1?param=forbidden"));
+               assertContent("servlet1", createURL("/servlet/1?param=any"));
+               assertContent("servlet1", createURL("/servlet/1"));
+               
+               assertResponseCode(SC_OK, 
createURL("/servlet/2?param=forbidden"));
+               assertContent("servlet2", 
createURL("/servlet/2?param=forbidden"));
+               
+               reg1.unregister();
+               reg2.unregister();
+               reg.unregister();
+               
+               assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+       }       
+       
+       @Test
+       public void testFilterTargetMatchPort() throws Exception
+       {
+               CountDownLatch initLatch = new CountDownLatch(2);
+               CountDownLatch destroyLatch = new CountDownLatch(2);
+               
+               TestServlet servlet = new TestServlet(initLatch, destroyLatch)
+               {
+                       private static final long serialVersionUID = 1L;
+                       
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException
+                       {
+                               resp.getWriter().print("servlet");
+                               resp.flushBuffer();
+                       }
+               };
+               Dictionary<String, Object> sprops = new Hashtable<String, 
Object>();
+               
sprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet");
+               
sprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servlet1");
+               sprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, "(" 
+ SERVICE_HTTP_PORT + "=8080" + ")");
+               
+               TestFilter filter = new TestFilter(initLatch, destroyLatch) 
+               {
+                       @Override
+                       protected void filter(HttpServletRequest req, 
HttpServletResponse resp, FilterChain chain) throws IOException, 
ServletException
+                       {
+                               String param = req.getParameter("param");
+                               if("forbidden".equals(param))
+                               {
+                                       resp.reset();
+                                       resp.sendError(SC_FORBIDDEN);
+                                       resp.flushBuffer();
+                               } 
+                               else 
+                               {
+                                       chain.doFilter(req, resp);
+                               }
+                       }
+               };
+
+               Dictionary<String, Object> fprops = new Hashtable<String, 
Object>();
+               
fprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN, "/servlet");
+               
fprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servletName");
+               fprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, "(" 
+ SERVICE_HTTP_PORT + "=8080" + ")");
+
+               ServiceRegistration<?> sreg = 
m_context.registerService(Servlet.class.getName(), servlet, sprops);
+               ServiceRegistration<?> freg = 
m_context.registerService(Filter.class.getName(), filter, fprops);
+               
+               assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+               
+               assertResponseCode(SC_FORBIDDEN, 
createURL("/servlet?param=forbidden"));
+               assertContent("servlet", createURL("/servlet?param=any"));
+               assertContent("servlet", createURL("/servlet"));
+               
+               sreg.unregister();
+               freg.unregister();
+               
+               assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+       }       
+
+       @Test
+       public void testFilterTargetNotMatchPort() throws Exception
+       {
+               CountDownLatch servletInitLatch = new CountDownLatch(1);
+               CountDownLatch servletDestroyLatch = new CountDownLatch(1);
+               
+               CountDownLatch filterInitLatch = new CountDownLatch(1);
+               CountDownLatch filterDestroyLatch = new CountDownLatch(1);
+               
+               TestServlet servlet = new TestServlet(servletInitLatch, 
servletDestroyLatch)
+               {
+                       private static final long serialVersionUID = 1L;
+                       
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException
+                       {
+                               resp.getWriter().print("servlet");
+                               resp.flushBuffer();
+                       }
+               };
+               Dictionary<String, Object> sprops = new Hashtable<String, 
Object>();
+               
sprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet");
+               
sprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servlet1");
+               sprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, "(" 
+ SERVICE_HTTP_PORT + "=8080" + ")");
+               
+               TestFilter filter = new TestFilter(filterInitLatch, 
filterDestroyLatch) 
+               {
+                       @Override
+                       protected void filter(HttpServletRequest req, 
HttpServletResponse resp, FilterChain chain) throws IOException, 
ServletException
+                       {
+                               String param = req.getParameter("param");
+                               if("forbidden".equals(param))
+                               {
+                                       resp.reset();
+                                       resp.sendError(SC_FORBIDDEN);
+                                       resp.flushBuffer();
+                               } 
+                               else 
+                               {
+                                       chain.doFilter(req, resp);
+                               }
+                       }
+               };
+
+               Dictionary<String, Object> fprops = new Hashtable<String, 
Object>();
+               
fprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN, "/servlet");
+               
fprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "servletName");
+               fprops.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET, "(" 
+ SERVICE_HTTP_PORT + "=8181" + ")");
+
+               ServiceRegistration<?> sreg = 
m_context.registerService(Servlet.class.getName(), servlet, sprops);
+               ServiceRegistration<?> freg = 
m_context.registerService(Filter.class.getName(), filter, fprops);
+               
+               // servlet is registered
+               assertTrue(servletInitLatch.await(5, TimeUnit.SECONDS));
+               // fitler is not registered, timeout occurs
+               assertFalse(filterInitLatch.await(5, TimeUnit.SECONDS));
+               
+               assertResponseCode(SC_OK, 
createURL("/servlet?param=forbidden"));
+               assertContent("servlet", createURL("/servlet?param=forbidden"));
+               assertContent("servlet", createURL("/servlet?param=any"));
+               assertContent("servlet", createURL("/servlet"));
+               
+               sreg.unregister();
+               freg.unregister();
+               
+               assertTrue(servletDestroyLatch.await(5, TimeUnit.SECONDS));
+               assertFalse(filterDestroyLatch.await(5, TimeUnit.SECONDS));
+       }       
+}

Propchange: 
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/HttpWhiteboardTargetTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/ServletPatternTest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/ServletPatternTest.java?rev=1665462&view=auto
==============================================================================
--- 
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/ServletPatternTest.java
 (added)
+++ 
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/ServletPatternTest.java
 Tue Mar 10 10:45:02 2015
@@ -0,0 +1,170 @@
+/*
+ * 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.itest;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.Servlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
+
+
+@RunWith(JUnit4TestRunner.class)
+public class ServletPatternTest extends BaseIntegrationTest 
+{
+       
+       @Test
+       public void testHighRankReplaces() throws Exception
+       {
+               CountDownLatch initLatch = new CountDownLatch(2);
+               CountDownLatch destroyLatch = new CountDownLatch(2);
+               
+               TestServlet lowRankServlet = new TestServlet(initLatch, 
destroyLatch)
+               {
+                       private static final long serialVersionUID = 1L;
+                       
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException
+                       {
+                               resp.getWriter().print("lowRankServlet");
+                               resp.flushBuffer();
+                       }
+               };
+               
+               TestServlet highRankServlet = new TestServlet(initLatch, 
destroyLatch)
+               {
+                       private static final long serialVersionUID = 1L;
+                       
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException
+                       {
+                               resp.getWriter().print("highRankServlet");
+                               resp.flushBuffer();
+                       }
+               };
+               
+               Dictionary<String, Object> lowRankProps = new Hashtable<String, 
Object>();
+               String lowRankPattern[] = {"/foo", "/bar"};
+               
lowRankProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, 
lowRankPattern);
+               
lowRankProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX
 + ".myname", "lowRankServlet");
+               lowRankProps.put(Constants.SERVICE_RANKING, 1);
+               
+               ServiceRegistration<?> lowRankReg = 
m_context.registerService(Servlet.class.getName(), lowRankServlet, 
lowRankProps);
+               
+               Dictionary<String, Object> highRankProps = new 
Hashtable<String, Object>();
+               String highRankPattern[] = {"/foo", "/baz"};
+               
highRankProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, 
highRankPattern);
+               
highRankProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX
 + ".myname", "highRankServlet");
+               highRankProps.put(Constants.SERVICE_RANKING, 2);
+
+               ServiceRegistration<?> highRankReg = 
m_context.registerService(Servlet.class.getName(), highRankServlet, 
highRankProps);
+               
+               try {
+                       assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+                       
+                       assertContent("highRankServlet", createURL("/foo"));
+                       assertContent("lowRankServlet", createURL("/bar"));
+                       assertContent("highRankServlet", createURL("/baz"));
+                       
+               } finally {
+                       lowRankReg.unregister();
+                       highRankReg.unregister();
+               }
+               
+               assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+       }
+       
+       @Test
+       public void testSameRankDoesNotReplace() throws Exception
+       {
+               CountDownLatch initLatch = new CountDownLatch(2);
+               CountDownLatch destroyLatch = new CountDownLatch(2);
+               
+               TestServlet servlet1 = new TestServlet(initLatch, destroyLatch)
+               {
+                       private static final long serialVersionUID = 1L;
+                       
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException
+                       {
+                               resp.getWriter().print("servlet1");
+                               resp.flushBuffer();
+                       }
+               };
+               
+               TestServlet servlet2 = new TestServlet(initLatch, destroyLatch)
+               {
+                       private static final long serialVersionUID = 1L;
+                       
+                       @Override
+                       protected void doGet(HttpServletRequest req, 
HttpServletResponse resp) throws IOException
+                       {
+                               resp.getWriter().print("servlet2");
+                               resp.flushBuffer();
+                       }
+               };
+               
+               Dictionary<String, Object> props1 = new Hashtable<String, 
Object>();
+               String lowRankPattern[] = {"/foo", "/bar"};
+               
props1.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, 
lowRankPattern);
+               
props1.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "lowRankServlet");
+               props1.put(Constants.SERVICE_RANKING, 2);
+               
+               ServiceRegistration<?> reg1 = 
m_context.registerService(Servlet.class.getName(), servlet1, props1);
+               
+               Dictionary<String, Object> props2 = new Hashtable<String, 
Object>();
+               String highRankPattern[] = {"/foo", "/baz"};
+               
props2.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, 
highRankPattern);
+               
props2.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX + 
".myname", "highRankServlet");
+               props2.put(Constants.SERVICE_RANKING, 2);
+
+               ServiceRegistration<?> reg2 = 
m_context.registerService(Servlet.class.getName(), servlet2, props2);
+               
+               try {
+                       assertTrue(initLatch.await(5, TimeUnit.SECONDS));
+                       
+                       assertContent("servlet1", createURL("/foo"));
+                       assertContent("servlet1", createURL("/bar"));
+                       assertContent("servlet2", createURL("/baz"));
+                       
+               } finally {
+                       reg1.unregister();
+                       reg2.unregister();
+               }
+               
+               assertTrue(destroyLatch.await(5, TimeUnit.SECONDS));
+       }
+}
+
+
+

Propchange: 
felix/trunk/http/itest/src/test/java/org/apache/felix/http/itest/ServletPatternTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to