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/23 14:15:53 UTC

svn commit: r1681335 - in /felix/trunk/http/base/src: main/java/org/apache/felix/http/base/internal/registry/ main/java/org/apache/felix/http/base/internal/runtime/ main/java/org/apache/felix/http/base/internal/runtime/dto/ main/java/org/apache/felix/h...

Author: cziegeler
Date: Sat May 23 12:15:52 2015
New Revision: 1681335

URL: http://svn.apache.org/r1681335
Log:
FELIX-4060 : Implement HTTP Whiteboard Service (RFC-189). Clean up error handling and add logging

Added:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java   (with props)
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java   (with props)
    felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/
    felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java   (with props)
Removed:
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java
Modified:
    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/dto/FailedDTOHolder.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
    felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.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

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java?rev=1681335&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java Sat May 23 12:15:52 2015
@@ -0,0 +1,479 @@
+/*
+ * 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.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentSkipListMap;
+
+import javax.annotation.Nonnull;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionIdListener;
+import javax.servlet.http.HttpSessionListener;
+
+import org.apache.felix.http.base.internal.runtime.HttpSessionAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionIdListenerInfo;
+import org.apache.felix.http.base.internal.runtime.HttpSessionListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletContextListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestAttributeListenerInfo;
+import org.apache.felix.http.base.internal.runtime.ServletRequestListenerInfo;
+import org.apache.felix.http.base.internal.runtime.dto.ListenerDTOBuilder;
+import org.apache.felix.http.base.internal.util.CollectionUtils;
+import org.apache.felix.http.base.internal.whiteboard.ContextHandler;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.runtime.dto.DTOConstants;
+import org.osgi.service.http.runtime.dto.ListenerDTO;
+import org.osgi.service.http.runtime.dto.ServletContextDTO;
+
+/**
+ * Per context event listener registry.
+ */
+public final class EventListenerRegistry implements
+        HttpSessionListener,
+        HttpSessionAttributeListener,
+        HttpSessionIdListener,
+        ServletContextAttributeListener,
+        ServletRequestListener,
+        ServletRequestAttributeListener
+{
+    /** Servlet context listeners. */
+    private final Map<ServiceReference<ServletContextListener>, ServletContextListener> contextListeners = new ConcurrentSkipListMap<ServiceReference<ServletContextListener>, ServletContextListener>();
+
+    /** Servlet context attribute listeners. */
+    private final Map<ServiceReference<ServletContextAttributeListener>, ServletContextAttributeListener> contextAttributeListeners = new ConcurrentSkipListMap<ServiceReference<ServletContextAttributeListener>, ServletContextAttributeListener>();
+
+    /** Session attribute listeners. */
+    private final Map<ServiceReference<HttpSessionAttributeListener>, HttpSessionAttributeListener> sessionAttributeListeners = new ConcurrentSkipListMap<ServiceReference<HttpSessionAttributeListener>, HttpSessionAttributeListener>();
+
+    /** Session listeners. */
+    private final Map<ServiceReference<HttpSessionListener>, HttpSessionListener> sessionListeners = new ConcurrentSkipListMap<ServiceReference<HttpSessionListener>, HttpSessionListener>();
+
+    /** Session id listeners. */
+    private final Map<ServiceReference<HttpSessionIdListener>, HttpSessionIdListener> sessionIdListeners = new ConcurrentSkipListMap<ServiceReference<HttpSessionIdListener>, HttpSessionIdListener>();
+
+    /** Request listeners. */
+    private final Map<ServiceReference<ServletRequestListener>, ServletRequestListener> requestListeners = new ConcurrentSkipListMap<ServiceReference<ServletRequestListener>, ServletRequestListener>();
+
+    /** Request attribute listeners. */
+    private final Map<ServiceReference<ServletRequestAttributeListener>, ServletRequestAttributeListener> requestAttributeListeners = new ConcurrentSkipListMap<ServiceReference<ServletRequestAttributeListener>, ServletRequestAttributeListener>();
+
+    private final Bundle bundle;
+
+    public EventListenerRegistry(final Bundle bundle)
+    {
+        this.bundle = bundle;
+    }
+
+    public int initialized(@Nonnull final ServletContextListenerInfo listenerInfo, @Nonnull final ContextHandler contextHandler)
+    {
+        final ServletContextListener listener = listenerInfo.getService(bundle);
+        if (listener != null)
+        {
+            final ServletContext context = contextHandler
+                    .getServletContext(listenerInfo.getServiceReference()
+                            .getBundle());
+            if ( context != null )
+            {
+                this.contextListeners.put(listenerInfo.getServiceReference(), listener);
+
+                listener.contextInitialized(new ServletContextEvent(context));
+                return -1;
+            }
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
+        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+    }
+
+    public void destroyed(@Nonnull final ServletContextListenerInfo listenerInfo, @Nonnull final ContextHandler contextHandler)
+    {
+        final ServiceReference<ServletContextListener> listenerRef = listenerInfo
+                .getServiceReference();
+        final ServletContextListener listener = this.contextListeners
+                .remove(listenerRef);
+        if (listener != null)
+        {
+            final ServletContext context = contextHandler
+                    .getServletContext(listenerRef.getBundle());
+            listener.contextDestroyed(new ServletContextEvent(context));
+            // call unget twice, once for the call in initialized and once for
+            // the call in this method(!)
+            contextHandler.ungetServletContext(listenerRef.getBundle());
+            contextHandler.ungetServletContext(listenerRef.getBundle());
+            listenerInfo.ungetService(bundle, listener);
+        }
+    }
+
+    /**
+     * Add servlet context attribute listener
+     *
+     * @param info
+     */
+    public int addListener(@Nonnull final ServletContextAttributeListenerInfo info)
+    {
+        final ServletContextAttributeListener service = info.getService(bundle);
+        if (service != null)
+        {
+            this.contextAttributeListeners.put(info.getServiceReference(),
+                    service);
+            return -1;
+        }
+        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+    }
+
+    /**
+     * Remove servlet context attribute listener
+     *
+     * @param info
+     */
+    public void removeListener(@Nonnull final ServletContextAttributeListenerInfo info)
+    {
+        final ServletContextAttributeListener service = this.contextAttributeListeners
+                .remove(info.getServiceReference());
+        if (service != null)
+        {
+            info.ungetService(bundle, service);
+        }
+    }
+
+    /**
+     * Add session attribute listener
+     *
+     * @param info
+     */
+    public int addListener(@Nonnull final HttpSessionAttributeListenerInfo info)
+    {
+        final HttpSessionAttributeListener service = info.getService(bundle);
+        if (service != null)
+        {
+            this.sessionAttributeListeners.put(info.getServiceReference(),
+                    service);
+            return -1;
+        }
+        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+    }
+
+    /**
+     * Remove session attribute listener
+     *
+     * @param info
+     */
+    public void removeListener(@Nonnull final HttpSessionAttributeListenerInfo info)
+    {
+        final HttpSessionAttributeListener service = this.sessionAttributeListeners
+                .remove(info.getServiceReference());
+        if (service != null)
+        {
+            info.ungetService(bundle, service);
+        }
+    }
+
+    /**
+     * Add session listener
+     *
+     * @param info
+     */
+    public int addListener(@Nonnull final HttpSessionListenerInfo info)
+    {
+        final HttpSessionListener service = info.getService(bundle);
+        if (service != null)
+        {
+            this.sessionListeners.put(info.getServiceReference(), service);
+            return -1;
+        }
+        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+    }
+
+    /**
+     * Remove session listener
+     *
+     * @param info
+     */
+    public void removeListener(@Nonnull final HttpSessionListenerInfo info)
+    {
+        final HttpSessionListener service = this.sessionListeners.remove(info
+                .getServiceReference());
+        if (service != null)
+        {
+            info.ungetService(bundle, service);
+        }
+    }
+
+    /**
+     * Add session id listener
+     *
+     * @param info
+     */
+    public  int addListener(@Nonnull final HttpSessionIdListenerInfo info)
+    {
+        final HttpSessionIdListener service = info.getService(bundle);
+        if (service != null)
+        {
+            this.sessionIdListeners.put(info.getServiceReference(),
+                    service);
+            return -1;
+        }
+        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+    }
+
+    /**
+     * Remove session id listener
+     *
+     * @param info
+     */
+    public void removeListener(@Nonnull final HttpSessionIdListenerInfo info)
+    {
+        final HttpSessionIdListener service = this.sessionIdListeners.remove(info.getServiceReference());
+        if (service != null)
+        {
+            info.ungetService(bundle, service);
+        }
+    }
+
+    /**
+     * Add request listener
+     *
+     * @param info
+     */
+    public int addListener(@Nonnull final ServletRequestListenerInfo info)
+    {
+        final ServletRequestListener service = info.getService(bundle);
+        if (service != null)
+        {
+            this.requestListeners.put(info.getServiceReference(), service);
+            return -1;
+        }
+        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+    }
+
+    /**
+     * Remove request listener
+     *
+     * @param info
+     */
+    public void removeListener(@Nonnull final ServletRequestListenerInfo info)
+    {
+        final ServletRequestListener service = this.requestListeners
+                .remove(info.getServiceReference());
+        if (service != null)
+        {
+            info.ungetService(bundle, service);
+        }
+    }
+
+    /**
+     * Add request attribute listener
+     *
+     * @param info
+     */
+    public int addListener(@Nonnull final ServletRequestAttributeListenerInfo info)
+    {
+        final ServletRequestAttributeListener service = info.getService(bundle);
+        if (service != null)
+        {
+            this.requestAttributeListeners.put(info.getServiceReference(),
+                    service);
+            return -1;
+        }
+        return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
+    }
+
+    /**
+     * Remove request attribute listener
+     *
+     * @param info
+     */
+    public void removeListener(@Nonnull final ServletRequestAttributeListenerInfo info)
+    {
+        final ServletRequestAttributeListener service = this.requestAttributeListeners
+                .remove(info.getServiceReference());
+        if (service != null)
+        {
+            info.ungetService(bundle, service);
+        }
+    }
+
+    @Override
+    public void attributeReplaced(final HttpSessionBindingEvent event)
+    {
+        for (final HttpSessionAttributeListener l : sessionAttributeListeners
+                .values())
+        {
+            l.attributeReplaced(event);
+        }
+    }
+
+    @Override
+    public void attributeRemoved(final HttpSessionBindingEvent event)
+    {
+        for (final HttpSessionAttributeListener l : sessionAttributeListeners
+                .values())
+        {
+            l.attributeReplaced(event);
+        }
+    }
+
+    @Override
+    public void attributeAdded(final HttpSessionBindingEvent event)
+    {
+        for (final HttpSessionAttributeListener l : sessionAttributeListeners
+                .values())
+        {
+            l.attributeReplaced(event);
+        }
+    }
+
+    @Override
+    public void attributeReplaced(final ServletContextAttributeEvent event)
+    {
+        for (final ServletContextAttributeListener l : contextAttributeListeners
+                .values())
+        {
+            l.attributeReplaced(event);
+        }
+    }
+
+    @Override
+    public void attributeRemoved(final ServletContextAttributeEvent event)
+    {
+        for (final ServletContextAttributeListener l : contextAttributeListeners
+                .values())
+        {
+            l.attributeReplaced(event);
+        }
+    }
+
+    @Override
+    public void attributeAdded(final ServletContextAttributeEvent event)
+    {
+        for (final ServletContextAttributeListener l : contextAttributeListeners
+                .values())
+        {
+            l.attributeReplaced(event);
+        }
+    }
+
+    @Override
+    public void sessionCreated(final HttpSessionEvent se)
+    {
+        for (final HttpSessionListener l : sessionListeners.values())
+        {
+            l.sessionCreated(se);
+        }
+    }
+
+    @Override
+    public void sessionDestroyed(final HttpSessionEvent se)
+    {
+        for (final HttpSessionListener l : sessionListeners.values())
+        {
+            l.sessionDestroyed(se);
+        }
+    }
+
+    @Override
+    public void requestDestroyed(final ServletRequestEvent sre)
+    {
+        for (final ServletRequestListener l : requestListeners.values())
+        {
+            l.requestDestroyed(sre);
+        }
+    }
+
+    @Override
+    public void requestInitialized(final ServletRequestEvent sre)
+    {
+        for (final ServletRequestListener l : requestListeners.values())
+        {
+            l.requestInitialized(sre);
+        }
+    }
+
+    @Override
+    public void attributeAdded(final ServletRequestAttributeEvent srae)
+    {
+        for (final ServletRequestAttributeListener l : requestAttributeListeners
+                .values())
+        {
+            l.attributeAdded(srae);
+        }
+    }
+
+    @Override
+    public void attributeRemoved(final ServletRequestAttributeEvent srae)
+    {
+        for (final ServletRequestAttributeListener l : requestAttributeListeners
+                .values())
+        {
+            l.attributeRemoved(srae);
+        }
+    }
+
+    @Override
+    public void attributeReplaced(final ServletRequestAttributeEvent srae)
+    {
+        for (final ServletRequestAttributeListener l : requestAttributeListeners
+                .values())
+        {
+            l.attributeReplaced(srae);
+        }
+    }
+
+    /**
+     * @see javax.servlet.http.HttpSessionIdListener#sessionIdChanged(javax.servlet.http.HttpSessionEvent, java.lang.String)
+     */
+    @Override
+    public void sessionIdChanged(@Nonnull final HttpSessionEvent event, @Nonnull final String oldSessionId) {
+        for (final HttpSessionIdListener l : sessionIdListeners.values())
+        {
+            l.sessionIdChanged(event, oldSessionId);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void getRuntime(final ServletContextDTO dto)
+    {
+        final Collection<ServiceReference<?>> col = CollectionUtils.<ServiceReference<?>>sortedUnion(
+                Collections.<ServiceReference<?>>reverseOrder(),
+                contextListeners.keySet(),
+                contextAttributeListeners.keySet(),
+                sessionAttributeListeners.keySet(),
+                sessionIdListeners.keySet(),
+                sessionListeners.keySet(),
+                requestAttributeListeners.keySet(),
+                requestListeners.keySet());
+        dto.listenerDTOs = new ListenerDTO[col.size()];
+        int index = 0;
+        for(final ServiceReference<?> ref : col)
+        {
+            dto.listenerDTOs[index++] = ListenerDTOBuilder.build(ref, dto.serviceId);
+        }
+    }
+}

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

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

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

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=1681335&r1=1681334&r2=1681335&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 Sat May 23 12:15:52 2015
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.http.base.internal.runtime;
 
+import org.apache.felix.http.base.internal.util.PatternUtil;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 
@@ -46,8 +47,19 @@ public final class ResourceInfo extends
     @Override
     public boolean isValid()
     {
-        // TODO - do we need to check the values?
-        return super.isValid() && !isEmpty(this.patterns) && !isEmpty(this.prefix);
+        // TODO - do we need to check the prefix?
+        boolean valid = super.isValid() && !isEmpty(this.patterns) && !isEmpty(this.prefix);
+        if ( valid ) {
+            for(final String p : patterns)
+            {
+                if ( !PatternUtil.isValidPattern(p) )
+                {
+                    valid = false;
+                    break;
+                }
+            }
+        }
+        return valid;
     }
 
     public String getPrefix()

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=1681335&r1=1681334&r2=1681335&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 Sat May 23 12:15:52 2015
@@ -20,7 +20,6 @@ package org.apache.felix.http.base.inter
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.registry.ErrorPageRegistry;
@@ -52,15 +51,7 @@ public final class FailedDTOHolder
 
     public final List<FailedServletContextDTO> failedServletContextDTO = new ArrayList<FailedServletContextDTO>();
 
-    public void add(Map<AbstractInfo<?>, Integer> failureInfos)
-    {
-        for (Map.Entry<AbstractInfo<?>, Integer> failureEntry : failureInfos.entrySet())
-        {
-            add(failureEntry.getKey(), failureEntry.getValue());
-        }
-    }
-
-    private void add(final AbstractInfo<?> info, final int failureCode)
+    public void add(final AbstractInfo<?> info, final long contextId, final int failureCode)
     {
         if (info instanceof ServletContextHelperInfo)
         {
@@ -78,6 +69,7 @@ public final class FailedDTOHolder
                 final ErrorPageRegistry.ErrorRegistration  reg = ErrorPageRegistry.getErrorRegistration((ServletInfo)info);
                 dto.errorCodes = reg.errorCodes;
                 dto.exceptions = reg.exceptions;
+                dto.servletContextId = contextId;
                 this.failedErrorPageDTOs.add(dto);
             }
 
@@ -88,6 +80,7 @@ public final class FailedDTOHolder
                 {
                     dto.patterns = ((ServletInfo) info).getPatterns();
                 }
+                dto.servletContextId = contextId;
                 this.failedServletDTOs.add(dto);
             }
         }
@@ -96,17 +89,20 @@ public final class FailedDTOHolder
             final FailedFilterDTO dto = (FailedFilterDTO)FilterDTOBuilder.build((FilterInfo) info, failureCode);
             dto.failureReason = failureCode;
 
+            dto.servletContextId = contextId;
             this.failedFilterDTOs.add(dto);
         }
         else if (info instanceof ResourceInfo)
         {
             final FailedResourceDTO dto = (FailedResourceDTO)ResourceDTOBuilder.build((ResourceInfo) info, true);
             dto.failureReason = failureCode;
+            dto.servletContextId = contextId;
             this.failedResourceDTOs.add(dto);
         }
         else if (info instanceof ListenerInfo)
         {
             final FailedListenerDTO dto = (FailedListenerDTO)ListenerDTOBuilder.build((ListenerInfo<?>)info, failureCode);
+            dto.servletContextId = contextId;
             this.failedListenerDTOs.add(dto);
         }
         else

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java?rev=1681335&r1=1681334&r2=1681335&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java Sat May 23 12:15:52 2015
@@ -39,6 +39,7 @@ import org.apache.felix.http.base.intern
 import org.apache.felix.http.base.internal.logger.SystemLogger;
 import org.apache.felix.http.base.internal.runtime.FilterInfo;
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.util.PatternUtil;
 import org.osgi.framework.Bundle;
 import org.osgi.service.http.HttpContext;
 import org.osgi.service.http.NamespaceException;
@@ -146,10 +147,13 @@ public final class PerBundleHttpServiceI
             throw new IllegalArgumentException("Malformed resource name [" + name + "]");
         }
 
