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/17 12:21:26 UTC

svn commit: r1679833 - in /felix/trunk/http/base/src: main/java/org/apache/felix/http/base/internal/handler/holder/ main/java/org/apache/felix/http/base/internal/registry/ test/java/org/apache/felix/http/base/internal/registry/

Author: cziegeler
Date: Sun May 17 10:21:26 2015
New Revision: 1679833

URL: http://svn.apache.org/r1679833
Log:
FELIX-4888 : ServletHandler's are not sorted by longest matching path. Implement new servlet registry, start filter holder implementation

Added:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java   (with props)
    felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/
    felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java   (with props)
Modified:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/ServletHolder.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java?rev=1679833&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java Sun May 17 10:21:26 2015
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.handler.holder;
+
+import javax.servlet.Filter;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.felix.http.base.internal.handler.FilterConfigImpl;
+import org.apache.felix.http.base.internal.logger.SystemLogger;
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
+import org.osgi.service.http.runtime.dto.DTOConstants;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class FilterHolder implements Comparable<FilterHolder>
+{
+    private final FilterInfo filterInfo;
+
+    private final ServletContext context;
+
+    private volatile Filter filter;
+
+    protected volatile int useCount;
+
+    public FilterHolder(final ServletContext context,
+            final FilterInfo filterInfo)
+    {
+        this.context = context;
+        this.filterInfo = filterInfo;
+    }
+
+    @Override
+    public int compareTo(final FilterHolder other)
+    {
+        return this.filterInfo.compareTo(other.filterInfo);
+    }
+
+    protected ServletContext getContext()
+    {
+        return this.context;
+    }
+
+    protected Filter getFilter()
+    {
+        return filter;
+    }
+
+    protected void setFilter(final Filter f)
+    {
+        this.filter = f;
+    }
+
+    public FilterInfo getFilterInfo()
+    {
+        return this.filterInfo;
+    }
+
+    protected String getName()
+    {
+        String name = this.filterInfo.getName();
+        if (name == null)
+        {
+            name = filter.getClass().getName();
+        }
+        return name;
+    }
+
+    /**
+     * Initialize the object
+     * @return {code -1} on success, a failure reason according to {@link DTOConstants} otherwise.
+     */
+    public int init()
+    {
+        if ( this.useCount > 0 )
+        {
+            return -1;
+        }
+
+        if (this.filter == null)
+        {
+            return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+        }
+
+        try
+        {
+            filter.init(new FilterConfigImpl(getName(), getContext(), getFilterInfo().getInitParameters()));
+        }
+        catch (final ServletException e)
+        {
+            SystemLogger.error(this.getFilterInfo().getServiceReference(),
+                    "Error during calling init() on filter " + this.filter,
+                    e);
+            return DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT;
+        }
+        this.useCount++;
+        return -1;
+    }
+
+
+    public boolean destroy()
+    {
+        if (this.filter == null)
+        {
+            return false;
+        }
+
+        this.useCount--;
+        if ( this.useCount == 0 )
+        {
+            try
+            {
+                filter.destroy();
+            }
+            catch ( final Exception ignore )
+            {
+                // we ignore this
+                SystemLogger.error(this.getFilterInfo().getServiceReference(),
+                        "Error during calling destroy() on filter " + this.filter,
+                        ignore);
+            }
+
+            filter = null;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean dispose()
+    {
+        // fully destroy the filter
+        this.useCount = 1;
+        return this.destroy();
+    }
+}

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

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

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/FilterHolder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java?rev=1679833&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java Sun May 17 10:21:26 2015
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.handler.holder;
+
+import javax.servlet.Filter;
+import javax.servlet.ServletContext;
+
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
+
+/**
+ * Servlet holder for filters registered through the ext http service.
+ */
+public final class HttpServiceFilterHolder extends FilterHolder
+{
+    public HttpServiceFilterHolder(final ServletContext context,
+            final FilterInfo filterInfo,
+            final Filter filter)
+    {
+        super(context, filterInfo);
+        this.setFilter(filter);
+    }
+}

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

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

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/HttpServiceFilterHolder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/ServletHolder.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/ServletHolder.java?rev=1679833&r1=1679832&r2=1679833&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/ServletHolder.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/ServletHolder.java Sun May 17 10:21:26 2015
@@ -150,4 +150,11 @@ public abstract class ServletHolder impl
         }
         return false;
     }
