You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cz...@apache.org on 2015/05/22 10:06:54 UTC

svn commit: r1681027 - in /felix/trunk/http/base/src: main/java/org/apache/felix/http/base/internal/dispatch/ main/java/org/apache/felix/http/base/internal/handler/ main/java/org/apache/felix/http/base/internal/registry/ main/java/org/apache/felix/http...

Author: cziegeler
Date: Fri May 22 08:06:54 2015
New Revision: 1681027

URL: http://svn.apache.org/r1681027
Log:
FELIX-4860 : Revisit HandlerRegistry implementation. Improve error page registration.

Modified:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.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/registry/ErrorPageRegistry.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.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/runtime/FilterInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionAttributeListenerInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionListenerInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextAttributeListenerInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextListenerInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestAttributeListenerInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestListenerInfo.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.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/util/UriUtils.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
    felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java
    felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java
    felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java Fri May 22 08:06:54 2015
@@ -22,9 +22,6 @@ package org.apache.felix.http.base.inter
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletContext;
 
-/**
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
 public interface RequestDispatcherProvider
 {
     /**

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java Fri May 22 08:06:54 2015
@@ -24,9 +24,6 @@ import javax.servlet.RequestDispatcher;
 import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.context.ExtServletContextWrapper;
 
-/**
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
- */
 class ServletContextWrapper extends ExtServletContextWrapper
 {
     private final RequestDispatcherProvider provider;

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/FilterHandler.java Fri May 22 08:06:54 2015
@@ -169,4 +169,25 @@ public class FilterHandler implements Co
         this.useCount = 1;
         return this.destroy();
     }
+
+    @Override
+    public int hashCode()
+    {
+        return 31 + filterInfo.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        final FilterHandler other = (FilterHandler) obj;
+        return filterInfo.equals(other.filterInfo);
+    }
 }

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HttpSessionWrapper.java Fri May 22 08:06:54 2015
@@ -40,8 +40,6 @@ import org.apache.felix.http.base.intern
 /**
  * The session wrapper keeps track of the internal session, manages their attributes
  * separately and also handles session timeout.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class HttpSessionWrapper implements HttpSession
 {

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=1681027&r1=1681026&r2=1681027&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 Fri May 22 08:06:54 2015
@@ -167,4 +167,26 @@ public abstract class ServletHandler imp
         this.useCount = 1;
         return this.destroy();
     }
+
+    @Override
+    public int hashCode()
+    {
+        return 31 + servletInfo.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        final ServletHandler other = (ServletHandler) obj;
+        return servletInfo.equals(other.servletInfo);
+    }
+
 }

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java Fri May 22 08:06:54 2015
@@ -28,10 +28,12 @@ import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.regex.Pattern;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 
 import org.apache.felix.http.base.internal.handler.ServletHandler;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.runtime.dto.BuilderConstants;
 import org.apache.felix.http.base.internal.runtime.dto.ErrorPageDTOBuilder;
 import org.osgi.service.http.runtime.dto.DTOConstants;
 import org.osgi.service.http.runtime.dto.ErrorPageDTO;
@@ -52,6 +54,43 @@ public final class ErrorPageRegistry
     private static final List<Long> CLIENT_ERROR_CODES = hundredOf(400);
     private static final List<Long> SERVER_ERROR_CODES = hundredOf(500);
 
+    private final Map<String, List<ServletHandler>> errorMapping = new ConcurrentHashMap<String, List<ServletHandler>>();
+
+    private volatile List<ErrorRegistrationStatus> status = Collections.emptyList();
+
+    public static final class ErrorRegistration {
+        public final long[] errorCodes;
+        public final String[] exceptions;
+
+        public ErrorRegistration(final long[] errorCodes, final String[] exceptions)
+        {
+            this.errorCodes = errorCodes;
+            this.exceptions = exceptions;
+        }
+    }
+
+    static final class ErrorRegistrationStatus implements Comparable<ErrorRegistrationStatus> {
+
+        private final ServletHandler handler;
+        public final Map<Integer, ErrorRegistration> reasonMapping = new HashMap<Integer, ErrorRegistration>();
+
+        public ErrorRegistrationStatus(final ServletHandler handler)
+        {
+            this.handler = handler;
+        }
+
+        public ServletHandler getHandler()
+        {
+            return this.handler;
+        }
+
+        @Override
+        public int compareTo(final ErrorRegistrationStatus o)
+        {
+            return this.handler.compareTo(o.getHandler());
+        }
+    }
+
     private static List<Long> hundredOf(final int start)
     {
         List<Long> result = new ArrayList<Long>();
@@ -62,6 +101,51 @@ public final class ErrorPageRegistry
         return Collections.unmodifiableList(result);
     }
 
+    private static long[] toLongArray(final Set<Long> set)
+    {
+        long[] codes = BuilderConstants.EMPTY_LONG_ARRAY;
+        if ( !set.isEmpty() )
+        {
+            codes = new long[set.size()];
+            int index = 0;
+            for(final Long code : set)
+            {
+                codes[index++] = code;
+            }
+        }
+        return codes;
+    }
+
+    private static Set<Long> toLongSet(final long[] codes)
+    {
+        final Set<Long> set = new TreeSet<Long>();
+        for(final long c : codes)
+        {
+            set.add(c);
+        }
+        return set;
+    }
+
+    private static String[] toStringArray(final Set<String> set)
+    {
+        String[] array = BuilderConstants.EMPTY_STRING_ARRAY;
+        if ( !set.isEmpty() )
+        {
+            array = set.toArray(new String[set.size()]);
+        }
+        return array;
+    }
+
+    private static Set<String> toStringSet(final String[] array)
+    {
+        final Set<String> set = new TreeSet<String>();
+        for(final String s : array)
+        {
+            set.add(s);
+        }
+        return set;
+    }
+
     private static String parseErrorCodes(final Set<Long> codes, final String string)
     {
         if (CLIENT_ERROR.equalsIgnoreCase(string))
@@ -83,41 +167,30 @@ public final class ErrorPageRegistry
         return null;
     }
 
-    private final Map<Long, List<ServletHandler>> errorCodesMap = new ConcurrentHashMap<Long, List<ServletHandler>>();
-    private final Map<String, List<ServletHandler>> exceptionsMap = new ConcurrentHashMap<String, List<ServletHandler>>();
-
-    private final Map<ServletInfo, ErrorRegistrationStatus> statusMapping = new ConcurrentHashMap<ServletInfo, ErrorRegistrationStatus>();
-
-    public static final class ErrorRegistration {
-        public final Set<Long> errorCodes = new TreeSet<Long>();
-        public final Set<String> exceptions = new TreeSet<String>();
-    }
-
-    static final class ErrorRegistrationStatus {
-        ServletHandler handler;
-        final Map<Long, Integer> errorCodeMapping = new ConcurrentHashMap<Long, Integer>();
-        final Map<String, Integer> exceptionMapping = new ConcurrentHashMap<String, Integer>();
-    }
-
-    Map<ServletInfo, ErrorRegistrationStatus> getStatusMapping()
-    {
-        return this.statusMapping;
-    }
-
-    public static ErrorRegistration getErrorRegistration(@Nonnull final ServletInfo info)
+    /**
+     * Parse the registration properties of the servlet for error handling
+     * @param info The servlet info
+     * @return An error registration object if the servlet handles errors
+     */
+    public static @CheckForNull ErrorRegistration getErrorRegistration(@Nonnull final ServletInfo info)
     {
         if ( info.getErrorPage() != null )
         {
-            final ErrorRegistration reg = new ErrorRegistration();
+            final Set<Long> errorCodes = new TreeSet<Long>();
+            final Set<String> exceptions = new TreeSet<String>();
+
             for(final String val : info.getErrorPage())
             {
-                final String exception = parseErrorCodes(reg.errorCodes, val);
+                final String exception = parseErrorCodes(errorCodes, val);
                 if ( exception != null )
                 {
-                    reg.exceptions.add(exception);
+                    exceptions.add(exception);
                 }
             }
-            return reg;
+            final long[] codes = toLongArray(errorCodes);
+            final String[] exceptionsArray = toStringArray(exceptions);
+
+            return new ErrorRegistration(codes, exceptionsArray);
         }
         return null;
     }