-        // TODO - check validity of alias
+        if (!PatternUtil.isValidPattern(alias) || !alias.startsWith("/") )
+        {
+            throw new IllegalArgumentException("Malformed resource alias [" + alias + "]");
+        }
         try
         {
-            Servlet servlet = new ResourceServlet(name);
+            final Servlet servlet = new ResourceServlet(name);
             registerServlet(alias, servlet, null, context);
         }
         catch (ServletException e)
@@ -168,7 +172,7 @@ public final class PerBundleHttpServiceI
         {
             throw new IllegalArgumentException("Servlet must not be null");
         }
-        if (!isAliasValid(alias))
+        if (!PatternUtil.isValidPattern(alias) || !alias.startsWith("/") )
         {
             throw new IllegalArgumentException("Malformed servlet alias [" + alias + "]");
         }
@@ -324,21 +328,6 @@ public final class PerBundleHttpServiceI
         {
             return false;
         }
-
-        return true;
-    }
-
-    private boolean isAliasValid(final String alias)
-    {
-        if (alias == null)
-        {
-            return false;
-        }
-
-        if (!alias.equals("/") && (!alias.startsWith("/") || alias.endsWith("/")))
-        {
-            return false;
-        }
 
         return true;
     }

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java?rev=1681335&r1=1681334&r2=1681335&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java Sat May 23 12:15:52 2015
@@ -23,8 +23,10 @@ import javax.annotation.Nonnull;
 import javax.servlet.ServletContext;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.registry.EventListenerRegistry;
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceObjects;
 import org.osgi.service.http.context.ServletContextHelper;
 