+
+    public boolean dispose()
+    {
+        // fully destroy the servlet
+        this.useCount = 1;
+        return this.destroy();
+    }
 }

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java?rev=1679833&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java Sun May 17 10:21:26 2015
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.handler.holder;
+
+import javax.servlet.Filter;
+import javax.servlet.ServletContext;
+
+import org.apache.felix.http.base.internal.runtime.FilterInfo;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceObjects;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Filter holder for filters registered through the http whiteboard.
+ */
+public final class WhiteboardFilterHolder extends FilterHolder
+{
+    private final BundleContext bundleContext;
+
+    public WhiteboardFilterHolder(final ServletContext context,
+            final FilterInfo filterInfo,
+            final BundleContext bundleContext)
+    {
+        super(context, filterInfo);
+        this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public int init()
+    {
+        if ( this.useCount > 0 )
+        {
+            return -1;
+        }
+
+        final ServiceReference<Filter> serviceReference = getFilterInfo().getServiceReference();
+        final ServiceObjects<Filter> so = this.bundleContext.getServiceObjects(serviceReference);
+
+        this.setFilter((so == null ? null : so.getService()));
+
+        final int reason = super.init();
+        if ( reason != -1 )
+        {
+            so.ungetService(this.getFilter());
+            this.setFilter(null);
+        }
+        return -reason;
+    }
+
+    @Override
+    public boolean destroy()
+    {
+        final Filter s = this.getFilter();
+        if ( s != null )
+        {
+            if ( super.destroy() )
+            {
+
+                final ServiceObjects<Filter> so = this.bundleContext.getServiceObjects(getFilterInfo().getServiceReference());
+                if (so != null)
+                {
+                    so.ungetService(s);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+}

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

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

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/handler/holder/WhiteboardFilterHolder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java?rev=1679833&r1=1679832&r2=1679833&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java Sun May 17 10:21:26 2015
@@ -16,19 +16,11 @@
  */
 package org.apache.felix.http.base.internal.registry;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.regex.Pattern;
-
 import javax.annotation.Nonnull;
 
 import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
-import org.apache.felix.http.base.internal.util.PatternUtil;
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
 
 /**
  * This registry keeps track of all processing components per context:
@@ -50,9 +42,7 @@ public final class PerContextHandlerRegi
     /** The context prefix. */
     private final String prefix;
 
-    private Map<String, ServletHandler> activateServletMappings = new ConcurrentHashMap<String, ServletHandler>();
-
-    private Map<String, List<ServletHolder>> inactivateServletMappings = new HashMap<String, List<ServletHolder>>();
+    private final ServletRegistry servletRegistry = new ServletRegistry();
 
     /**
      * Default http service registry
@@ -126,18 +116,7 @@ public final class PerContextHandlerRegi
 
     public PathResolution resolve(final String relativeRequestURI)
     {
-        int len = -1;
-        PathResolution candidate = null;
-        for(final Map.Entry<String, ServletHandler> entry : this.activateServletMappings.entrySet())
-        {
-            final PathResolution pr = entry.getValue().resolve(relativeRequestURI);
-            if ( pr != null && entry.getKey().length() > len )
-            {
-                candidate = pr;
-                len = entry.getKey().length();
-            }
-        }
-        return candidate;
+        return this.servletRegistry.resolve(relativeRequestURI);
     }
 
     /**
@@ -147,70 +126,15 @@ public final class PerContextHandlerRegi
      */
     public void addServlet(@Nonnull final ServletHolder holder)
     {
-        // we have to check for every pattern in the info
-        // Can be null in case of error-handling servlets...
-        final String[] patternStrings = holder.getServletInfo().getPatterns();
-        if ( patternStrings != null )
-        {
-            final int length = patternStrings.length;
-            for (int i = 0; i < length; i++)
-            {
-                final String pattern = patternStrings[i];
-
-                final ServletHandler regHandler = this.activateServletMappings.get(pattern);
-                if ( regHandler != null )
-                {
-                    if ( regHandler.getServletHolder().getServletInfo().getServiceReference().compareTo(holder.getServletInfo().getServiceReference()) < 0 )
-                    {
-                        // replace if no error with new servlet
-                        if ( holder.init() == -1 )
-                        {
-                            final Pattern p = Pattern.compile(PatternUtil.convertToRegEx(pattern));
-                            final ServletHandler handler = new ServletHandler(holder, p);
-                            this.activateServletMappings.put(pattern, handler);
-
-                            regHandler.getServletHolder().destroy();
-
-                            this.addToInactiveList(pattern, regHandler.getServletHolder());
-                        }
-                        else
-                        {
-                            // TODO - add to failure
-                        }
-                    }
-                    else
-                    {
-                        // add to inactive
-                        this.addToInactiveList(pattern, holder);
-                    }
-                }
-                else
-                {
-                    // add to active
-                    if ( holder.init() == -1 )
-                    {
-                        final Pattern p = Pattern.compile(PatternUtil.convertToRegEx(pattern));
-                        final ServletHandler handler = new ServletHandler(holder, p);
-                        this.activateServletMappings.put(pattern, handler);
-                    }
-                    else
-                    {
-                        // TODO - add to failure
-                    }
-                }
-            }
-        }
+        this.servletRegistry.addServlet(holder);
     }
 
-    private void addToInactiveList(final String pattern, final ServletHolder holder)
+    /**
+     * Remove a servlet
+     * @param info The servlet info
+     */
+    public void removeServlet(@Nonnull final ServletInfo info)
     {
-        List<ServletHolder> inactiveList = this.inactivateServletMappings.get(pattern);
-        if ( inactiveList == null )
-        {
-            inactiveList = new ArrayList<ServletHolder>(inactiveList);
-            this.inactivateServletMappings.put(pattern, inactiveList);
-        }
-        inactiveList.add(holder);
-        Collections.sort(inactiveList);
+        this.servletRegistry.removeServlet(info);
     }
 }

Added: 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=1679833&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java Sun May 17 10:21:26 2015
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nonnull;
+
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.util.PatternUtil;
+import org.osgi.service.http.runtime.dto.DTOConstants;
+
+/**
+ * The servlet registry keeps the mappings for all servlets (by using their pattern)
+ * for a single servlet context.
+ */
+public final class ServletRegistry
+{
+    private final Map<String, ServletHandler> activateServletMapping = new ConcurrentHashMap<String, ServletHandler>();
+
+    private final Map<String, List<ServletHolder>> inactivateServletMapping = new HashMap<String, List<ServletHolder>>();
+
+    private final Map<ServletInfo, ServletRegistrationStatus> statusMapping = new ConcurrentHashMap<ServletInfo, ServletRegistry.ServletRegistrationStatus>();
+
+    public static final class ServletRegistrationStatus
+    {
+        public final Map<String, Integer> pathToStatus = new ConcurrentHashMap<String, Integer>();
+    }
+
+    public PathResolution resolve(final String relativeRequestURI)
+    {
+        int len = -1;
+        PathResolution candidate = null;
+        for(final Map.Entry<String, ServletHandler> entry : this.activateServletMapping.entrySet())
+        {
+            final PathResolution pr = entry.getValue().resolve(relativeRequestURI);
+            if ( pr != null && entry.getKey().length() > len )
+            {
+                candidate = pr;
+                len = entry.getKey().length();
+            }
+        }
+        return candidate;
+    }
+
+    /**
+     * Add a servlet
+     * @param holder The servlet holder
+     */
+    public void addServlet(@Nonnull final ServletHolder holder)
+    {
+        final ServletRegistrationStatus status = new ServletRegistrationStatus();
+
+        // we have to check for every pattern in the info
+        // Can be null in case of error-handling servlets...
+        if ( holder.getServletInfo().getPatterns() != null )
+        {
+            for(final String pattern : holder.getServletInfo().getPatterns())
+            {
+                final ServletHandler regHandler = this.activateServletMapping.get(pattern);
+                if ( regHandler != null )
+                {
+                    if ( regHandler.getServletHolder().getServletInfo().getServiceReference().compareTo(holder.getServletInfo().getServiceReference()) < 0 )
+                    {
+                        // replace if no error with new servlet
+                        if ( this.tryToActivate(pattern, holder, status) )
+                        {
+                            regHandler.getServletHolder().destroy();
+
+                            this.addToInactiveList(pattern, regHandler.getServletHolder(), this.statusMapping.get(regHandler.getServletHolder().getServletInfo()));
+                        }
+                    }
+                    else
+                    {
+                        // add to inactive
+                        this.addToInactiveList(pattern, holder, status);
+                    }
+                }
+                else
+                {
+                    // add to active
+                    this.tryToActivate(pattern, holder, status);
+                }
+            }
+            this.statusMapping.put(holder.getServletInfo(), status);
+        }
+    }
+
+    /**
+     * Remove a servlet
+     * @param info The servlet info
+     */
+    public void removeServlet(@Nonnull final ServletInfo info)
+    {
+        if ( info.getPatterns() != null )
+        {
+            this.statusMapping.remove(info);
+            ServletHolder cleanupHolder = null;
+
+            for(final String pattern : info.getPatterns())
+            {
+
+                final ServletHandler regHandler = this.activateServletMapping.get(pattern);
+                if ( regHandler != null && regHandler.getServletHolder().getServletInfo().equals(info) )
+                {
+                    cleanupHolder = regHandler.getServletHolder();
+                    final List<ServletHolder> inactiveList = this.inactivateServletMapping.get(pattern);
+                    if ( inactiveList == null )
+                    {
+                        this.activateServletMapping.remove(pattern);
+                    }
+                    else
+                    {
+                        boolean done = false;
+                        while ( !done )
+                        {
+                            final ServletHolder h = inactiveList.remove(0);
+                            done = this.tryToActivate(pattern, h, this.statusMapping.get(h.getServletInfo()));
+                            if ( !done )
+                            {
+                                done = inactiveList.isEmpty();
+                            }
+                        }
+                        if ( inactiveList.isEmpty() )
+                        {
+                            this.inactivateServletMapping.remove(pattern);
+                        }
+                    }
+                }
+                else
+                {
+                    final List<ServletHolder> inactiveList = this.inactivateServletMapping.get(pattern);
+                    if ( inactiveList != null )
+                    {
+                        final Iterator<ServletHolder> i = inactiveList.iterator();
+                        while ( i.hasNext() )
+                        {
+                            final ServletHolder h = i.next();
+                            if ( h.getServletInfo().equals(info) )
+                            {
+                                i.remove();
+                                cleanupHolder = h;
+                                break;
+                            }
+                        }
+                        if ( inactiveList.isEmpty() )
+                        {
+                            this.inactivateServletMapping.remove(pattern);
+                        }
+                    }
+                }
+            }
+
+            if ( cleanupHolder != null )
+            {
+                cleanupHolder.dispose();
+            }
+        }
+    }
+
+    private void addToInactiveList(final String pattern, final ServletHolder holder, final ServletRegistrationStatus status)
+    {
+        List<ServletHolder> inactiveList = this.inactivateServletMapping.get(pattern);
+        if ( inactiveList == null )
+        {
+            inactiveList = new ArrayList<ServletHolder>(inactiveList);
+            this.inactivateServletMapping.put(pattern, inactiveList);
+        }
+        inactiveList.add(holder);
+        Collections.sort(inactiveList);
+        status.pathToStatus.put(pattern, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+    }
+
+    private boolean tryToActivate(final String pattern, final ServletHolder holder, final ServletRegistrationStatus status)
+    {
+        // add to active
+        final int result = holder.init();
+        if ( result == -1 )
+        {
+            final Pattern p = Pattern.compile(PatternUtil.convertToRegEx(pattern));
+            final ServletHandler handler = new ServletHandler(holder, p);
+            this.activateServletMapping.put(pattern, handler);
+
+            // add ok
+            status.pathToStatus.put(pattern, result);
+            return true;
+        }
+        else
+        {
+            // add to failure
+            status.pathToStatus.put(pattern, result);
+            return false;
+        }
+    }
+
+    public Map<ServletInfo, ServletRegistrationStatus> getServletStatusMapping()
+    {
+        return this.statusMapping;
+    }
+}

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

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

Propchange: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ServletRegistry.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java?rev=1679833&view=auto
==============================================================================
--- felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java (added)
+++ felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java Sun May 17 10:21:26 2015
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.registry;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Map;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+
+import org.apache.felix.http.base.internal.handler.holder.HttpServiceServletHolder;
+import org.apache.felix.http.base.internal.handler.holder.ServletHolder;
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.osgi.framework.Bundle;
+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;
+
+public class ServletRegistryTest {
+
+    private final ServletRegistry reg = new ServletRegistry();
+
+    @Test public void testSingleServlet() throws InvalidSyntaxException
+    {
+        final Map<ServletInfo, ServletRegistry.ServletRegistrationStatus> status = reg.getServletStatusMapping();
+        // empty reg
+        assertEquals(0, status.size());
+
+        // register servlet
+        final ServletHolder h1 = createServletHolder(1L, 0, "/foo");
+        reg.addServlet(h1);
+
+        // one entry in reg
+        assertEquals(1, status.size());
+        assertNotNull(status.get(h1.getServletInfo()));
+        assertNotNull(status.get(h1.getServletInfo()).pathToStatus.get("/foo"));
+        final int code = status.get(h1.getServletInfo()).pathToStatus.get("/foo");
+        assertEquals(-1, code);
+
+        // remove servlet
+        reg.removeServlet(h1.getServletInfo());
+
+        // empty again
+        assertEquals(0, status.size());
+    }
+
+    private static ServletInfo createServletInfo(final long id, final int ranking, final String... paths) throws InvalidSyntaxException
+    {
+        final BundleContext bCtx = mock(BundleContext.class);
+        when(bCtx.createFilter(Matchers.anyString())).thenReturn(null);
+        final Bundle bundle = mock(Bundle.class);
+        when(bundle.getBundleContext()).thenReturn(bCtx);
+
+        final ServiceReference<Servlet> ref = mock(ServiceReference.class);
+        when(ref.getBundle()).thenReturn(bundle);
+        when(ref.getProperty(Constants.SERVICE_ID)).thenReturn(id);
+        when(ref.getProperty(Constants.SERVICE_RANKING)).thenReturn(ranking);
+        when(ref.getProperty(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN)).thenReturn(paths);
+        when(ref.getPropertyKeys()).thenReturn(new String[0]);
+        final ServletInfo si = new ServletInfo(ref);
+
+        return si;
+    }
+
+    private static ServletHolder createServletHolder(final long id, final int ranking, final String... paths) throws InvalidSyntaxException
+    {
+        final ServletInfo si = createServletInfo(id, ranking, paths);
+        final ServletContext ctx = mock(ServletContext.class);
+        final Servlet servlet = mock(Servlet.class);
+
+        return new HttpServiceServletHolder(ctx, si, servlet);
+    }
+}

Propchange: felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ServletRegistryTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain