FELIX-4060 : Implement HTTP Whiteboard Service (RFC-189). Clean up error handling and add logging
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1681335 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
similarity index 84%
rename from http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java
rename to http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
index edf9937..c921a58 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerContextEventListener.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/EventListenerRegistry.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.felix.http.base.internal.whiteboard;
+package org.apache.felix.http.base.internal.registry;
import java.util.Collection;
import java.util.Collections;
@@ -46,12 +46,17 @@
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;
-public final class PerContextEventListener implements
+/**
+ * Per context event listener registry.
+ */
+public final class EventListenerRegistry implements
HttpSessionListener,
HttpSessionAttributeListener,
HttpSessionIdListener,
@@ -82,30 +87,32 @@
private final Bundle bundle;
- private final ContextHandler contextHandler;
-
- PerContextEventListener(final Bundle bundle, final ContextHandler contextHandler)
+ public EventListenerRegistry(final Bundle bundle)
{
this.bundle = bundle;
- this.contextHandler = contextHandler;
}
- void initialized(@Nonnull final ServletContextListenerInfo listenerInfo)
+ public int initialized(@Nonnull final ServletContextListenerInfo listenerInfo, @Nonnull final ContextHandler contextHandler)
{
final ServletContextListener listener = listenerInfo.getService(bundle);
if (listener != null)
{
- this.contextListeners.put(listenerInfo.getServiceReference(), listener);
-
final ServletContext context = contextHandler
.getServletContext(listenerInfo.getServiceReference()
.getBundle());
+ if ( context != null )
+ {
+ this.contextListeners.put(listenerInfo.getServiceReference(), listener);
- listener.contextInitialized(new ServletContextEvent(context));
+ listener.contextInitialized(new ServletContextEvent(context));
+ return -1;
+ }
+ return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
}
+ return DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE;
}
- void destroyed(@Nonnull final ServletContextListenerInfo listenerInfo)
+ public void destroyed(@Nonnull final ServletContextListenerInfo listenerInfo, @Nonnull final ContextHandler contextHandler)
{
final ServiceReference<ServletContextListener> listenerRef = listenerInfo
.getServiceReference();
@@ -129,14 +136,16 @@
*
* @param info
*/
- void addListener(@Nonnull final ServletContextAttributeListenerInfo 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;
}
/**
@@ -144,7 +153,7 @@
*
* @param info
*/
- void removeListener(@Nonnull final ServletContextAttributeListenerInfo info)
+ public void removeListener(@Nonnull final ServletContextAttributeListenerInfo info)
{
final ServletContextAttributeListener service = this.contextAttributeListeners
.remove(info.getServiceReference());
@@ -159,14 +168,16 @@
*
* @param info
*/
- void addListener(@Nonnull final HttpSessionAttributeListenerInfo 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;
}
/**
@@ -174,7 +185,7 @@
*
* @param info
*/
- void removeListener(@Nonnull final HttpSessionAttributeListenerInfo info)
+ public void removeListener(@Nonnull final HttpSessionAttributeListenerInfo info)
{
final HttpSessionAttributeListener service = this.sessionAttributeListeners
.remove(info.getServiceReference());
@@ -189,13 +200,15 @@
*
* @param info
*/
- void addListener(@Nonnull final HttpSessionListenerInfo 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;
}
/**
@@ -203,7 +216,7 @@
*
* @param info
*/
- void removeListener(@Nonnull final HttpSessionListenerInfo info)
+ public void removeListener(@Nonnull final HttpSessionListenerInfo info)
{
final HttpSessionListener service = this.sessionListeners.remove(info
.getServiceReference());
@@ -218,14 +231,16 @@
*
* @param info
*/
- void addListener(@Nonnull final HttpSessionIdListenerInfo 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;
}
/**
@@ -233,7 +248,7 @@
*
* @param info
*/
- void removeListener(@Nonnull final HttpSessionIdListenerInfo info)
+ public void removeListener(@Nonnull final HttpSessionIdListenerInfo info)
{
final HttpSessionIdListener service = this.sessionIdListeners.remove(info.getServiceReference());
if (service != null)
@@ -247,13 +262,15 @@
*
* @param info
*/
- void addListener(@Nonnull final ServletRequestListenerInfo 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;
}
/**
@@ -261,7 +278,7 @@
*
* @param info
*/
- void removeListener(@Nonnull final ServletRequestListenerInfo info)
+ public void removeListener(@Nonnull final ServletRequestListenerInfo info)
{
final ServletRequestListener service = this.requestListeners
.remove(info.getServiceReference());
@@ -276,14 +293,16 @@
*
* @param info
*/
- void addListener(@Nonnull final ServletRequestAttributeListenerInfo 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;
}
/**
@@ -291,7 +310,7 @@
*
* @param info
*/
- void removeListener(@Nonnull final ServletRequestAttributeListenerInfo info)
+ public void removeListener(@Nonnull final ServletRequestAttributeListenerInfo info)
{
final ServletRequestAttributeListener service = this.requestAttributeListeners
.remove(info.getServiceReference());
@@ -439,7 +458,7 @@
}
@SuppressWarnings("unchecked")
- void getRuntime(final ServletContextDTO dto)
+ public void getRuntime(final ServletContextDTO dto)
{
final Collection<ServiceReference<?>> col = CollectionUtils.<ServiceReference<?>>sortedUnion(
Collections.<ServiceReference<?>>reverseOrder(),
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java
index 3b2e283..580cb8d 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ResourceInfo.java
@@ -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 @@
@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()
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java
index a4d0ffc..fc2e5d2 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/FailedDTOHolder.java
@@ -20,7 +20,6 @@
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 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 @@
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 @@
{
dto.patterns = ((ServletInfo) info).getPatterns();
}
+ dto.servletContextId = contextId;
this.failedServletDTOs.add(dto);
}
}
@@ -96,17 +89,20 @@
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
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
index 1146497..266b65c 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/PerBundleHttpServiceImpl.java
@@ -39,6 +39,7 @@
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 @@
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 @@
{
throw new IllegalArgumentException("Servlet must not be null");
}
- if (!isAliasValid(alias))
+ if (!PatternUtil.isValidPattern(alias) || !alias.startsWith("/") )
{
throw new IllegalArgumentException("Malformed servlet alias [" + alias + "]");
}
@@ -327,19 +331,4 @@
return true;
}
-
- private boolean isAliasValid(final String alias)
- {
- if (alias == null)
- {
- return false;
- }
-
- if (!alias.equals("/") && (!alias.startsWith("/") || alias.endsWith("/")))
- {
- return false;
- }
-
- return true;
- }
}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
index 7b96cdd..16cbcc6 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/ContextHandler.java
@@ -23,8 +23,10 @@
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 @@
/** 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 @@
return this.info.compareTo(o.info);
}
- public void activate()
+ /**
+ * Activate this context.
+ * @return {@code true} if it succeeded.
+ */
+ public boolean activate()
{
- getServletContext(bundle);
+ return getServletContext(bundle) != null;
}
+ /**
+ * Deactivate this context.
+ */
public void deactivate()
{
this.ungetServletContext(bundle);
@@ -92,24 +101,31 @@
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 @@
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 ServletContextHelper servletContextHelper;
}
- public PerContextEventListener getListenerRegistry() {
+ public EventListenerRegistry getListenerRegistry() {
return this.eventListener;
}
}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java
new file mode 100644
index 0000000..60285ca
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandler.java
@@ -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());
+ }
+ }
+ }
+
+ }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
index 83655e9..9d9d845 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/PerBundleServletContextImpl.java
@@ -43,6 +43,7 @@
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 @@
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 @@
@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
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
index 659e284..5ce2948 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardHttpService.java
@@ -18,6 +18,7 @@
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.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 @@
* 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 @@
* @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 @@
* 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);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
index ec9d4bc..89b729d 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardManager.java
@@ -32,8 +32,6 @@
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.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 @@
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 @@
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 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 @@
this.runtimeServiceReg.unregister();
this.runtimeServiceReg = null;
}
- this.allInfos.clear();
}
public void setProperties(final Hashtable<String, Object> props)
@@ -283,14 +277,20 @@
/**
* 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 @@
{
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 @@
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 @@
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) )
{
- ContextHandler oldHead = handlerList.get(1);
- this.deactivate(oldHead);
- this.serviceFailures.put(oldHead.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+ 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);
+ }
}
- removeFailure(handler.getContextInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
- this.activate(handler);
+ else
+ {
+ 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);
+ }
}
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;
+ break;
}
- if ( handlerList.isEmpty() )
+ first = false;
+ }
+ if ( handlerList.isEmpty() )
+ {
+ this.contextMap.remove(info.getName());
+ }
+ else if ( activateNext )
+ {
+ // Try to activate next
+ boolean done = false;
+ while ( !handlerList.isEmpty() && !done)
{
- this.contextMap.remove(info.getName());
- }
- else if ( activateNext )
- {
- 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 @@
/**
* 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 @@
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 @@
{
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 @@
{
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 @@
}
else
{
- h.getListenerRegistry().initialized((ServletContextListenerInfo)info);
+ h.getListenerRegistry().destroyed((ServletContextListenerInfo)info, h);
}
}
}
}
}
- this.serviceFailures.remove(info);
+ this.failureStateHandler.removeAll(info);
}
}
@@ -585,47 +656,59 @@
{
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 @@
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 @@
return true;
}
- public ContextHandler getContextHandler(final Long contextId)
+ private ContextHandler getContextHandler(final Long contextId)
{
synchronized ( this.contextMap )
{
@@ -734,21 +807,6 @@
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 @@
contextHandlerList.add(list.get(0));
}
}
- failedDTOHolder.add(serviceFailures);
+ this.failureStateHandler.getRuntime(failedDTOHolder);
}
Collections.sort(contextHandlerList);
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
index dc8569c..d74c3d5 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/ServletContextHelperTracker.java
@@ -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 @@
{
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 @@
}
@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 @@
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);
+ }
}
}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
index 57b072c..4d32e1d 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/tracker/WhiteboardServiceTracker.java
@@ -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 @@
*/
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 @@
}
@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 @@
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);
+ }
}
/**
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java
new file mode 100644
index 0000000..14da25d
--- /dev/null
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/whiteboard/FailureStateHandlerTest.java
@@ -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());
+ }
+
+}