@@ -42,14 +44,14 @@ public final class ContextHandler implem
     /** A map of all created servlet contexts. Each bundle gets it's own instance. */
     private final Map<Long, ContextHolder> perBundleContextMap = new HashMap<Long, ContextHolder>();
 
-    private final PerContextEventListener eventListener;
+    private final EventListenerRegistry eventListener;
 
     public ContextHandler(final ServletContextHelperInfo info,
             final ServletContext webContext,
             final Bundle bundle)
     {
         this.info = info;
-        this.eventListener = new PerContextEventListener(bundle, this);
+        this.eventListener = new EventListenerRegistry(bundle);
         this.bundle = bundle;
         this.sharedContext = new SharedServletContextImpl(webContext,
                 info.getName(),
@@ -69,11 +71,18 @@ public final class ContextHandler implem
         return this.info.compareTo(o.info);
     }
 
-    public void activate()
-    {
-        getServletContext(bundle);
+    /**
+     * Activate this context.
+     * @return {@code true} if it succeeded.
+     */
+    public boolean activate()
+    {
+        return getServletContext(bundle) != null;
     }
 
+    /**
+     * Deactivate this context.
+     */
     public void deactivate()
     {
         this.ungetServletContext(bundle);
@@ -92,24 +101,31 @@ public final class ContextHandler implem
             ContextHolder holder = this.perBundleContextMap.get(key);
             if ( holder == null )
             {
-                final ServiceObjects<ServletContextHelper> so = bundle.getBundleContext().getServiceObjects(this.info.getServiceReference());
+                final BundleContext ctx = bundle.getBundleContext();
+                final ServiceObjects<ServletContextHelper> so = (ctx == null ? null : ctx.getServiceObjects(this.info.getServiceReference()));
                 if ( so != null )
                 {
-                    holder = new ContextHolder();
-                    // TODO check for null of getService()
-                    holder.servletContextHelper = so.getService();
-                    holder.servletContext = new PerBundleServletContextImpl(bundle,
-                            this.sharedContext,
-                            holder.servletContextHelper,
-                            this.eventListener);
-                    this.perBundleContextMap.put(key, holder);
+                    final ServletContextHelper service = so.getService();
+                    if ( service != null )
+                    {
+                        holder = new ContextHolder();
+                        holder.servletContextHelper = service;
+                        holder.servletContext = new PerBundleServletContextImpl(bundle,
+                                this.sharedContext,
+                                service,
+                                this.eventListener);
+                        this.perBundleContextMap.put(key, holder);
+                    }
                 }
-                // TODO - check null for so
             }
-            holder.counter++;
+            if ( holder != null )
+            {
+                holder.counter++;
 
-            return holder.servletContext;
+                return holder.servletContext;
+            }
         }
+        return null;
     }
 
     public void ungetServletContext(@Nonnull final Bundle bundle)
@@ -126,7 +142,8 @@ public final class ContextHandler implem
                     this.perBundleContextMap.remove(key);
                     if ( holder.servletContextHelper != null )
                     {
-                        final ServiceObjects<ServletContextHelper> so = bundle.getBundleContext().getServiceObjects(this.info.getServiceReference());
+                        final BundleContext ctx = bundle.getBundleContext();
+                        final ServiceObjects<ServletContextHelper> so = (ctx == null ? null : ctx.getServiceObjects(this.info.getServiceReference()));
                         if ( so != null )
                         {
                             so.ungetService(holder.servletContextHelper);
@@ -144,7 +161,7 @@ public final class ContextHandler implem
         public ServletContextHelper servletContextHelper;
     }
 
-    public PerContextEventListener getListenerRegistry() {
+    public EventListenerRegistry getListenerRegistry() {
         return this.eventListener;
     }
 }

Added: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java?rev=1681335&view=auto
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java (added)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java Sat May 23 12:15:52 2015
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.whiteboard;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.felix.http.base.internal.runtime.AbstractInfo;
+import org.apache.felix.http.base.internal.runtime.dto.FailedDTOHolder;
+
+public class FailureStateHandler {
+
+    private static final class FailureStatus
+    {
+        public final Map<Integer, Set<Long>> reasonToContextsMapping = new ConcurrentHashMap<Integer, Set<Long>>();
+    }
+
+    private final Map<AbstractInfo<?>, FailureStatus> serviceFailures = new ConcurrentHashMap<AbstractInfo<?>, FailureStatus>();
+
+    public void add(final AbstractInfo<?> info, final int reason)
+    {
+        this.add(info, 0, reason);
+    }
+
+    public void add(final AbstractInfo<?> info, final long contextId, final int reason)
+    {
+        FailureStatus status = serviceFailures.get(info);
+        if ( status == null )
+        {
+            // we don't need to sync the add operation, that's taken care of by the caller.
+            status = new FailureStatus();
+            this.serviceFailures.put(info, status);
+        }
+        Set<Long> contexts = status.reasonToContextsMapping.get(reason);
+        if ( contexts == null )
+        {
+            contexts = new HashSet<Long>();
+        }
+        else
+        {
+            contexts = new HashSet<Long>(contexts);
+        }
+        contexts.add(contextId);
+        status.reasonToContextsMapping.put(reason, contexts);
+    }
+
+    public boolean remove(final AbstractInfo<?> info)
+    {
+        return remove(info, 0);
+    }
+
+    public boolean removeAll(final AbstractInfo<?> info)
+    {
+        final boolean result = remove(info, 0);
+        this.serviceFailures.remove(info);
+        return result;
+    }
+
+    public boolean remove(final AbstractInfo<?> info, final long contextId)
+    {
+        final FailureStatus status = serviceFailures.get(info);
+        if ( status != null )
+        {
+            final Iterator<Map.Entry<Integer, Set<Long>>> i = status.reasonToContextsMapping.entrySet().iterator();
+            while ( i.hasNext() )
+            {
+                final Map.Entry<Integer, Set<Long>> entry = i.next();
+                if ( entry.getValue().contains(contextId) )
+                {
+                    if ( entry.getValue().size() == 1 )
+                    {
+                        i.remove();
+                    }
+                    else
+                    {
+                        final Set<Long> set = new HashSet<Long>(entry.getValue());
+                        set.remove(contextId);
+                        entry.setValue(set);
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void getRuntime(final FailedDTOHolder failedDTOHolder) {
+        for(final Map.Entry<AbstractInfo<?>, FailureStatus> entry : this.serviceFailures.entrySet() )
+        {
+            final Iterator<Map.Entry<Integer, Set<Long>>> i = entry.getValue().reasonToContextsMapping.entrySet().iterator();
+            while ( i.hasNext() )
+            {
+                final Map.Entry<Integer, Set<Long>> status = i.next();
+
+                for(final long contextId : status.getValue())
+                {
+                    failedDTOHolder.add(entry.getKey(), contextId, status.getKey());
+                }
+            }
+        }
+
+    }
+}

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

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

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

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java?rev=1681335&r1=1681334&r2=1681335&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java Sat May 23 12:15:52 2015
@@ -43,6 +43,7 @@ import javax.servlet.http.HttpSessionAtt
 import javax.servlet.http.HttpSessionListener;
 
 import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.registry.EventListenerRegistry;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.wiring.BundleWiring;
 import org.osgi.service.http.context.ServletContextHelper;
@@ -58,17 +59,17 @@ public class PerBundleServletContextImpl
     private final Bundle bundle;
     private final ServletContext delegatee;
     private final ServletContextHelper contextHelper;
-    private final PerContextEventListener eventListener;
+    private final EventListenerRegistry eventListenerRegistry;
 
     public PerBundleServletContextImpl(final Bundle bundle,
             final ServletContext sharedContext,
             final ServletContextHelper delegatee,
-            final PerContextEventListener eventListener)
+            final EventListenerRegistry eventListenerRegistry)
     {
         this.bundle = bundle;
         this.delegatee = sharedContext;
         this.contextHelper = delegatee;
-        this.eventListener = eventListener;
+        this.eventListenerRegistry = eventListenerRegistry;
     }
 
     @Override
@@ -82,25 +83,25 @@ public class PerBundleServletContextImpl
     @Override
     public HttpSessionListener getHttpSessionListener()
     {
-        return this.eventListener;
+        return this.eventListenerRegistry;
     }
 
     @Override
     public HttpSessionAttributeListener getHttpSessionAttributeListener()
     {
-        return this.eventListener;
+        return this.eventListenerRegistry;
     }
 
     @Override
     public ServletRequestListener getServletRequestListener()
     {
-        return this.eventListener;
+        return this.eventListenerRegistry;
     }
 
     @Override
     public ServletRequestAttributeListener getServletRequestAttributeListener()
     {
-        return this.eventListener;
+        return this.eventListenerRegistry;
     }
 
     @Override

Modified: felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java?rev=1681335&r1=1681334&r2=1681335&view=diff
==============================================================================
--- felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java (original)
+++ felix/trunk/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java Sat May 23 12:15:52 2015
@@ -18,6 +18,7 @@ package org.apache.felix.http.base.inter
 
 import javax.annotation.Nonnull;
 
+import org.apache.felix.http.base.internal.context.ExtServletContext;
 import org.apache.felix.http.base.internal.handler.FilterHandler;
 import org.apache.felix.http.base.internal.handler.HttpServiceServletHandler;
 import org.apache.felix.http.base.internal.handler.ServletHandler;
@@ -29,6 +30,7 @@ import org.apache.felix.http.base.intern
 import org.apache.felix.http.base.internal.runtime.ServletInfo;
 import org.apache.felix.http.base.internal.service.ResourceServlet;
 import org.osgi.framework.BundleContext;
+import org.osgi.service.http.runtime.dto.DTOConstants;
 
 public final class WhiteboardHttpService
 {
@@ -52,25 +54,29 @@ public final class WhiteboardHttpService
      * Register a servlet.
      * @param contextInfo The servlet context helper info
      * @param servletInfo The servlet info
-     * @throws RegistrationFailureException
      */
-    public void registerServlet(@Nonnull final ContextHandler contextHandler,
+    public int registerServlet(@Nonnull final ContextHandler contextHandler,
             @Nonnull final ServletInfo servletInfo)
     {
+        final ExtServletContext context = contextHandler.getServletContext(servletInfo.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
         final ServletHandler holder = new WhiteboardServletHandler(
                 contextHandler.getContextInfo().getServiceId(),
-                contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
+                context,
                 servletInfo, bundleContext);
         handlerRegistry.addServlet(holder);
+        return -1;
     }
 
     /**
      * Unregister a servlet
      * @param contextInfo The servlet context helper info
      * @param servletInfo The servlet info
-     * @throws RegistrationFailureException
      */
-    public void unregisterServlet(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletInfo servletInfo) throws RegistrationFailureException
+    public void unregisterServlet(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletInfo servletInfo)
     {
         handlerRegistry.removeServlet(contextHandler.getContextInfo().getServiceId(), servletInfo, true);
         contextHandler.ungetServletContext(servletInfo.getServiceReference().getBundle());
@@ -81,14 +87,20 @@ public final class WhiteboardHttpService
      * @param contextInfo The servlet context helper info
      * @param filterInfo The filter info
      */
-    public void registerFilter(@Nonnull  final ContextHandler contextHandler,
+    public int registerFilter(@Nonnull  final ContextHandler contextHandler,
             @Nonnull final FilterInfo filterInfo)
     {
+        final ExtServletContext context = contextHandler.getServletContext(filterInfo.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
         final FilterHandler holder = new WhiteboardFilterHandler(
                 contextHandler.getContextInfo().getServiceId(),
-                contextHandler.getServletContext(filterInfo.getServiceReference().getBundle()),
+                context,
                 filterInfo, bundleContext);
         handlerRegistry.addFilter(holder);
+        return -1;
     }
 
     /**
@@ -106,28 +118,33 @@ public final class WhiteboardHttpService
      * Register a resource.
      * @param contextInfo The servlet context helper info
      * @param resourceInfo The resource info
-     * @throws RegistrationFailureException
      */
-    public void registerResource(@Nonnull final ContextHandler contextHandler,
+    public int registerResource(@Nonnull final ContextHandler contextHandler,
             @Nonnull final ResourceInfo resourceInfo)
     {
         final ServletInfo servletInfo = new ServletInfo(resourceInfo);
 
+        final ExtServletContext context = contextHandler.getServletContext(servletInfo.getServiceReference().getBundle());
+        if ( context == null )
+        {
+            return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
+        }
+
         final ServletHandler holder = new HttpServiceServletHandler(
                 contextHandler.getContextInfo().getServiceId(),
-                contextHandler.getServletContext(servletInfo.getServiceReference().getBundle()),
+                context,
                 servletInfo, new ResourceServlet(resourceInfo.getPrefix()));
 
         handlerRegistry.addServlet(holder);
+        return -1;
     }
 
     /**
      * Unregister a resource.
      * @param contextInfo The servlet context helper info
      * @param resourceInfo The resource info
-     * @throws RegistrationFailureException
      */
-    public void unregisterResource(@Nonnull final ContextHandler contextHandler, @Nonnull final ResourceInfo resourceInfo) throws RegistrationFailureException
+    public void unregisterResource(@Nonnull final ContextHandler contextHandler, @Nonnull final ResourceInfo resourceInfo)
     {
         final ServletInfo servletInfo = new ServletInfo(resourceInfo);
         handlerRegistry.removeServlet(contextHandler.getContextInfo().getServiceId(), servletInfo, true);

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=1681335&r1=1681334&r2=1681335&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 Sat May 23 12:15:52 2015
@@ -32,8 +32,6 @@ 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;
 import javax.servlet.ServletContext;
@@ -86,6 +84,7 @@ import org.osgi.framework.ServiceRegistr
 import org.osgi.service.http.context.ServletContextHelper;
 import org.osgi.service.http.runtime.HttpServiceRuntime;
 import org.osgi.service.http.runtime.HttpServiceRuntimeConstants;
+import org.osgi.service.http.runtime.dto.DTOConstants;
 import org.osgi.service.http.runtime.dto.ServletContextDTO;
 import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
 import org.osgi.util.tracker.ServiceTracker;
@@ -106,7 +105,7 @@ public final class WhiteboardManager
 
     private final WhiteboardHttpService httpService;
 
-    private final Map<AbstractInfo<?>, Integer> serviceFailures = new ConcurrentSkipListMap<AbstractInfo<?>, Integer>();
+    private final FailureStateHandler failureStateHandler = new FailureStateHandler();
 
     private volatile ServletContext webContext;
 
@@ -118,9 +117,6 @@ 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
@@ -140,7 +136,6 @@ public final class WhiteboardManager
 
     public void start(final ServletContext context)
     {
-        // TODO set Endpoint
         this.serviceRuntime.setAttribute(HttpServiceRuntimeConstants.HTTP_SERVICE_ID,
                 Collections.singletonList(this.httpServiceFactory.getHttpServiceServiceId()));
         this.runtimeServiceReg = this.bundleContext.registerService(HttpServiceRuntime.class,
@@ -233,7 +228,6 @@ public final class WhiteboardManager
             this.runtimeServiceReg.unregister();
             this.runtimeServiceReg = null;
         }
-        this.allInfos.clear();
     }
 
     public void setProperties(final Hashtable<String, Object> props)
@@ -283,14 +277,20 @@ public final class WhiteboardManager
 
     /**
      * Activate a servlet context helper.
-     * @param contextInfo A context info
+     *
+     * @param handler The context handler
+     * @return {@code true} if activation succeeded.
      */
-    private void activate(final ContextHandler handler)
+    private boolean activate(final ContextHandler handler)
     {
-        handler.activate();
+        if ( !handler.activate() )
+        {
+            return false;
+        }
 
         this.httpService.registerContext(handler);
 
+        // use a map to sort the listeners
         final Map<ServiceReference<ServletContextListener>, ServletContextListenerInfo> listeners = new TreeMap<ServiceReference<ServletContextListener>, ServletContextListenerInfo>();
         final List<WhiteboardServiceInfo<?>> services = new ArrayList<WhiteboardServiceInfo<?>>();
 
@@ -308,28 +308,40 @@ public final class WhiteboardManager
                 {
                     services.add(entry.getKey());
                 }
-                removeFailure(entry.getKey(), FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
+                if ( entry.getValue().size() == 1 )
+                {
+                    this.failureStateHandler.remove(entry.getKey());
+                }
             }
         }
         // context listeners first
         for(final ServletContextListenerInfo info : listeners.values())
         {
-            handler.getListenerRegistry().initialized(info);
+            final int reason = handler.getListenerRegistry().initialized(info, handler);
+            if ( reason != -1 )
+            {
+                final String type = info.getClass().getSimpleName().substring(0,info.getClass().getSimpleName().length() - 4);
+                SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
+                this.failureStateHandler.add(info, handler.getContextInfo().getServiceId(), reason);
+            }
         }
         // now register services
         for(final WhiteboardServiceInfo<?> info : services)
         {
             this.registerWhiteboardService(handler, info);
         }
+
+        return true;
     }
 
     /**
-     * Deactivate a servlet context helper.
-     * @param contextInfo A context info
+     * Deactivate a servlet context.
+     *
+     * @param handler A context handler
      */
     private void deactivate(final ContextHandler handler)
     {
-        // context listeners last
+        // context listeners last but sorted
         final Map<ServiceReference<ServletContextListener>, ServletContextListenerInfo> listeners = new TreeMap<ServiceReference<ServletContextListener>, ServletContextListenerInfo>();
         final Iterator<Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>>> i = this.servicesMap.entrySet().iterator();
         while ( i.hasNext() )
@@ -337,35 +349,47 @@ public final class WhiteboardManager
             final Map.Entry<WhiteboardServiceInfo<?>, List<ContextHandler>> entry = i.next();
             if ( entry.getValue().remove(handler) )
             {
-                if ( entry.getKey() instanceof ServletContextListenerInfo )
+                if ( !this.failureStateHandler.remove(entry.getKey(), handler.getContextInfo().getServiceId()) )
                 {
-                    final ServletContextListenerInfo info = (ServletContextListenerInfo)entry.getKey();
-                    listeners.put(info.getServiceReference(), info);
+                    if ( entry.getKey() instanceof ServletContextListenerInfo )
+                    {
+                        final ServletContextListenerInfo info = (ServletContextListenerInfo)entry.getKey();
+                        listeners.put(info.getServiceReference(), info);
+                    }
+                    else
+                    {
+                        this.unregisterWhiteboardService(handler, entry.getKey());
+                    }
                 }
-                else
+                if ( entry.getValue().isEmpty() )
                 {
-                    this.unregisterWhiteboardService(handler, entry.getKey());
+                    final String type = entry.getKey().getClass().getSimpleName().substring(0, entry.getKey().getClass().getSimpleName().length() - 4);
+                    SystemLogger.debug("Ignoring unmatching " + type + " service " + entry.getKey().getServiceReference());
+                    this.failureStateHandler.add(entry.getKey(), FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
                 }
             }
         }
         for(final ServletContextListenerInfo info : listeners.values())
         {
-            handler.getListenerRegistry().destroyed(info);
+            handler.getListenerRegistry().destroyed(info, handler);
         }
-        handler.deactivate();
 
         this.httpService.unregisterContext(handler);
+
+        handler.deactivate();
     }
 
     /**
      * Add a servlet context helper.
+     *
+     * @param info The servlet context helper info
+     * @return {@code true} if the service matches this http whiteboard service
      */
-    public void addContextHelper(final ServletContextHelperInfo info)
+    public boolean addContextHelper(final ServletContextHelperInfo info)
     {
         // no failure DTO and no logging if not matching
         if ( isMatchingService(info) )
         {
-            this.allInfos.put(info.getServiceId(), info);
             if ( info.isValid() )
             {
                 synchronized ( this.contextMap )
@@ -374,91 +398,127 @@ public final class WhiteboardManager
                             this.webContext,
                             this.bundleContext.getBundle());
 
+                    // check for activate/deactivate
                     List<ContextHandler> handlerList = this.contextMap.get(info.getName());
                     if ( handlerList == null )
                     {
                         handlerList = new ArrayList<ContextHandler>();
-                        this.contextMap.put(info.getName(), handlerList);
                     }
-                    handlerList.add(handler);
-                    Collections.sort(handlerList);
-                    // check for activate/deactivate
-                    if ( handlerList.get(0) == handler )
+                    final boolean activate = handlerList.isEmpty() || handlerList.get(0).compareTo(handler) > 0;
+                    if ( activate )
                     {
-                        // check for deactivate
-                        if ( handlerList.size() > 1 )
+                        // try to activate
+                        if ( this.activate(handler) )
+                        {
+                            handlerList.add(handler);
+                            Collections.sort(handlerList);
+                            this.contextMap.put(info.getName(), handlerList);
+
+                            // check for deactivate
+                            if ( handlerList.size() > 1 )
+                            {
+                                ContextHandler oldHead = handlerList.get(1);
+                                this.deactivate(oldHead);
+
+                                final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
+                                SystemLogger.debug("Ignoring shadowed " + type + " service " + info.getServiceReference());
+                                this.failureStateHandler.add(oldHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                            }
+                        }
+                        else
                         {
-                            ContextHandler oldHead = handlerList.get(1);
-                            this.deactivate(oldHead);
-                            this.serviceFailures.put(oldHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                            final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
+                            SystemLogger.error("Ignoring ungettable " + type + " service " + info.getServiceReference(), null);
+                            this.failureStateHandler.add(handler.getContextInfo(), DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE);
                         }
-                        removeFailure(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
-                        this.activate(handler);
                     }
                     else
                     {
-                        this.serviceFailures.put(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                        handlerList.add(handler);
+                        Collections.sort(handlerList);
+                        this.contextMap.put(info.getName(), handlerList);
+
+                        final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
+                        SystemLogger.debug("Ignoring shadowed " + type + " service " + info.getServiceReference());
+                        this.failureStateHandler.add(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
                     }
                 }
             }
             else
             {
                 final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
-                SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
-                this.serviceFailures.put(info, FAILURE_REASON_VALIDATION_FAILED);
+                SystemLogger.debug("Ignoring invalid " + type + " service " + info.getServiceReference());
+                this.failureStateHandler.add(info, FAILURE_REASON_VALIDATION_FAILED);
             }
+            return true;
         }
+        return false;
     }
 
     /**
      * Remove a servlet context helper
+     *
+     * @param The servlet context helper info
      */
-    public void removeContextHelper(final long serviceId)
+    public void removeContextHelper(final ServletContextHelperInfo info)
     {
-        final ServletContextHelperInfo info = (ServletContextHelperInfo) this.allInfos.remove(serviceId);
-        if ( info != null )
+        if ( info.isValid() )
         {
-            if ( info.isValid() )
+            synchronized ( this.contextMap )
             {
-                synchronized ( this.contextMap )
+                final List<ContextHandler> handlerList = this.contextMap.get(info.getName());
+                if ( handlerList != null )
                 {
-                    final List<ContextHandler> handlerList = this.contextMap.get(info.getName());
-                    if ( handlerList != null )
+                    final Iterator<ContextHandler> i = handlerList.iterator();
+                    boolean first = true;
+                    boolean activateNext = false;
+                    while ( i.hasNext() )
                     {
-                        final Iterator<ContextHandler> i = handlerList.iterator();
-                        boolean first = true;
-                        boolean activateNext = false;
-                        while ( i.hasNext() )
+                        final ContextHandler handler = i.next();
+                        if ( handler.getContextInfo().equals(info) )
                         {
-                            final ContextHandler handler = i.next();
-                            if ( handler.getContextInfo().equals(info) )
+                            i.remove();
+                            // check for deactivate
+                            if ( first )
                             {
-                                i.remove();
-                                // check for deactivate
-                                if ( first )
-                                {
-                                    this.deactivate(handler);
-                                    activateNext = true;
-                                }
-                                break;
+                                this.deactivate(handler);
+                                activateNext = true;
                             }
-                            first = false;
-                        }
-                        if ( handlerList.isEmpty() )
-                        {
-                            this.contextMap.remove(info.getName());
+                            break;
                         }
-                        else if ( activateNext )
+                        first = false;
+                    }
+                    if ( handlerList.isEmpty() )
+                    {
+                        this.contextMap.remove(info.getName());
+                    }
+                    else if ( activateNext )
+                    {
+                        // Try to activate next
+                        boolean done = false;
+                        while ( !handlerList.isEmpty() && !done)
                         {
-                            ContextHandler newHead = handlerList.get(0);
-                            this.activate(newHead);
-                            removeFailure(newHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+                            final ContextHandler newHead = handlerList.get(0);
+                            this.failureStateHandler.removeAll(newHead.getContextInfo());
+
+                            if ( this.activate(newHead) )
+                            {
+                                done = true;
+                            }
+                            else
+                            {
+                                handlerList.remove(0);
+
+                                final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
+                                SystemLogger.error("Ignoring ungettable " + type + " service " + info.getServiceReference(), null);
+                                this.failureStateHandler.add(newHead.getContextInfo(), DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE);
+                            }
                         }
                     }
                 }
             }
-            this.serviceFailures.remove(info);
         }
+        this.failureStateHandler.removeAll(info);
     }
 
     /**
@@ -499,14 +559,15 @@ public final class WhiteboardManager
 
     /**
      * Add new whiteboard service to the registry
+     *
      * @param info Whiteboard service info
+     * @return {@code true} if it matches this http service runtime
      */
-    public void addWhiteboardService(@Nonnull final WhiteboardServiceInfo<?> info)
+    public boolean addWhiteboardService(@Nonnull final WhiteboardServiceInfo<?> info)
     {
         // no logging and no DTO if other target service
         if ( isMatchingService(info) )
         {
-            this.allInfos.put(info.getServiceId(), info);
             if ( info.isValid() )
             {
                 synchronized ( this.contextMap )
@@ -515,7 +576,9 @@ public final class WhiteboardManager
                     this.servicesMap.put(info, handlerList);
                     if (handlerList.isEmpty())
                     {
-                        this.serviceFailures.put(info, FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
+                        final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
+                        SystemLogger.debug("Ignoring unmatched " + type + " service " + info.getServiceReference());
+                        this.failureStateHandler.add(info, FAILURE_REASON_NO_SERVLET_CONTEXT_MATCHING);
                     }
                     else
                     {
@@ -523,7 +586,13 @@ public final class WhiteboardManager
                         {
                             if ( info instanceof ServletContextListenerInfo )
                             {
-                                h.getListenerRegistry().initialized((ServletContextListenerInfo)info);
+                                final int reason = h.getListenerRegistry().initialized((ServletContextListenerInfo)info, h);
+                                if ( reason != -1 )
+                                {
+                                    final String type = info.getClass().getSimpleName().substring(0,info.getClass().getSimpleName().length() - 4);
+                                    SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
+                                    this.failureStateHandler.add(info, h.getContextInfo().getServiceId(), reason);
+                                }
                             }
                             else
                             {
@@ -537,28 +606,30 @@ public final class WhiteboardManager
             {
                 final String type = info.getClass().getSimpleName().substring(0, info.getClass().getSimpleName().length() - 4);
                 SystemLogger.debug("Ignoring invalid " + type + " service " + info.getServiceReference());
-                this.serviceFailures.put(info, FAILURE_REASON_VALIDATION_FAILED);
+                this.failureStateHandler.add(info, FAILURE_REASON_VALIDATION_FAILED);
             }
+            return true;
         }
+        return false;
     }
 
     /**
-     * Remove whiteboard service from the registry
+     * Remove whiteboard service from the registry.
+     *
      * @param info The service id of the whiteboard service
      */
-    public void removeWhiteboardService(final long serviceId)
+    public void removeWhiteboardService(final WhiteboardServiceInfo<?> info )
     {
-        final WhiteboardServiceInfo<?> info = (WhiteboardServiceInfo<?>) this.allInfos.remove(serviceId);
-        if ( info != null )
+        synchronized ( this.contextMap )
         {
-            if ( info.isValid() )
+            if ( !failureStateHandler.remove(info) )
             {
-                synchronized ( this.contextMap )
+                final List<ContextHandler> handlerList = this.servicesMap.remove(info);
+                if ( handlerList != null )
                 {
-                    final List<ContextHandler> handlerList = this.servicesMap.remove(info);
-                    if ( handlerList != null )
+                    for(final ContextHandler h : handlerList)
                     {
-                        for(final ContextHandler h : handlerList)
+                        if ( !failureStateHandler.remove(info, h.getContextInfo().getServiceId()) )
                         {
                             if ( !(info instanceof ServletContextListenerInfo ) )
                             {
@@ -566,13 +637,13 @@ public final class WhiteboardManager
                             }
                             else
                             {
-                                h.getListenerRegistry().initialized((ServletContextListenerInfo)info);
+                                h.getListenerRegistry().destroyed((ServletContextListenerInfo)info, h);
                             }
                         }
                     }
                 }
             }
-            this.serviceFailures.remove(info);
+            this.failureStateHandler.removeAll(info);
         }
     }
 
@@ -585,47 +656,59 @@ public final class WhiteboardManager
     {
         try
         {
+            int failureCode = -1;
             if ( info instanceof ServletInfo )
             {
-                this.httpService.registerServlet(handler, (ServletInfo)info);
+                failureCode = this.httpService.registerServlet(handler, (ServletInfo)info);
             }
             else if ( info instanceof FilterInfo )
             {
-                this.httpService.registerFilter(handler, (FilterInfo)info);
+                failureCode = this.httpService.registerFilter(handler, (FilterInfo)info);
             }
             else if ( info instanceof ResourceInfo )
             {
-                this.httpService.registerResource(handler, (ResourceInfo)info);
+                failureCode = this.httpService.registerResource(handler, (ResourceInfo)info);
             }
 
             else if ( info instanceof ServletContextAttributeListenerInfo )
             {
-                handler.getListenerRegistry().addListener((ServletContextAttributeListenerInfo) info);
+                failureCode = handler.getListenerRegistry().addListener((ServletContextAttributeListenerInfo) info);
             }
             else if ( info instanceof HttpSessionListenerInfo )
             {
-                handler.getListenerRegistry().addListener((HttpSessionListenerInfo) info);
+                failureCode = handler.getListenerRegistry().addListener((HttpSessionListenerInfo) info);
             }
             else if ( info instanceof HttpSessionAttributeListenerInfo )
             {
-                handler.getListenerRegistry().addListener((HttpSessionAttributeListenerInfo) info);
+                failureCode = handler.getListenerRegistry().addListener((HttpSessionAttributeListenerInfo) info);
             }
             else if ( info instanceof HttpSessionIdListenerInfo )
             {
-                handler.getListenerRegistry().addListener((HttpSessionIdListenerInfo) info);
+                failureCode = handler.getListenerRegistry().addListener((HttpSessionIdListenerInfo) info);
             }
             else if ( info instanceof ServletRequestListenerInfo )
             {
-                handler.getListenerRegistry().addListener((ServletRequestListenerInfo) info);
+                failureCode = handler.getListenerRegistry().addListener((ServletRequestListenerInfo) info);
             }
             else if ( info instanceof ServletRequestAttributeListenerInfo )
             {
-                handler.getListenerRegistry().addListener((ServletRequestAttributeListenerInfo) info);
+                failureCode = handler.getListenerRegistry().addListener((ServletRequestAttributeListenerInfo) info);
+            }
+            else
+            {
+                // This should never happen, but we log anyway
+                SystemLogger.error("Unknown whiteboard service " + info.getServiceReference(), null);
+            }
+            if ( failureCode != -1 )
+            {
+                final String type = info.getClass().getSimpleName().substring(0,info.getClass().getSimpleName().length() - 4);
+                SystemLogger.debug("Ignoring " + type + " service " + info.getServiceReference());
+                this.failureStateHandler.add(info, handler.getContextInfo().getServiceId(), failureCode);
             }
         }
-        catch (final RuntimeException e)
+        catch (final Exception e)
         {
-            serviceFailures.put(info, FAILURE_REASON_UNKNOWN);
+            this.failureStateHandler.add(info, handler.getContextInfo().getServiceId(), FAILURE_REASON_UNKNOWN);
             SystemLogger.error("Exception while registering whiteboard service " + info.getServiceReference(), e);
         }
     }
@@ -677,21 +760,11 @@ public final class WhiteboardManager
                 handler.getListenerRegistry().removeListener((ServletRequestAttributeListenerInfo) info);
             }
         }
-        catch (final RegistrationFailureException e)
+        catch (final Exception e)
         {
-            serviceFailures.put(e.getInfo(), e.getErrorCode());
-            SystemLogger.error("Exception while removing servlet", e);
+            SystemLogger.error("Exception while unregistering whiteboard service " + info.getServiceReference(), e);
         }
-        serviceFailures.remove(info);
-    }
 
-    private void removeFailure(AbstractInfo<?> info, int failureCode)
-    {
-        Integer registeredFailureCode = this.serviceFailures.get(info);
-        if (registeredFailureCode != null && registeredFailureCode == failureCode)
-        {
-            this.serviceFailures.remove(info);
-        }
     }
 
     /**
@@ -718,7 +791,7 @@ public final class WhiteboardManager
         return true;
     }
 
-    public ContextHandler getContextHandler(final Long contextId)
+    private ContextHandler getContextHandler(final Long contextId)
     {
         synchronized ( this.contextMap )
         {
@@ -734,21 +807,6 @@ public final class WhiteboardManager
         return null;
     }
 
-    public Collection<ContextHandler> getContextHandlers()
-    {
-         final List<ContextHandler> handlers = new ArrayList<ContextHandler>();
-         synchronized ( this.contextMap )
-         {
-             for(final List<ContextHandler> handlerList : this.contextMap.values())
-             {
-                 final ContextHandler h = handlerList.get(0);
-                 handlers.add(h);
-             }
-         }
-         return handlers;
-    }
-
-
     public RegistryRuntime getRuntime(final HandlerRegistry registry)
     {
         final FailedDTOHolder failedDTOHolder = new FailedDTOHolder();
@@ -775,7 +833,7 @@ public final class WhiteboardManager
                     contextHandlerList.add(list.get(0));
                 }
             }
-            failedDTOHolder.add(serviceFailures);
+            this.failureStateHandler.getRuntime(failedDTOHolder);
         }
         Collections.sort(contextHandlerList);
 

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=1681335&r1=1681334&r2=1681335&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 Sat May 23 12:15:52 2015
@@ -16,6 +16,9 @@
  */
 package org.apache.felix.http.base.internal.whiteboard.tracker;
 
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
 import javax.annotation.Nonnull;
 
 import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
@@ -34,6 +37,9 @@ public final class ServletContextHelperT
 {
     private final WhiteboardManager contextManager;
 
+    /** Map containing all info objects reported from the trackers. */
+    private final Map<Long, ServletContextHelperInfo> allInfos = new ConcurrentHashMap<Long, ServletContextHelperInfo>();
+
     private static org.osgi.framework.Filter createFilter(final BundleContext btx)
     {
         try
@@ -55,6 +61,12 @@ public final class ServletContextHelperT
     }
 
     @Override
+    public void close() {
+        super.close();
+        this.allInfos.clear();
+    }
+
+    @Override
     public final ServiceReference<ServletContextHelper> addingService(@Nonnull final ServiceReference<ServletContextHelper> ref)
     {
         this.added(ref);
@@ -77,11 +89,18 @@ public final class ServletContextHelperT
     private void added(@Nonnull final ServiceReference<ServletContextHelper> ref)
     {
         final ServletContextHelperInfo info = new ServletContextHelperInfo(ref);
-        this.contextManager.addContextHelper(info);
+        if ( this.contextManager.addContextHelper(info) )
+        {
+            this.allInfos.put((Long)ref.getProperty(Constants.SERVICE_ID), info);
+        }
     }
 
     private void removed(@Nonnull final ServiceReference<ServletContextHelper> ref)
     {
-        this.contextManager.removeContextHelper((Long)ref.getProperty(Constants.SERVICE_ID));
+        final ServletContextHelperInfo info = this.allInfos.get(ref.getProperty(Constants.SERVICE_ID));
+        if ( info != null )
+        {
+            this.contextManager.removeContextHelper(info);
+        }
     }
 }

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=1681335&r1=1681334&r2=1681335&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 Sat May 23 12:15:52 2015
@@ -16,6 +16,9 @@
  */
 package org.apache.felix.http.base.internal.whiteboard.tracker;
 
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
 import org.apache.felix.http.base.internal.runtime.WhiteboardServiceInfo;
 import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
 import org.osgi.framework.BundleContext;
@@ -33,6 +36,9 @@ import org.osgi.util.tracker.ServiceTrac
  */
 public abstract class WhiteboardServiceTracker<T> extends ServiceTracker<T, ServiceReference<T>>
 {
+    /** Map containing all info objects reported from the trackers. */
+    private final Map<Long, WhiteboardServiceInfo<T>> allInfos = new ConcurrentHashMap<Long, WhiteboardServiceInfo<T>>();
+
     /**
      * Create a filter expression for the specific listener.
      */
@@ -74,6 +80,12 @@ public abstract class WhiteboardServiceT
     }
 
     @Override
+    public void close() {
+        super.close();
+        this.allInfos.clear();
+    }
+
+    @Override
     public final ServiceReference<T> addingService(final ServiceReference<T> ref)
     {
         this.added(ref);
@@ -101,12 +113,19 @@ public abstract class WhiteboardServiceT
     private void added(final ServiceReference<T> ref)
     {
         final WhiteboardServiceInfo<T> info = this.getServiceInfo(ref);
-        this.contextManager.addWhiteboardService(info);
+        if ( this.contextManager.addWhiteboardService(info) )
+        {
+            this.allInfos.put((Long)ref.getProperty(Constants.SERVICE_ID), info);
+        }
     }
 
     private void removed(final ServiceReference<T> ref)
     {
-        this.contextManager.removeWhiteboardService((Long)ref.getProperty(Constants.SERVICE_ID));
+        final WhiteboardServiceInfo<T> info = this.allInfos.get(ref.getProperty(Constants.SERVICE_ID));
+        if ( info != null )
+        {
+            this.contextManager.removeWhiteboardService(info);
+        }
     }
 
     /**

Added: felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java?rev=1681335&view=auto
==============================================================================
--- felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java (added)
+++ felix/trunk/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java Sat May 23 12:15:52 2015
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.http.base.internal.whiteboard;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collections;
+
+import org.apache.felix.http.base.internal.runtime.ServletInfo;
+import org.apache.felix.http.base.internal.runtime.dto.FailedDTOHolder;
+import org.junit.Test;
+import org.osgi.service.http.runtime.dto.DTOConstants;
+
+public class FailureStateHandlerTest {
+
+    @Test public void testAddRemoveNoContext()
+    {
+        final ServletInfo info = new ServletInfo("test", "/test", 3, Collections.EMPTY_MAP);
+
+        final FailureStateHandler handler = new FailureStateHandler();
+        handler.add(info, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+
+        final FailedDTOHolder holder = new FailedDTOHolder();
+        handler.getRuntime(holder);
+
+        assertEquals(1, holder.failedServletDTOs.size());
+        assertEquals(DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, holder.failedServletDTOs.get(0).failureReason);
+
+        holder.failedServletDTOs.clear();
+
+        handler.remove(info);
+        handler.getRuntime(holder);
+
+        assertEquals(0, holder.failedServletDTOs.size());
+    }
+
+    @Test public void testAddRemoveContext()
+    {
+        final ServletInfo info1 = new ServletInfo("test", "/test", 3, Collections.EMPTY_MAP);
+        final ServletInfo info2 = new ServletInfo("test", "/test", 4, Collections.EMPTY_MAP);
+
+        final FailureStateHandler handler = new FailureStateHandler();
+        handler.add(info1, 1L, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+        handler.add(info2, 2L, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+
+        final FailedDTOHolder holder = new FailedDTOHolder();
+        handler.getRuntime(holder);
+
+        assertEquals(2, holder.failedServletDTOs.size());
+        assertEquals(DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, holder.failedServletDTOs.get(0).failureReason);
+        assertEquals(DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, holder.failedServletDTOs.get(1).failureReason);
+        assertEquals(1L, holder.failedServletDTOs.get(0).servletContextId);
+        assertEquals(2L, holder.failedServletDTOs.get(1).servletContextId);
+
+
+        handler.remove(info1, 1L);
+        handler.remove(info2, 2L);
+
+        holder.failedServletDTOs.clear();
+        handler.getRuntime(holder);
+
+        assertEquals(0, holder.failedServletDTOs.size());
+    }
+
+}

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

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

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