@@ -131,87 +204,19 @@ public final class ErrorPageRegistry
         final ErrorRegistration reg = getErrorRegistration(handler.getServletInfo());
         if ( reg != null )
         {
-            final ErrorRegistrationStatus status = new ErrorRegistrationStatus();
-            status.handler = handler;
+            final ErrorRegistrationStatus status = new ErrorRegistrationStatus(handler);
             for(final long code : reg.errorCodes)
             {
-                List<ServletHandler> list = errorCodesMap.get(code);
-                if ( list == null )
-                {
-                    // activate
-                    if ( tryToActivate(code, handler, status) )
-                    {
-                        final List<ServletHandler> newList = new ArrayList<ServletHandler>(1);
-                        newList.add(handler);
-                        errorCodesMap.put(code, newList);
-                    }
-                }
-                else
-                {
-                    final List<ServletHandler> newList = new ArrayList<ServletHandler>(list);
-                    newList.add(handler);
-                    Collections.sort(newList);
-
-                    if ( newList.get(0) == handler )
-                    {
-                        // activate and reactive
-                        if ( tryToActivate(code, handler, status) )
-                        {
-                            final ServletHandler old = list.get(0);
-                            old.destroy();
-                            errorCodesMap.put(code, newList);
-                            final ErrorRegistrationStatus oldStatus = statusMapping.get(old.getServletInfo());
-                            oldStatus.errorCodeMapping.put(code, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
-                        }
-                    }
-                    else
-                    {
-                        // failure
-                        status.errorCodeMapping.put(code, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
-                        errorCodesMap.put(code, newList);
-                    }
-                }
+                addErrorHandling(handler, status, code, null);
             }
             for(final String exception : reg.exceptions)
             {
-                List<ServletHandler> list = exceptionsMap.get(exception);
-                if ( list == null )
-                {
-                    // activate
-                    if ( tryToActivate(exception, handler, status) )
-                    {
-                        final List<ServletHandler> newList = new ArrayList<ServletHandler>(1);
-                        newList.add(handler);
-                        exceptionsMap.put(exception, newList);
-                    }
-                }
-                else
-                {
-                    final List<ServletHandler> newList = new ArrayList<ServletHandler>(list);
-                    newList.add(handler);
-                    Collections.sort(newList);
-
-                    if ( newList.get(0) == handler )
-                    {
-                        // activate and reactive
-                        if ( tryToActivate(exception, handler, status) )
-                        {
-                            final ServletHandler old = list.get(0);
-                            old.destroy();
-                            exceptionsMap.put(exception, newList);
-                            final ErrorRegistrationStatus oldStatus = statusMapping.get(old.getServletInfo());
-                            oldStatus.exceptionMapping.put(exception, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
-                        }
-                    }
-                    else
-                    {
-                        // failure
-                        status.exceptionMapping.put(exception, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
-                        exceptionsMap.put(exception, newList);
-                    }
-                }
+                addErrorHandling(handler, status, 0, exception);
             }
-            this.statusMapping.put(handler.getServletInfo(), status);
+            final List<ErrorRegistrationStatus> newList = new ArrayList<ErrorPageRegistry.ErrorRegistrationStatus>(this.status);
+            newList.add(status);
+            Collections.sort(newList);
+            this.status = newList;
         }
     }
 
@@ -224,102 +229,213 @@ public final class ErrorPageRegistry
         final ErrorRegistration reg = getErrorRegistration(info);
         if ( reg != null )
         {
-            this.statusMapping.remove(info);
+            final List<ErrorRegistrationStatus> newList = new ArrayList<ErrorPageRegistry.ErrorRegistrationStatus>(this.status);
+            final Iterator<ErrorRegistrationStatus> i = newList.iterator();
+            while ( i.hasNext() )
+            {
+                final ErrorRegistrationStatus status = i.next();
+                if ( status.handler.getServletInfo().equals(info) )
+                {
+                    i.remove();
+                    break;
+                }
+            }
+            this.status = newList;
+
             for(final long code : reg.errorCodes)
             {
-                final List<ServletHandler> list = errorCodesMap.get(code);
+                removeErrorHandling(info, code, null);
+            }
+            for(final String exception : reg.exceptions)
+            {
+                removeErrorHandling(info, 0, exception);
+            }
+        }
+    }
+
+    private void addErrorHandling(final ServletHandler handler, final ErrorRegistrationStatus status, final long code, final String exception)
+    {
+        final String key = (exception != null ? exception : String.valueOf(code));
+
+        final List<ServletHandler> newList;
+        final List<ServletHandler> list = errorMapping.get(key);
+        if ( list == null )
+        {
+            newList = Collections.singletonList(handler);
+        }
+        else
+        {
+            newList = new ArrayList<ServletHandler>(list);
+            newList.add(handler);
+            Collections.sort(newList);
+        }
+        if ( newList.get(0) == handler )
+        {
+            // try to activate (and deactivate old handler)
+            final int result = handler.init();
+            addReason(status, code, exception, result);
+            if ( result == -1 )
+            {
                 if ( list != null )
                 {
-                    int index = 0;
-                    final Iterator<ServletHandler> i = list.iterator();
-                    while ( i.hasNext() )
+                    final ServletHandler old = list.get(0);
+                    old.destroy();
+                    errorMapping.put(key, newList);
+                    ErrorRegistrationStatus oldStatus = null;
+                    final Iterator<ErrorRegistrationStatus> i = this.status.iterator();
+                    while ( oldStatus == null && i.hasNext() )
                     {
-                        final ServletHandler handler = i.next();
-                        if ( handler.getServletInfo().equals(info) )
+                        final ErrorRegistrationStatus current = i.next();
+                        if ( current.handler.getServletInfo().equals(old.getServletInfo()) )
                         {
-                            handler.destroy();
-
-                            final List<ServletHandler> newList = new ArrayList<ServletHandler>(list);
-                            newList.remove(handler);
-
-                            if ( index == 0 )
-                            {
-                                index++;
-                                while ( index < list.size() )
-                                {
-                                    final ServletHandler next = list.get(index);
-                                    if ( tryToActivate(code, next, statusMapping.get(next.getServletInfo())) )
-                                    {
-                                        break;
-                                    }
-                                    else
-                                    {
-                                        newList.remove(next);
-                                    }
-                                }
-                            }
-                            if ( newList.isEmpty() )
-                            {
-                                errorCodesMap.remove(code);
-                            }
-                            else
-                            {
-                                errorCodesMap.put(code, newList);
-                            }
-
-                            break;
+                            oldStatus = current;
                         }
-                        index++;
+                    }
+                    if ( oldStatus != null )
+                    {
+                        removeReason(oldStatus, code, exception, -1);
+                        addReason(oldStatus, code, exception, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
                     }
                 }
+                else
+                {
+                    errorMapping.put(key, newList);
+                }
             }
-            for(final String exception : reg.exceptions)
+        }
+        else
+        {
+            // failure
+            addReason(status, code, exception, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+            errorMapping.put(key, newList);
+        }
+    }
+
+    private void addReason(final ErrorRegistrationStatus status, final long code, final String exception, final int reason)
+    {
+        ErrorRegistration reg = status.reasonMapping.get(reason);
+        if ( reg == null )
+        {
+            if ( exception != null )
             {
-                final List<ServletHandler> list = exceptionsMap.get(exception);
-                if ( list != null )
+                reg = new ErrorRegistration(BuilderConstants.EMPTY_LONG_ARRAY, new String[] {exception});
+            }
+            else
+            {
+                reg = new ErrorRegistration(new long[] {code}, BuilderConstants.EMPTY_STRING_ARRAY);
+            }
+        }
+        else
+        {
+            long[] codes = reg.errorCodes;
+            String[] exceptions = reg.exceptions;
+            if ( exception != null )
+            {
+                final Set<String> set = toStringSet(exceptions);
+                set.add(exception);
+                exceptions = toStringArray(set);
+            }
+            else
+            {
+                final Set<Long> set = toLongSet(codes);
+                set.add(code);
+                codes = toLongArray(set);
+            }
+
+            reg = new ErrorRegistration(codes, exceptions);
+        }
+        status.reasonMapping.put(reason, reg);
+    }
+
+    private void removeReason(final ErrorRegistrationStatus status, final long code, final String exception, final int reason)
+    {
+        ErrorRegistration reg = status.reasonMapping.get(reason);
+        if ( reg != null )
+        {
+            long[] codes = reg.errorCodes;
+            String[] exceptions = reg.exceptions;
+            if ( exception != null )
+            {
+                final Set<String> set = toStringSet(exceptions);
+                set.remove(exception);
+                exceptions = toStringArray(set);
+            }
+            else
+            {
+                final Set<Long> set = toLongSet(codes);
+                set.remove(code);
+                codes = toLongArray(set);
+            }
+            if ( codes.length == 0 && exceptions.length == 0 )
+            {
+                status.reasonMapping.remove(reason);
+            }
+            else
+            {
+                status.reasonMapping.put(reason, new ErrorRegistration(codes, exceptions));
+            }
+        }
+    }
+
+    private void removeErrorHandling(final ServletInfo info, final long code, final String exception)
+    {
+        final String key = (exception != null ? exception : String.valueOf(code));
+
+        final List<ServletHandler> list = errorMapping.get(key);
+        if ( list != null )
+        {
+            int index = 0;
+            final Iterator<ServletHandler> i = list.iterator();
+            while ( i.hasNext() )
+            {
+                final ServletHandler handler = i.next();
+                if ( handler.getServletInfo().equals(info) )
                 {
-                    int index = 0;
-                    final Iterator<ServletHandler> i = list.iterator();
-                    while ( i.hasNext() )
-                    {
-                        final ServletHandler handler = i.next();
-                        if ( handler.getServletInfo().equals(info) )
-                        {
-                            handler.destroy();
+                    final List<ServletHandler> newList = new ArrayList<ServletHandler>(list);
+                    newList.remove(handler);
 
-                            final List<ServletHandler> newList = new ArrayList<ServletHandler>(list);
-                            newList.remove(handler);
+                    if ( index == 0 )
+                    {
+                        handler.destroy();
 
-                            if ( index == 0 )
+                        index++;
+                        while ( index < list.size() )
+                        {
+                            final ServletHandler next = list.get(index);
+                            ErrorRegistrationStatus nextStatus = null;
+                            for(final ErrorRegistrationStatus s : this.status)
                             {
-                                index++;
-                                while ( index < list.size() )
+                                if ( s.handler.getServletInfo().equals(next.getServletInfo()) )
                                 {
-                                    final ServletHandler next = list.get(index);
-                                    if ( tryToActivate(exception, next, statusMapping.get(next.getServletInfo())) )
-                                    {
-                                        break;
-                                    }
-                                    else
-                                    {
-                                        newList.remove(next);
-                                    }
+                                    nextStatus = s;
+                                    break;
                                 }
                             }
-                            if ( newList.isEmpty() )
+                            this.removeReason(nextStatus, code, exception, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                            final int reason = next.init();
+                            this.addReason(nextStatus, code, exception, reason);
+                            if ( reason == -1 )
                             {
-                                exceptionsMap.remove(exception);
+                                break;
                             }
                             else
                             {
-                                exceptionsMap.put(exception, newList);
+                                newList.remove(next);
                             }
-
-                            break;
                         }
-                        index++;
                     }
+                    if ( newList.isEmpty() )
+                    {
+                        errorMapping.remove(key);
+                    }
+                    else
+                    {
+                        errorMapping.put(key, newList);
+                    }
+
+                    break;
                 }
+                index++;
             }
         }
     }
@@ -351,7 +467,7 @@ public final class ErrorPageRegistry
      */
     private ServletHandler get(final long errorCode)
     {
-        final List<ServletHandler> list = this.errorCodesMap.get(errorCode);
+        final List<ServletHandler> list = this.errorMapping.get(String.valueOf(errorCode));
         if ( list != null )
         {
             return list.get(0);
@@ -375,7 +491,7 @@ public final class ErrorPageRegistry
         Class<?> throwableClass = exception.getClass();
         while ( servletHandler == null && throwableClass != null )
         {
-            final List<ServletHandler> list = this.exceptionsMap.get(throwableClass.getName());
+            final List<ServletHandler> list = this.errorMapping.get(throwableClass.getName());
             if ( list != null )
             {
                 servletHandler = list.get(0);
@@ -394,121 +510,31 @@ public final class ErrorPageRegistry
     }
 
     /**
-     * Try to activate a servlet for an error code
-     * @param code The error code
-     * @param handler The servlet handler
-     * @param status The status to keep track of activation
-     * @return {@code -1} if activation was successful, failure code otherwise
+     * Get DTOs for error pages.
+     * @param dto The servlet context DTO
+     * @param failedErrorPageDTOs The failed error page DTOs
      */
-    private boolean tryToActivate(final Long code, final ServletHandler handler, final ErrorRegistrationStatus status)
-    {
-        // add to active
-        final int result = handler.init();
-        status.errorCodeMapping.put(code, result);
-
-        return result == -1;
-    }
-
-    /**
-     * Try to activate a servlet for an exception
-     * @param exception The exception
-     * @param handler The servlet handler
-     * @param status The status to keep track of activation
-     * @return {@code -1} if activation was successful, failure code otherwise
-     */
-    private boolean tryToActivate(final String exception, final ServletHandler handler, final ErrorRegistrationStatus status)
-    {
-        // add to active
-        final int result = handler.init();
-        status.exceptionMapping.put(exception, result);
-
-        return result == -1;
-    }
-
     public void getRuntimeInfo(final ServletContextDTO dto,
             final Collection<FailedErrorPageDTO> failedErrorPageDTOs)
     {
-        final Collection<ErrorPageDTO> errorPageDTOs = new ArrayList<ErrorPageDTO>();
-
-        for(final ErrorRegistrationStatus status : this.statusMapping.values())
+        final List<ErrorPageDTO> errorPageDTOs = new ArrayList<ErrorPageDTO>();
+        final List<ErrorRegistrationStatus> statusList = this.status;
+        for(final ErrorRegistrationStatus status : statusList)
         {
-            // TODO - we could do this calculation already when generating the status object
-            final ErrorRegistration active = new ErrorRegistration();
-            final Map<Integer, ErrorRegistration> inactive = new HashMap<Integer, ErrorRegistration>();
-
-            for(Map.Entry<Long, Integer> codeEntry : status.errorCodeMapping.entrySet() )
+            for(final Map.Entry<Integer, ErrorRegistration> entry : status.reasonMapping.entrySet())
             {
-                if ( codeEntry.getValue() == -1 )
-                {
-                    active.errorCodes.add(codeEntry.getKey());
-                }
-                else
-                {
-                    ErrorRegistration set = inactive.get(codeEntry.getValue());
-                    if ( set == null )
-                    {
-                        set = new ErrorRegistration();
-                        inactive.put(codeEntry.getValue(), set);
-                    }
-                    set.errorCodes.add(codeEntry.getKey());
-                }
-            }
-            for(Map.Entry<String, Integer> codeEntry : status.exceptionMapping.entrySet() )
-            {
-                if ( codeEntry.getValue() == -1 )
-                {
-                    active.exceptions.add(codeEntry.getKey());
-                }
-                else
-                {
-                    ErrorRegistration set = inactive.get(codeEntry.getValue());
-                    if ( set == null )
-                    {
-                        set = new ErrorRegistration();
-                        inactive.put(codeEntry.getValue(), set);
-                    }
-                    set.exceptions.add(codeEntry.getKey());
-                }
-            }
+                final ErrorPageDTO state = ErrorPageDTOBuilder.build(status.getHandler(), entry.getKey());
+                state.errorCodes = entry.getValue().errorCodes;
+                state.exceptions = entry.getValue().exceptions;
 
-            // create DTOs
-            if ( !active.errorCodes.isEmpty() || !active.exceptions.isEmpty() )
-            {
-                final ErrorPageDTO state = ErrorPageDTOBuilder.build(status.handler, -1);
-                if ( !active.errorCodes.isEmpty() )
+                if ( entry.getKey() == -1 )
                 {
-                    final long[] codes = new long[active.errorCodes.size()];
-                    final Iterator<Long> iter = active.errorCodes.iterator();
-                    for(int i=0; i<codes.length; i++)
-                    {
-                        codes[i] = iter.next();
-                    }
-                    state.errorCodes = codes;
+                    errorPageDTOs.add(state);
                 }
-                if ( !active.exceptions.isEmpty() )
-                {
-                    state.exceptions = active.exceptions.toArray(new String[active.exceptions.size()]);
-                }
-                errorPageDTOs.add(state);
-            }
-            for(final Map.Entry<Integer, ErrorRegistration> entry : inactive.entrySet())
-            {
-                final FailedErrorPageDTO state = (FailedErrorPageDTO)ErrorPageDTOBuilder.build(status.handler, entry.getKey());
-                if ( !entry.getValue().errorCodes.isEmpty() )
-                {
-                    final long[] codes = new long[entry.getValue().errorCodes.size()];
-                    final Iterator<Long> iter = entry.getValue().errorCodes.iterator();
-                    for(int i=0; i<codes.length; i++)
-                    {
-                        codes[i] = iter.next();
-                    }
-                    state.errorCodes = codes;
-                }
-                if ( !entry.getValue().exceptions.isEmpty() )
+                else
                 {
-                    state.exceptions = entry.getValue().exceptions.toArray(new String[entry.getValue().exceptions.size()]);
+                    failedErrorPageDTOs.add((FailedErrorPageDTO)state);
                 }
-                failedErrorPageDTOs.add(state);
             }
         }
         if ( !errorPageDTOs.isEmpty() )

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterRegistry.java Fri May 22 08:06:54 2015
@@ -193,8 +193,8 @@ public final class FilterRegistry
                         break;
                     }
                 }
-                // check for servlet name
-                final String servletName = (handler != null) ? handler.getName() : null;
+                // check for servlet name if it's not a resource
+                final String servletName = (handler != null && !handler.getServletInfo().isResource()) ? handler.getName() : null;
                 if ( !added && servletName != null && status.getHandler().getFilterInfo().getServletNames() != null )
                 {
                     for(final String name : status.getHandler().getFilterInfo().getServletNames())

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java Fri May 22 08:06:54 2015
@@ -20,9 +20,11 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import javax.annotation.Nonnull;
@@ -100,8 +102,15 @@ public final class ServletRegistry
             status.handler = handler;
 
             boolean isActive = false;
+            // used for detecting duplicates
+            final Set<String> patterns = new HashSet<String>();
             for(final String pattern : handler.getServletInfo().getPatterns())
             {
+                if ( patterns.contains(pattern) )
+                {
+                    continue;
+                }
+                patterns.add(pattern);
                 final PathResolver regHandler = this.activeServletMappings.get(pattern);
                 if ( regHandler != null )
                 {
@@ -207,8 +216,15 @@ public final class ServletRegistry
             this.statusMapping.remove(info);
             ServletHandler cleanupHandler = null;
 
+            // used for detecting duplicates
+            final Set<String> patterns = new HashSet<String>();
             for(final String pattern : info.getPatterns())
             {
+                if ( patterns.contains(pattern) )
+                {
+                    continue;
+                }
+                patterns.add(pattern);
                 final PathResolver regHandler = this.activeServletMappings.get(pattern);
                 if ( regHandler != null && regHandler.getServletHandler().getServletInfo().equals(info) )
                 {

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=1681027&r1=1681026&r2=1681027&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 Fri May 22 08:06:54 2015
@@ -204,28 +204,21 @@ public abstract class AbstractInfo<T> im
     @Override
     public int hashCode()
     {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ranking;
-        result = prime * result + (int) (serviceId ^ (serviceId >>> 32));
-        return result;
+        return 31 + (int) (serviceId ^ (serviceId >>> 32));
     }
 
     @Override
     public boolean equals(final Object obj)
     {
         if (this == obj)
+        {
             return true;
-        if (obj == null)
+        }
+        if (obj == null || getClass() != obj.getClass())
+        {
             return false;
-        if (getClass() != obj.getClass())
-            return false;
-        @SuppressWarnings("unchecked")
-        final AbstractInfo<T> other = (AbstractInfo<T>) obj;
-        if (ranking != other.ranking)
-            return false;
-        if (serviceId != other.serviceId)
-            return false;
-        return true;
+        }
+        final AbstractInfo<?> other = (AbstractInfo<?>) obj;
+        return serviceId == other.serviceId;
     }
 }

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/FilterInfo.java Fri May 22 08:06:54 2015
@@ -20,10 +20,13 @@ package org.apache.felix.http.base.inter
 
 import java.util.Collections;
 import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
 
 import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
 
+import org.apache.felix.http.base.internal.util.PatternUtil;
 import org.osgi.dto.DTO;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.runtime.dto.FilterDTO;
@@ -34,8 +37,6 @@ import org.osgi.service.http.whiteboard.
  * <p>
  * This class only provides information used at registration time, and as such differs slightly from {@link DTO}s like, {@link FilterDTO}.
  * </p>
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public final class FilterInfo extends WhiteboardServiceInfo<Filter>
 {
@@ -110,7 +111,15 @@ public final class FilterInfo extends Wh
             DispatcherType[] dispatchers = new DispatcherType[dispatcherNames.length];
             for (int i = 0; i < dispatchers.length; i++)
             {
-                dispatchers[i] = DispatcherType.valueOf(dispatcherNames[i].toUpperCase());
+                try
+                {
+                    dispatchers[i] = DispatcherType.valueOf(dispatcherNames[i].toUpperCase());
+                }
+                catch ( final IllegalArgumentException iae)
+                {
+                    dispatchers = null;
+                    break;
+                }
             }
             this.dispatcher = dispatchers;
         }
@@ -141,7 +150,44 @@ public final class FilterInfo extends Wh
     @Override
     public boolean isValid()
     {
-        return super.isValid() && (!isEmpty(this.patterns) || !isEmpty(this.regexs) || !isEmpty(this.servletNames));
+        boolean valid = super.isValid() && (!isEmpty(this.patterns) || !isEmpty(this.regexs) || !isEmpty(this.servletNames));
+        if ( valid )
+        {
+            if ( this.patterns != null )
+            {
+                for(final String p : this.patterns)
+                {
+                    if ( !PatternUtil.isValidPattern(p) )
+                    {
+                        valid = false;
+                        break;
+                    }
+                }
+            }
+            if ( valid && this.regexs != null )
+            {
+                for(final String p : this.regexs)
+                {
+                    try
+                    {
+                        Pattern.compile(p);
+                    }
+                    catch ( final PatternSyntaxException pse)
+                    {
+                        valid = false;
+                        break;
+                    }
+                }
+            }
+        }
+        if ( valid )
+        {
+            if ( this.dispatcher == null || this.dispatcher.length == 0 )
+            {
+                valid = false;
+            }
+        }
+        return valid;
     }
 
     public String getName()

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionAttributeListenerInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionAttributeListenerInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionAttributeListenerInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionAttributeListenerInfo.java Fri May 22 08:06:54 2015
@@ -24,8 +24,6 @@ import org.osgi.framework.ServiceReferen
 
 /**
  * Info object for registered servlet context listeners
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public final class HttpSessionAttributeListenerInfo extends ListenerInfo<HttpSessionAttributeListener>
 {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionIdListenerInfo.java Fri May 22 08:06:54 2015
@@ -24,8 +24,6 @@ import org.osgi.framework.ServiceReferen
 
 /**
  * Info object for registered http session id listeners
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public final class HttpSessionIdListenerInfo extends ListenerInfo<HttpSessionIdListener>
 {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionListenerInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionListenerInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionListenerInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/HttpSessionListenerInfo.java Fri May 22 08:06:54 2015
@@ -24,8 +24,6 @@ import org.osgi.framework.ServiceReferen
 
 /**
  * Info object for registered servlet context listeners
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public final class HttpSessionListenerInfo extends ListenerInfo<HttpSessionListener>
 {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ListenerInfo.java Fri May 22 08:06:54 2015
@@ -19,14 +19,13 @@
 package org.apache.felix.http.base.internal.runtime;
 
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceObjects;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
 /**
  * Info object for registered listeners.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public abstract class ListenerInfo<T> extends WhiteboardServiceInfo<T>
 {
@@ -50,10 +49,14 @@ public abstract class ListenerInfo<T> ex
     {
         if (this.getServiceReference() != null)
         {
-            final ServiceObjects<T> so = bundle.getBundleContext().getServiceObjects(this.getServiceReference());
-            if (so != null)
+            final BundleContext bctx = bundle.getBundleContext();
+            if ( bctx != null )
             {
-                return so.getService();
+                final ServiceObjects<T> so = bctx.getServiceObjects(this.getServiceReference());
+                if (so != null)
+                {
+                    return so.getService();
+                }
             }
         }
         return null;
@@ -63,10 +66,14 @@ public abstract class ListenerInfo<T> ex
     {
         if (this.getServiceReference() != null)
         {
-            final ServiceObjects<T> so = bundle.getBundleContext().getServiceObjects(this.getServiceReference());
-            if (so != null)
+            final BundleContext bctx = bundle.getBundleContext();
+            if ( bctx != null )
             {
-                so.ungetService(service);
+                final ServiceObjects<T> so = bctx.getServiceObjects(this.getServiceReference());
+                if (so != null)
+                {
+                    so.ungetService(service);
+                }
             }
         }
     }

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java Fri May 22 08:06:54 2015
@@ -22,9 +22,7 @@ import org.osgi.framework.ServiceReferen
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
 /**
- *
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * Info object for a resource registration
  */
 public final class ResourceInfo extends WhiteboardServiceInfo<Object>
 {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextAttributeListenerInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextAttributeListenerInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextAttributeListenerInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextAttributeListenerInfo.java Fri May 22 08:06:54 2015
@@ -24,8 +24,6 @@ import org.osgi.framework.ServiceReferen
 
 /**
  * Info object for registered servlet context attribute listeners
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public final class ServletContextAttributeListenerInfo extends ListenerInfo<ServletContextAttributeListener>
 {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextListenerInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextListenerInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextListenerInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletContextListenerInfo.java Fri May 22 08:06:54 2015
@@ -24,8 +24,6 @@ import org.osgi.framework.ServiceReferen
 
 /**
  * Info object for registered servlet context listeners
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public final class ServletContextListenerInfo extends ListenerInfo<ServletContextListener>
 {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java Fri May 22 08:06:54 2015
@@ -23,6 +23,7 @@ import java.util.Map;
 
 import javax.servlet.Servlet;
 
+import org.apache.felix.http.base.internal.util.PatternUtil;
 import org.osgi.dto.DTO;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.runtime.dto.ServletDTO;
@@ -33,8 +34,6 @@ import org.osgi.service.http.whiteboard.
  * <p>
  * This class only provides information used at registration time, and as such differs slightly from {@link DTO}s like, {@link ServletDTO}.
  * </p>
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class ServletInfo extends WhiteboardServiceInfo<Servlet>
 {
@@ -128,28 +127,25 @@ public class ServletInfo extends Whitebo
         this.prefix = null;
     }
 
-    ServletInfo(int serviceRanking,
-            long serviceId,
-            String name,
-            String[] patterns,
-            String[] errorPage,
-            boolean asyncSupported,
-            Map<String, String> initParams)
-    {
-        super(serviceRanking, serviceId);
-        this.name = name;
-        this.patterns = patterns;
-        this.errorPage = errorPage;
-        this.asyncSupported = asyncSupported;
-        this.initParams = Collections.unmodifiableMap(initParams);
-        this.isResource = false;
-        this.prefix = null;
-    }
-
     @Override
     public boolean isValid()
     {
-        return super.isValid() && !(isEmpty(this.patterns) && isEmpty(this.errorPage));
+        boolean valid = super.isValid() && !(isEmpty(this.patterns) && isEmpty(this.errorPage));
+        if ( valid )
+        {
+            if ( this.patterns != null )
+            {
+                for(final String p : this.patterns)
+                {
+                    if ( !PatternUtil.isValidPattern(p) )
+                    {
+                        valid = false;
+                        break;
+                    }
+                }
+            }
+        }
+        return valid;
     }
 
     public String getName()

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestAttributeListenerInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestAttributeListenerInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestAttributeListenerInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestAttributeListenerInfo.java Fri May 22 08:06:54 2015
@@ -24,8 +24,6 @@ import org.osgi.framework.ServiceReferen
 
 /**
  * Info object for registered servlet context listeners
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public final class ServletRequestAttributeListenerInfo extends ListenerInfo<ServletRequestAttributeListener>
 {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestListenerInfo.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestListenerInfo.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestListenerInfo.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletRequestListenerInfo.java Fri May 22 08:06:54 2015
@@ -24,8 +24,6 @@ import org.osgi.framework.ServiceReferen
 
 /**
  * Info object for registered servlet context listeners
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public final class ServletRequestListenerInfo extends ListenerInfo<ServletRequestListener>
 {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java Fri May 22 08:06:54 2015
@@ -19,7 +19,6 @@
 package org.apache.felix.http.base.internal.runtime.dto;
 
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -77,21 +76,8 @@ public final class FailedDTOHolder
                 final FailedErrorPageDTO dto = (FailedErrorPageDTO)ErrorPageDTOBuilder.build((ServletInfo)info, true);
                 dto.failureReason = failureCode;
                 final ErrorPageRegistry.ErrorRegistration  reg = ErrorPageRegistry.getErrorRegistration((ServletInfo)info);
-                if ( !reg.errorCodes.isEmpty() )
-                {
-                    final long[] codes = new long[reg.errorCodes.size()];
-                    int index = 0;
-                    final Iterator<Long> i = reg.errorCodes.iterator();
-                    while ( i.hasNext() )
-                    {
-                        codes[index++] = i.next();
-                    }
-                    dto.errorCodes = codes;
-                }
-                if ( !reg.exceptions.isEmpty() )
-                {
-                    dto.exceptions = reg.exceptions.toArray(new String[reg.exceptions.size()]);
-                }
+                dto.errorCodes = reg.errorCodes;
+                dto.exceptions = reg.exceptions;
                 this.failedErrorPageDTOs.add(dto);
             }
 

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=1681027&r1=1681026&r2=1681027&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 Fri May 22 08:06:54 2015
@@ -22,12 +22,55 @@ import java.util.StringTokenizer;
 
 /**
  * Some convenience utilities to deal with path patterns.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class PatternUtil
+public abstract class PatternUtil
 {
 
+    /**
+     * Check for valid servlet pattern
+     * @param pattern The pattern
+     * @return {@code true} if its valid
+     */
+    public static boolean isValidPattern(final String pattern)
+    {
+        if ( pattern == null )
+        {
+            return false;
+        }
+        if ( pattern.indexOf("?") != -1 )
+        {
+            return false;
+        }
+        // default and root
+        if ( pattern.length() == 0 || pattern.equals("/") )
+        {
+            return true;
+        }
+        // extension
+        if ( pattern.startsWith("*.") )
+        {
+            return pattern.indexOf("/") == -1;
+        }
+        if ( !pattern.startsWith("/") )
+        {
+            return false;
+        }
+        final int pos = pattern.indexOf('*');
+        if ( pos != -1 && pos < pattern.length() - 1 )
+        {
+            return false;
+        }
+        if ( pos != -1 && pattern.charAt(pos - 1) != '/')
+        {
+            return false;
+        }
+        if ( pattern.charAt(pattern.length() - 1) == '/')
+        {
+            return false;
+        }
+        return true;
+    }
+
     // check for valid symbolic name
     public static boolean isValidSymbolicName(final String name)
     {

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/util/UriUtils.java Fri May 22 08:06:54 2015
@@ -28,10 +28,8 @@ import java.nio.charset.CodingErrorActio
 
 /**
  * Some convenience methods for handling URI(-parts).
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class UriUtils
+public abstract class UriUtils
 {
     private static final String SLASH_STR = "/";
     private static final char DOT = '.';

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java Fri May 22 08:06:54 2015
@@ -32,6 +32,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentSkipListMap;
 
 import javax.annotation.Nonnull;
@@ -117,6 +118,9 @@ public final class WhiteboardManager
 
     private final HttpServicePlugin plugin;
 
+    /** Map containing all info objects reported from the trackers. */
+    private final Map<Long, AbstractInfo<?>> allInfos = new ConcurrentHashMap<Long, AbstractInfo<?>>();
+
     /**
      * Create a new whiteboard http manager
      * @param bundleContext
@@ -229,6 +233,7 @@ public final class WhiteboardManager
             this.runtimeServiceReg.unregister();
             this.runtimeServiceReg = null;
         }
+        this.allInfos.clear();
     }
 
     public void setProperties(final Hashtable<String, Object> props)
@@ -360,6 +365,7 @@ public final class WhiteboardManager
         // no failure DTO and no logging if not matching
         if ( isMatchingService(info) )
         {
+            this.allInfos.put(info.getServiceId(), info);
             if ( info.isValid() )
             {
                 synchronized ( this.contextMap )
@@ -407,10 +413,10 @@ public final class WhiteboardManager
     /**
      * Remove a servlet context helper
      */
-    public void removeContextHelper(final ServletContextHelperInfo info)
+    public void removeContextHelper(final long serviceId)
     {
-        // no failure DTO and no logging if not matching
-        if ( isMatchingService(info) )
+        final ServletContextHelperInfo info = (ServletContextHelperInfo) this.allInfos.remove(serviceId);
+        if ( info != null )
         {
             if ( info.isValid() )
             {
@@ -500,6 +506,7 @@ public final class WhiteboardManager
         // no logging and no DTO if other target service
         if ( isMatchingService(info) )
         {
+            this.allInfos.put(info.getServiceId(), info);
             if ( info.isValid() )
             {
                 synchronized ( this.contextMap )
@@ -537,12 +544,13 @@ public final class WhiteboardManager
 
     /**
      * Remove whiteboard service from the registry
-     * @param info Whiteboard service info
+     * @param info The service id of the whiteboard service
      */
-    public void removeWhiteboardService(@Nonnull final WhiteboardServiceInfo<?> info)
+    public void removeWhiteboardService(final long serviceId)
     {
-        // no logging and no DTO if other target service
-        if ( isMatchingService(info) ) {
+        final WhiteboardServiceInfo<?> info = (WhiteboardServiceInfo<?>) this.allInfos.remove(serviceId);
+        if ( info != null )
+        {
             if ( info.isValid() )
             {
                 synchronized ( this.contextMap )

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java Fri May 22 08:06:54 2015
@@ -21,6 +21,7 @@ import javax.annotation.Nonnull;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.context.ServletContextHelper;
@@ -81,7 +82,6 @@ public final class ServletContextHelperT
 
     private void removed(@Nonnull final ServiceReference<ServletContextHelper> ref)
     {
-        final ServletContextHelperInfo info = new ServletContextHelperInfo(ref);
-        this.contextManager.removeContextHelper(info);
+        this.contextManager.removeContextHelper((Long)ref.getProperty(Constants.SERVICE_ID));
     }
 }

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java Fri May 22 08:06:54 2015
@@ -19,6 +19,7 @@ package org.apache.felix.http.base.inter
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
 import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
@@ -105,8 +106,7 @@ public abstract class WhiteboardServiceT
 
     private void removed(final ServiceReference<T> ref)
     {
-        final WhiteboardServiceInfo<T> info = this.getServiceInfo(ref);
-        this.contextManager.removeWhiteboardService(info);
+        this.contextManager.removeWhiteboardService((Long)ref.getProperty(Constants.SERVICE_ID));
     }
 
     /**

Modified: felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java (original)
+++ felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java Fri May 22 08:06:54 2015
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.when;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 
 import javax.servlet.Servlet;
@@ -52,8 +51,8 @@ import org.osgi.service.http.runtime.dto
 import org.osgi.service.http.runtime.dto.ServletContextDTO;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
-public class ErrorPageRegistryTest {
-
+public class ErrorPageRegistryTest
+{
     private void assertEmpty(final ServletContextDTO dto, final FailedDTOHolder holder)
     {
         assertNull(dto.servletDTOs);
@@ -77,10 +76,7 @@ public class ErrorPageRegistryTest {
         final FailedDTOHolder holder = new FailedDTOHolder();
         final ServletContextDTO dto = new ServletContextDTO();
 
-        final Map<ServletInfo, ErrorPageRegistry.ErrorRegistrationStatus> status = reg.getStatusMapping();
         // empty reg
-        assertEquals(0, status.size());
-        // check DTO
         reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
         assertEmpty(dto, holder);
 
@@ -91,22 +87,17 @@ public class ErrorPageRegistryTest {
         verify(h1.getServlet()).init(Matchers.any(ServletConfig.class));
 
         // one entry in reg
-        assertEquals(1, status.size());
-        assertNotNull(status.get(h1.getServletInfo()));
-        assertEquals(1, status.get(h1.getServletInfo()).exceptionMapping.size());
-        assertEquals(-1, (int)status.get(h1.getServletInfo()).exceptionMapping.get("java.io.IOException"));
-        assertEquals(1, status.get(h1.getServletInfo()).errorCodeMapping.size());
-        assertEquals(-1, (int)status.get(h1.getServletInfo()).errorCodeMapping.get(404L));
-
-        // check DTO
         clear(dto, holder);
         reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
         assertNull(dto.resourceDTOs);
         assertNull(dto.servletDTOs);
         assertNotNull(dto.errorPageDTOs);
         assertEquals(1, dto.errorPageDTOs.length);
+        assertEquals(1L, dto.errorPageDTOs[0].serviceId);
         assertEquals(1, dto.errorPageDTOs[0].errorCodes.length);
         assertEquals(404, dto.errorPageDTOs[0].errorCodes[0]);
+        assertEquals(1, dto.errorPageDTOs[0].exceptions.length);
+        assertEquals("java.io.IOException", dto.errorPageDTOs[0].exceptions[0]);
         assertTrue(holder.failedErrorPageDTOs.isEmpty());
 
         // test error handling
@@ -122,8 +113,6 @@ public class ErrorPageRegistryTest {
         verify(s).destroy();
 
         // empty again
-        assertEquals(0, status.size());
-        // check DTO
         clear(dto, holder);
         reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
         assertEmpty(dto, holder);
@@ -136,9 +125,6 @@ public class ErrorPageRegistryTest {
         final FailedDTOHolder holder = new FailedDTOHolder();
         final ServletContextDTO dto = new ServletContextDTO();
 
-        final Map<ServletInfo, ErrorPageRegistry.ErrorRegistrationStatus> status = reg.getStatusMapping();
-        // empty reg
-        assertEquals(0, status.size());
         // check DTO
         reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
         assertEmpty(dto, holder);
@@ -152,53 +138,34 @@ public class ErrorPageRegistryTest {
         verify(h1.getServlet()).init(Matchers.any(ServletConfig.class));
         verify(h2.getServlet()).init(Matchers.any(ServletConfig.class));
 
-        // two entries in reg
-        assertEquals(2, status.size());
-        assertNotNull(status.get(h1.getServletInfo()));
-        assertEquals(1, status.get(h1.getServletInfo()).exceptionMapping.size());
-        assertEquals(-1, (int)status.get(h1.getServletInfo()).exceptionMapping.get("java.io.IOException"));
-        assertEquals(1, status.get(h1.getServletInfo()).errorCodeMapping.size());
-        assertEquals(DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, (int)status.get(h1.getServletInfo()).errorCodeMapping.get(404L));
-        assertNotNull(status.get(h2.getServletInfo()));
-        assertEquals(1, status.get(h2.getServletInfo()).exceptionMapping.size());
-        assertEquals(-1, (int)status.get(h2.getServletInfo()).exceptionMapping.get("some.other.Exception"));
-        assertEquals(1, status.get(h2.getServletInfo()).errorCodeMapping.size());
-        assertEquals(-1, (int)status.get(h2.getServletInfo()).errorCodeMapping.get(404L));
-
-        // check DTO
+        // two entries in DTO
         clear(dto, holder);
         reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
+
         assertNull(dto.resourceDTOs);
         assertNull(dto.servletDTOs);
         assertNotNull(dto.errorPageDTOs);
         assertEquals(2, dto.errorPageDTOs.length);
-        assertEquals(0, dto.errorPageDTOs[0].errorCodes.length);
-        assertEquals(1, dto.errorPageDTOs[1].errorCodes.length);
-        assertEquals(404, dto.errorPageDTOs[1].errorCodes[0]);
-        assertEquals(1, dto.errorPageDTOs[0].exceptions.length);
+        assertEquals(0, dto.errorPageDTOs[1].errorCodes.length);
+        assertEquals(1, dto.errorPageDTOs[0].errorCodes.length);
+        assertEquals(404, dto.errorPageDTOs[0].errorCodes[0]);
         assertEquals(1, dto.errorPageDTOs[1].exceptions.length);
-        assertEquals("java.io.IOException", dto.errorPageDTOs[0].exceptions[0]);
-        assertEquals("some.other.Exception", dto.errorPageDTOs[1].exceptions[0]);
+        assertEquals(1, dto.errorPageDTOs[0].exceptions.length);
+        assertEquals("java.io.IOException", dto.errorPageDTOs[1].exceptions[0]);
+        assertEquals("some.other.Exception", dto.errorPageDTOs[0].exceptions[0]);
         assertEquals(1, holder.failedErrorPageDTOs.size());
-        assertEquals(1L, holder.failedErrorPageDTOs.iterator().next().serviceId);
-        assertEquals(1, holder.failedErrorPageDTOs.iterator().next().errorCodes.length);
-        assertEquals(404, holder.failedErrorPageDTOs.iterator().next().errorCodes[0]);
-        assertEquals(0, holder.failedErrorPageDTOs.iterator().next().exceptions.length);
+        assertEquals(1L, holder.failedErrorPageDTOs.get(0).serviceId);
+        assertEquals(1, holder.failedErrorPageDTOs.get(0).errorCodes.length);
+        assertEquals(404, holder.failedErrorPageDTOs.get(0).errorCodes[0]);
+        assertEquals(0, holder.failedErrorPageDTOs.get(0).exceptions.length);
+        assertEquals(DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, holder.failedErrorPageDTOs.get(0).failureReason);
 
         // remove second page
         final Servlet s2 = h2.getServlet();
         reg.removeServlet(h2.getServletInfo(), true);
         verify(s2).destroy();
 
-        // one entry in reg
-        assertEquals(1, status.size());
-        assertNotNull(status.get(h1.getServletInfo()));
-        assertEquals(1, status.get(h1.getServletInfo()).exceptionMapping.size());
-        assertEquals(-1, (int)status.get(h1.getServletInfo()).exceptionMapping.get("java.io.IOException"));
-        assertEquals(1, status.get(h1.getServletInfo()).errorCodeMapping.size());
-        assertEquals(-1, (int)status.get(h1.getServletInfo()).errorCodeMapping.get(404L));
-
-        // check DTO
+        // one entry in DTO
         clear(dto, holder);
         reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
         assertNull(dto.resourceDTOs);
@@ -207,6 +174,8 @@ public class ErrorPageRegistryTest {
         assertEquals(1, dto.errorPageDTOs.length);
         assertEquals(1, dto.errorPageDTOs[0].errorCodes.length);
         assertEquals(404, dto.errorPageDTOs[0].errorCodes[0]);
+        assertEquals(1, dto.errorPageDTOs[0].exceptions.length);
+        assertEquals("java.io.IOException", dto.errorPageDTOs[0].exceptions[0]);
         assertTrue(holder.failedErrorPageDTOs.isEmpty());
 
         // test error handling
@@ -222,8 +191,6 @@ public class ErrorPageRegistryTest {
         verify(s1).destroy();
 
         // empty again
-        assertEquals(0, status.size());
-        // check DTO
         clear(dto, holder);
         reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
         assertEmpty(dto, holder);
@@ -281,9 +248,9 @@ public class ErrorPageRegistryTest {
 
         assertEquals(1, holder.failedErrorPageDTOs.size());
         assertEquals(2, dto.errorPageDTOs.length);
-        assertEquals(98, dto.errorPageDTOs[0].errorCodes.length);
+        assertEquals(98, dto.errorPageDTOs[1].errorCodes.length);
         final Set<Long> codes4 = new HashSet<Long>();
-        for(final long c : dto.errorPageDTOs[0].errorCodes)
+        for(final long c : dto.errorPageDTOs[1].errorCodes)
         {
             assertTrue(c >= 400 && c < 500);
             codes4.add(c);
@@ -291,9 +258,9 @@ public class ErrorPageRegistryTest {
         assertEquals(98, codes4.size());
         assertFalse(codes4.contains(404L));
         assertFalse(codes4.contains(403L));
-        assertEquals(2, dto.errorPageDTOs[1].errorCodes.length);
+        assertEquals(2, dto.errorPageDTOs[0].errorCodes.length);
         final Set<Long> codes = new HashSet<Long>();
-        for(final long c : dto.errorPageDTOs[1].errorCodes)
+        for(final long c : dto.errorPageDTOs[0].errorCodes)
         {
             assertTrue(c >= 403 && c < 405);
             codes.add(c);

Modified: felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java (original)
+++ felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/PatternUtilTest.java Fri May 22 08:06:54 2015
@@ -25,8 +25,6 @@ import org.junit.Test;
 
 /**
  * Test cases for {@link PatternUtil}.
- *
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class PatternUtilTest
 {
@@ -40,4 +38,21 @@ public class PatternUtilTest
         assertTrue(PatternUtil.isValidSymbolicName("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
         assertTrue(PatternUtil.isValidSymbolicName("0123456789-_"));
     }
+
+    @Test public void testServletPattern()
+    {
+        assertFalse(PatternUtil.isValidPattern(null));
+        assertTrue(PatternUtil.isValidPattern(""));
+        assertTrue(PatternUtil.isValidPattern("*.html"));
+        assertTrue(PatternUtil.isValidPattern("/"));
+        assertTrue(PatternUtil.isValidPattern("/test"));
+        assertTrue(PatternUtil.isValidPattern("/test/*"));
+        assertTrue(PatternUtil.isValidPattern("/foo/bar"));
+        assertTrue(PatternUtil.isValidPattern("/foo/bar/*"));
+        assertFalse(PatternUtil.isValidPattern("/*.html"));
+        assertFalse(PatternUtil.isValidPattern("/*/foo"));
+        assertFalse(PatternUtil.isValidPattern("foo"));
+        assertFalse(PatternUtil.isValidPattern("foo/bla"));
+        assertFalse(PatternUtil.isValidPattern("/test/"));
+    }
 }

Modified: felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java?rev=1681027&r1=1681026&r2=1681027&view=diff
==============================================================================
--- felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java (original)
+++ felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/util/UriUtilsTest.java Fri May 22 08:06:54 2015
@@ -18,15 +18,17 @@
  */
 package org.apache.felix.http.base.internal.util;
 
-import static org.apache.felix.http.base.internal.util.UriUtils.*;
-import static org.junit.Assert.*;
+import static org.apache.felix.http.base.internal.util.UriUtils.compactPath;
+import static org.apache.felix.http.base.internal.util.UriUtils.concat;
+import static org.apache.felix.http.base.internal.util.UriUtils.decodePath;
+import static org.apache.felix.http.base.internal.util.UriUtils.relativePath;
+import static org.apache.felix.http.base.internal.util.UriUtils.removeDotSegments;
+import static org.junit.Assert.assertEquals;
 
 import org.junit.Test;
 
 /**
  * Test cases for {@link UriUtils}.
- * 
- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class UriUtilsTest
 {
@@ -51,7 +53,7 @@ public class UriUtilsTest
         assertEquals(null, relativePath("/foo", null));
         assertEquals(null, relativePath("/foo", ""));
         assertEquals(null, relativePath("/foo", "/foo"));
-        assertEquals(null, relativePath("/foo", "/foo/")); // XXX or "/"?   
+        assertEquals(null, relativePath("/foo", "/foo/")); // XXX or "/"?
         assertEquals("/foo", relativePath("/", "/foo"));
         assertEquals("/foo/", relativePath("/", "/foo/"));
         assertEquals("/foo/", relativePath(null, "/foo/"));
@@ -159,7 +161,7 @@ public class UriUtilsTest
         assertEquals("foo..", removeDotSegments("foo.."));
         assertEquals("foo.", removeDotSegments("foo."));
         assertEquals("/.foo", removeDotSegments("/.foo"));
-        assertEquals("/..foo", removeDotSegments("/..foo"));        
+        assertEquals("/..foo", removeDotSegments("/..foo"));
 
         // FELIX-4440
         assertEquals("foo.bar", removeDotSegments("foo.bar"));