You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ja...@apache.org on 2015/03/10 11:45:03 UTC
svn commit: r1665462 - in /felix/trunk/http:
base/src/main/java/org/apache/felix/http/base/internal/
base/src/main/java/org/apache/felix/http/base/internal/handler/
base/src/main/java/org/apache/felix/http/base/internal/runtime/
base/src/main/java/org/...
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:dev@felix.apache.org">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:dev@felix.apache.org">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