FELIX-4546 : Implement HttpServiceRuntime service. Apply patch from Thomas Baier
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1674868 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
index 8fa9788..d435bee 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/HandlerRegistry.java
@@ -17,7 +17,6 @@
package org.apache.felix.http.base.internal.handler;
import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
-import static org.osgi.service.http.runtime.dto.DTOConstants.FAILURE_REASON_VALIDATION_FAILED;
import java.util.ArrayList;
import java.util.Collections;
@@ -267,45 +266,23 @@
{
servletRegistry.addServlet(handler);
}
- else if (errorPages != null && errorPages.length > 0)
+ if (errorPages != null && errorPages.length > 0)
{
getRegistry(handler.getContextServiceId()).addErrorPage(handler, errorPages);
}
- else
- {
- throw new RegistrationFailureException(handler.getServletInfo(), FAILURE_REASON_VALIDATION_FAILED,
- "Neither patterns nor errorPages specified for " + handler.getName());
- }
}
public synchronized void removeServlet(Servlet servlet, boolean destroy)
{
- try
- {
- servletRegistry.removeServlet(servlet, destroy);
- }
- catch (RegistrationFailureException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
+ servletRegistry.removeServlet(servlet, destroy);
}
public synchronized Servlet removeServlet(ServletInfo servletInfo)
{
- try
- {
- return servletRegistry.removeServlet(servletInfo);
- }
- catch (RegistrationFailureException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
+ return servletRegistry.removeServlet(servletInfo);
}
- public synchronized void removeServlet(long contextId, ServletInfo servletInfo) throws RegistrationFailureException
+ public synchronized void removeServlet(long contextId, ServletInfo servletInfo)
{
String[] patterns = servletInfo.getPatterns();
if (patterns != null && patterns.length > 0)
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
index 6fc17e5..aa7a4e6 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/PerContextHandlerRegistry.java
@@ -27,6 +27,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.TreeSet;
import javax.servlet.DispatcherType;
@@ -52,6 +53,7 @@
private volatile ErrorsMapping errorsMapping = new ErrorsMapping();
private final HandlerRankingMultimap<String> registeredErrorPages = new HandlerRankingMultimap<String>();
+ private final Set<ServletHandler> initFailures = new TreeSet<ServletHandler>();
private final long serviceId;
@@ -132,7 +134,7 @@
void addErrorPage(ServletHandler handler, String[] errorPages) throws RegistrationFailureException
{
Update<String> update = this.registeredErrorPages.add(errorPages, handler);
- initHandlers(update.getInit());
+ initFirstHandler(update.getInit());
this.errorsMapping = this.errorsMapping.update(update.getActivated(), update.getDeactivated());
destroyHandlers(update.getDestroy());
}
@@ -195,7 +197,7 @@
return null;
}
- void removeErrorPage(ServletInfo info) throws RegistrationFailureException
+ void removeErrorPage(ServletInfo info)
{
ServletHandler handler = getServletHandler(info);
if (handler == null)
@@ -204,9 +206,39 @@
}
String[] errorPages = handler.getServletInfo().getErrorPage();
Update<String> update = this.registeredErrorPages.remove(errorPages, handler);
- initHandlers(update.getInit());
- this.errorsMapping = this.errorsMapping.update(update.getActivated(), update.getDeactivated());
+ Set<ServletHandler> initializedHandlers = initHandlers(update.getInit());
+ Map<String, ServletHandler> activated = update.getActivated();
+ activated = removeFailures(activated, initializedHandlers);
+ try
+ {
+ this.errorsMapping = this.errorsMapping.update(activated, update.getDeactivated());
+ }
+ catch (RegistrationFailureException e)
+ {
+ //this should not happen
+ throw new RuntimeException("Exception on error page removal", e);
+ }
destroyHandlers(update.getDestroy());
+ this.initFailures.remove(handler);
+ }
+
+ private Map<String, ServletHandler> removeFailures(Map<String, ServletHandler> activated,
+ Set<ServletHandler> initializedHandlers)
+ {
+ if (activated.size() == initializedHandlers.size())
+ {
+ return activated;
+ }
+
+ Map<String, ServletHandler> result = new HashMap<String, ServletHandler>();
+ for (Map.Entry<String, ServletHandler> entry : activated.entrySet())
+ {
+ if (initializedHandlers.contains(entry.getValue()))
+ {
+ result.put(entry.getKey(), entry.getValue());
+ }
+ }
+ return result;
}
private ServletHandler getServletHandler(final ServletInfo servletInfo)
@@ -233,20 +265,44 @@
return null;
}
- private void initHandlers(Collection<ServletHandler> handlers) throws RegistrationFailureException
+ private void initFirstHandler(Collection<ServletHandler> handlers) throws RegistrationFailureException
{
+ if (handlers.isEmpty())
+ {
+ return;
+ }
+
+ ServletHandler handler = handlers.iterator().next();
+ try
+ {
+ handler.init();
+ }
+ catch (ServletException e)
+ {
+ throw new RegistrationFailureException(handler.getServletInfo(), FAILURE_REASON_EXCEPTION_ON_INIT, e);
+ }
+ }
+
+ private Set<ServletHandler> initHandlers(Collection<ServletHandler> handlers)
+ {
+ Set<ServletHandler> success = new TreeSet<ServletHandler>();
+ List<ServletHandler> failure = new ArrayList<ServletHandler>();
for (ServletHandler servletHandler : handlers)
{
try
{
servletHandler.init();
+ success.add(servletHandler);
}
catch (ServletException e)
{
- // TODO we should collect this cases and not throw an exception immediately
- throw new RegistrationFailureException(servletHandler.getServletInfo(), FAILURE_REASON_EXCEPTION_ON_INIT, e);
+ failure.add(servletHandler);
}
}
+
+ this.initFailures.addAll(failure);
+
+ return success;
}
private void destroyHandlers(Collection<? extends AbstractHandler<?>> servletHandlers)
@@ -298,6 +354,10 @@
private boolean referencesDispatcherType(FilterHandler handler, DispatcherType dispatcherType)
{
+ if (dispatcherType == null)
+ {
+ return true;
+ }
return Arrays.asList(handler.getFilterInfo().getDispatcher()).contains(dispatcherType);
}
@@ -355,18 +415,18 @@
errorPages.add(ErrorPageRuntime.fromServletRuntime(servletHandler));
}
- addShadowedHandlers(failureRuntimeBuilder, this.registeredErrorPages.getShadowedValues());
+ addFailures(failureRuntimeBuilder, this.registeredErrorPages.getShadowedValues(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+ addFailures(failureRuntimeBuilder, this.initFailures, FAILURE_REASON_EXCEPTION_ON_INIT);
- return new ContextRuntime(filterRuntimes,
- errorPages,
- this.serviceId);
+ return new ContextRuntime(filterRuntimes, errorPages, this.serviceId);
}
- private void addShadowedHandlers(FailureRuntime.Builder failureRuntimeBuilder, Collection<ServletHandler> handlers)
+ private void addFailures(FailureRuntime.Builder failureRuntimeBuilder, Collection<ServletHandler> handlers, int failureCode)
{
for (ServletHandler handler : handlers)
{
- failureRuntimeBuilder.add(handler.getServletInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+ failureRuntimeBuilder.add(handler.getServletInfo(), failureCode);
}
}
+
}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandlerRegistry.java
index ab8daa9..82edda4 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/handler/ServletHandlerRegistry.java
@@ -29,6 +29,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
@@ -52,6 +53,7 @@
{
private final HandlerRankingMultimap<String> registeredServletHandlers;
private final SortedSet<ServletHandler> allServletHandlers = new TreeSet<ServletHandler>();
+ private final Set<ServletHandler> initFailures = new TreeSet<ServletHandler>();
private volatile ContextRegistry contextRegistry;
@@ -89,7 +91,7 @@
if (this.allServletHandlers.contains(handler))
{
throw new RegistrationFailureException(handler.getServletInfo(), FAILURE_REASON_SERVICE_ALREAY_USED,
- "Filter instance " + handler.getName() + " already registered");
+ "Servlet instance " + handler.getName() + " already registered");
}
registerServlet(handler);
@@ -99,20 +101,12 @@
private void registerServlet(ServletHandler handler) throws RegistrationFailureException
{
- String contextPath = contextRegistry.getPath(handler.getContextServiceId());
- if (contextPath == null)
- {
- throw new RegistrationFailureException(handler.getServletInfo(), FAILURE_REASON_SERVLET_CONTEXT_FAILURE);
- }
- contextPath = contextPath.equals("/") ? "" : contextPath;
- List<String> patterns = new ArrayList<String>(asList(handler.getServletInfo().getPatterns()));
- for (int i = 0; i < patterns.size(); i++)
- {
- patterns.set(i, contextPath + patterns.get(i));
- }
+ long contextId = handler.getContextServiceId();
+ List<String> patterns = getFullPathsChecked(handler);
+
Update<String> update = this.registeredServletHandlers.add(patterns, handler);
- initHandlers(update.getInit());
- contextRegistry = contextRegistry.updateServletMapping(update, handler.getContextServiceId());
+ initFirstHandler(update.getInit());
+ contextRegistry = contextRegistry.updateServletMapping(update.getActivated(), update.getDeactivated(), contextId);
destroyHandlers(update.getDestroy());
}
@@ -128,17 +122,17 @@
this.registeredServletHandlers.clear();
}
- synchronized Servlet removeServlet(ServletInfo servletInfo) throws RegistrationFailureException
+ synchronized Servlet removeServlet(ServletInfo servletInfo)
{
return removeServlet(0L, servletInfo, true);
}
- synchronized Servlet removeServlet(Long contextId, ServletInfo servletInfo) throws RegistrationFailureException
+ synchronized Servlet removeServlet(Long contextId, ServletInfo servletInfo)
{
return removeServlet(contextId, servletInfo, true);
}
- synchronized Servlet removeServlet(Long contextId, ServletInfo servletInfo, final boolean destroy) throws RegistrationFailureException
+ synchronized Servlet removeServlet(Long contextId, ServletInfo servletInfo, final boolean destroy)
{
ServletHandler handler = getServletHandler(servletInfo);
if (handler == null)
@@ -173,7 +167,7 @@
return null;
}
- synchronized void removeServlet(Servlet servlet, final boolean destroy) throws RegistrationFailureException
+ synchronized void removeServlet(Servlet servlet, final boolean destroy)
{
Iterator<ServletHandler> it = this.allServletHandlers.iterator();
List<ServletHandler> removals = new ArrayList<ServletHandler>();
@@ -192,39 +186,108 @@
}
}
- private void removeServlet(ServletHandler handler, boolean destroy) throws RegistrationFailureException
+ private void removeServlet(ServletHandler handler, boolean destroy)
+ {
+ long contextId = handler.getContextServiceId();
+ List<String> patterns = getFullPaths(handler);
+ Update<String> update = this.registeredServletHandlers.remove(patterns, handler);
+ Set<ServletHandler> initializedHandlers = initHandlers(update.getInit());
+ Map<String, ServletHandler> activated = update.getActivated();
+ activated = removeFailures(activated, initializedHandlers);
+ contextRegistry = contextRegistry.updateServletMapping(activated, update.getDeactivated(), contextId);
+ if (destroy)
+ {
+ destroyHandlers(update.getDestroy());
+ }
+ this.initFailures.remove(handler);
+ this.allServletHandlers.remove(handler);
+ }
+
+ private Map<String, ServletHandler> removeFailures(Map<String, ServletHandler> activated,
+ Set<ServletHandler> initializedHandlers)
+ {
+ if (activated.size() == initializedHandlers.size())
+ {
+ return activated;
+ }
+
+ Map<String, ServletHandler> result = new HashMap<String, ServletHandler>();
+ for (Map.Entry<String, ServletHandler> entry : activated.entrySet())
+ {
+ if (initializedHandlers.contains(entry.getValue()))
+ {
+ result.put(entry.getKey(), entry.getValue());
+ }
+ }
+ return result;
+ }
+
+ private List<String> getFullPathsChecked(ServletHandler handler) throws RegistrationFailureException
{
String contextPath = contextRegistry.getPath(handler.getContextServiceId());
+ if (contextPath == null)
+ {
+ throw new RegistrationFailureException(handler.getServletInfo(), FAILURE_REASON_SERVLET_CONTEXT_FAILURE);
+ }
+ return getFullPaths(contextPath, handler);
+ }
+
+ private List<String> getFullPaths(ServletHandler handler)
+ {
+ String contextPath = contextRegistry.getPath(handler.getContextServiceId());
+ return getFullPaths(contextPath, handler);
+ }
+
+ private List<String> getFullPaths(String contextPath, ServletHandler handler)
+ {
contextPath = contextPath.equals("/") ? "" : contextPath;
+
List<String> patterns = new ArrayList<String>(asList(handler.getServletInfo().getPatterns()));
for (int i = 0; i < patterns.size(); i++)
{
patterns.set(i, contextPath + patterns.get(i));
}
- Update<String> update = this.registeredServletHandlers.remove(patterns, handler);
- initHandlers(update.getInit());
- contextRegistry = contextRegistry.updateServletMapping(update, handler.getContextServiceId());
- if (destroy)
- {
- destroyHandlers(update.getDestroy());
- }
- this.allServletHandlers.remove(handler);
+ return patterns;
}
- private void initHandlers(Collection<ServletHandler> handlers) throws RegistrationFailureException
+ private void initFirstHandler(Collection<ServletHandler> handlers) throws RegistrationFailureException
{
+ if (handlers.isEmpty())
+ {
+ return;
+ }
+
+ ServletHandler handler = handlers.iterator().next();
+ try
+ {
+ handler.init();
+ }
+ catch (ServletException e)
+ {
+ throw new RegistrationFailureException(handler.getServletInfo(), FAILURE_REASON_EXCEPTION_ON_INIT, e);
+ }
+ }
+
+ private Set<ServletHandler> initHandlers(Collection<ServletHandler> handlers)
+ {
+ Set<ServletHandler> success = new TreeSet<ServletHandler>();
+ List<ServletHandler> failure = new ArrayList<ServletHandler>();
for (ServletHandler servletHandler : handlers)
{
try
{
servletHandler.init();
+ success.add(servletHandler);
}
catch (ServletException e)
{
- // TODO we should collect this cases and not throw an exception immediately
- throw new RegistrationFailureException(servletHandler.getServletInfo(), FAILURE_REASON_EXCEPTION_ON_INIT, e);
+ failure.add(servletHandler);
}
}
+
+ this.initFailures.addAll(failure);
+
+ return success;
}
private void destroyHandlers(Collection<? extends AbstractHandler<?>> servletHandlers)
@@ -248,7 +311,8 @@
synchronized ServletRegistryRuntime getRuntime(FailureRuntime.Builder failureRuntimeBuilder)
{
- addShadowedHandlers(failureRuntimeBuilder, this.registeredServletHandlers.getShadowedValues());
+ addFailures(failureRuntimeBuilder, this.registeredServletHandlers.getShadowedValues(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+ addFailures(failureRuntimeBuilder, this.initFailures, FAILURE_REASON_EXCEPTION_ON_INIT);
Collection<ServletRuntime> servletRuntimes = new TreeSet<ServletRuntime>(ServletRuntime.COMPARATOR);
Collection<ServletRuntime> resourceRuntimes = new TreeSet<ServletRuntime>(ServletRuntime.COMPARATOR);
@@ -266,11 +330,11 @@
return new ServletRegistryRuntime(servletRuntimes, resourceRuntimes);
}
- private void addShadowedHandlers(FailureRuntime.Builder failureRuntimeBuilder, Collection<ServletHandler> handlers)
+ private void addFailures(FailureRuntime.Builder failureRuntimeBuilder, Collection<ServletHandler> handlers, int failureCode)
{
for (ServletHandler handler : handlers)
{
- failureRuntimeBuilder.add(handler.getServletInfo(), FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
+ failureRuntimeBuilder.add(handler.getServletInfo(), failureCode);
}
}
@@ -381,7 +445,7 @@
return ids;
}
- ContextRegistry updateServletMapping(Update<String> update, long contextId)
+ ContextRegistry updateServletMapping(Map<String, ServletHandler> activated, Map<String, ServletHandler> deactivated, long contextId)
{
Map<Long, HandlerMapping<ServletHandler>> newServletMappingsPerContext = new HashMap<Long, HandlerMapping<ServletHandler>>(servletMappingsPerContext);
HandlerMapping<ServletHandler> servletMapping = newServletMappingsPerContext.get(contextId);
@@ -389,7 +453,7 @@
{
servletMapping = new HandlerMapping<ServletHandler>();
}
- newServletMappingsPerContext.put(contextId, servletMapping.update(convert(update.getActivated()), convert(update.getDeactivated())));
+ newServletMappingsPerContext.put(contextId, servletMapping.update(convert(activated), convert(deactivated)));
return new ContextRegistry(contextRankingsPerId, contextRankings, newServletMappingsPerContext);
}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
index b9173e1..b2dc85e 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/ServletInfo.java
@@ -157,7 +157,7 @@
@Override
public boolean isValid()
{
- return super.isValid() && (isEmpty(this.patterns) ^ isEmpty(this.errorPage));
+ return super.isValid() && !(isEmpty(this.patterns) && isEmpty(this.errorPage));
}
public String getName()
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseDTOBuilder.java
index 99361f8..ddcde61 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseDTOBuilder.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/BaseDTOBuilder.java
@@ -36,7 +36,7 @@
this.dtoFactory = dtoFactory;
}
- Collection<U> build(Collection<T> whiteboardServices, long servletContextId)
+ Collection<U> build(Collection<? extends T> whiteboardServices, long servletContextId)
{
List<U> dtoList = new ArrayList<U>();
for (T whiteboardService : whiteboardServices)
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java
new file mode 100644
index 0000000..9c1a9be
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/runtime/dto/RequestInfoDTOBuilder.java
@@ -0,0 +1,66 @@
+/*
+ * 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.runtime.dto;
+
+import static java.util.Arrays.asList;
+
+import org.apache.felix.http.base.internal.handler.FilterHandler;
+import org.apache.felix.http.base.internal.handler.HandlerRegistry;
+import org.apache.felix.http.base.internal.handler.ServletHandler;
+import org.osgi.service.http.runtime.dto.FilterDTO;
+import org.osgi.service.http.runtime.dto.RequestInfoDTO;
+
+public final class RequestInfoDTOBuilder
+{
+ private static final FilterDTO[] FILTER_DTO_ARRAY = new FilterDTO[0];
+
+ private final HandlerRegistry registry;
+ private final String path;
+
+ public RequestInfoDTOBuilder(HandlerRegistry registry, String path)
+ {
+ this.registry = registry;
+ this.path = path;
+ }
+
+ public RequestInfoDTO build()
+ {
+ ServletHandler servletHandler = registry.getServletHandler(path);
+ FilterHandler[] filterHandlers = registry.getFilterHandlers(servletHandler, null, path);
+ Long contextServiceId = servletHandler.getContextServiceId();
+
+ RequestInfoDTO requestInfoDTO = new RequestInfoDTO();
+ requestInfoDTO.path = path;
+ requestInfoDTO.servletContextId = contextServiceId;
+
+ requestInfoDTO.filterDTOs = FilterDTOBuilder.create()
+ .build(asList(filterHandlers), contextServiceId)
+ .toArray(FILTER_DTO_ARRAY);
+
+ if (servletHandler.getServletInfo().isResource())
+ {
+ requestInfoDTO.resourceDTO = ResourceDTOBuilder.create()
+ .buildDTO(servletHandler, contextServiceId);
+ }
+ else
+ {
+ requestInfoDTO.servletDTO = ServletDTOBuilder.create()
+ .buildDTO(servletHandler, contextServiceId);
+ }
+ return requestInfoDTO;
+ }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
index d6b2eab..aae2679 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/HttpServiceRuntimeImpl.java
@@ -23,6 +23,7 @@
import org.apache.felix.http.base.internal.handler.HandlerRegistry;
import org.apache.felix.http.base.internal.runtime.dto.RegistryRuntime;
+import org.apache.felix.http.base.internal.runtime.dto.RequestInfoDTOBuilder;
import org.apache.felix.http.base.internal.runtime.dto.RuntimeDTOBuilder;
import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
import org.osgi.service.http.runtime.HttpServiceRuntime;
@@ -31,7 +32,7 @@
public final class HttpServiceRuntimeImpl implements HttpServiceRuntime
{
- private final Hashtable<String, Object> attributes = new Hashtable<String, Object>();
+ private volatile Hashtable<String, Object> attributes = new Hashtable<String, Object>();
private final HandlerRegistry registry;
private final WhiteboardManager contextManager;
@@ -44,7 +45,7 @@
}
@Override
- public synchronized RuntimeDTO getRuntimeDTO()
+ public RuntimeDTO getRuntimeDTO()
{
RegistryRuntime runtime = contextManager.getRuntime(registry);
RuntimeDTOBuilder runtimeDTOBuilder = new RuntimeDTOBuilder(runtime, attributes);
@@ -54,25 +55,28 @@
@Override
public RequestInfoDTO calculateRequestInfoDTO(String path)
{
- return null;
+ return new RequestInfoDTOBuilder(registry, path).build();
}
public synchronized void setAttribute(String name, Object value)
{
- attributes.put(name, value);
+ Hashtable<String, Object> newAttributes = new Hashtable<String, Object>(attributes);
+ newAttributes.put(name, value);
+ attributes = newAttributes;
}
- public synchronized void setAllAttributes(Dictionary<String, Object> attributes)
+ public synchronized void setAllAttributes(Dictionary<String, Object> newAttributes)
{
- this.attributes.clear();
- for (String key :list(attributes.keys()))
+ Hashtable<String, Object> replacement = new Hashtable<String, Object>();
+ for (String key : list(newAttributes.keys()))
{
- this.attributes.put(key, attributes.get(key));
+ replacement.put(key, newAttributes.get(key));
}
+ attributes = replacement;
}
- public synchronized Dictionary<String, Object> getAttributes()
+ public Dictionary<String, Object> getAttributes()
{
- return attributes;
+ return new Hashtable<String, Object>(attributes);
}
}
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 65f6863..29523ce 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
@@ -74,10 +74,6 @@
{
throw e;
}
- catch (final ServletException e)
- {
- throw new RegistrationFailureException(servletInfo, FAILURE_REASON_EXCEPTION_ON_INIT, e);
- }
}
/**
diff --git a/http/itest/src/test/java/org/apache/felix/http/itest/HttpServiceRuntimeTest.java b/http/itest/src/test/java/org/apache/felix/http/itest/HttpServiceRuntimeTest.java
index 2c022a6..5dee199 100644
--- a/http/itest/src/test/java/org/apache/felix/http/itest/HttpServiceRuntimeTest.java
+++ b/http/itest/src/test/java/org/apache/felix/http/itest/HttpServiceRuntimeTest.java
@@ -48,11 +48,15 @@
import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN;
import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Dictionary;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.SortedSet;
+import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -67,10 +71,13 @@
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionListener;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.ExamReactorStrategy;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.ops4j.pax.exam.spi.reactors.EagerSingleStagedReactorFactory;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
@@ -79,14 +86,37 @@
import org.osgi.service.http.runtime.HttpServiceRuntime;
import org.osgi.service.http.runtime.dto.FailedErrorPageDTO;
import org.osgi.service.http.runtime.dto.FailedServletDTO;
+import org.osgi.service.http.runtime.dto.RequestInfoDTO;
import org.osgi.service.http.runtime.dto.RuntimeDTO;
import org.osgi.service.http.runtime.dto.ServletContextDTO;
@RunWith(JUnit4TestRunner.class)
+@ExamReactorStrategy( EagerSingleStagedReactorFactory.class )
public class HttpServiceRuntimeTest extends BaseIntegrationTest
{
+ Collection<ServiceRegistration<?>> registrations = new ArrayList<ServiceRegistration<?>>();
+
private static final long DEFAULT_SLEEP = 100;
+ @After
+ public void unregisterServices() throws Exception
+ {
+ for (ServiceRegistration<?> serviceRegistration : registrations)
+ {
+ try
+ {
+ serviceRegistration.unregister();
+ }
+ catch (Exception e)
+ {
+ // already unregistered
+ }
+ }
+ registrations.clear();
+
+ Thread.sleep(100);
+ }
+
private void registerServlet(String name, String path) throws InterruptedException
{
CountDownLatch initLatch = new CountDownLatch(1);
@@ -109,7 +139,7 @@
Dictionary<String, ?> properties = createDictionary(context == null ?
propertyEntries.subList(0, 4).toArray() : propertyEntries.toArray());
- m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties);
+ registrations.add(m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties));
}
private void registerFilter(String name, String path) throws InterruptedException
@@ -134,7 +164,7 @@
Dictionary<String, ?> properties = createDictionary(context == null ?
propertyEntries.subList(0, 4).toArray() : propertyEntries.toArray());
- m_context.registerService(Filter.class.getName(), new TestFilter(initLatch, null), properties);
+ registrations.add(m_context.registerService(Filter.class.getName(), new TestFilter(initLatch, null), properties));
}
private void registerResource(String prefix, String path) throws InterruptedException
@@ -152,7 +182,7 @@
Dictionary<String, ?> properties = createDictionary(context == null ?
propertyEntries.subList(0, 4).toArray() : propertyEntries.toArray());
- m_context.registerService(TestResource.class.getName(), new TestResource(), properties);
+ registrations.add(m_context.registerService(TestResource.class.getName(), new TestResource(), properties));
awaitServiceRegistration();
}
@@ -178,7 +208,7 @@
Dictionary<String, ?> properties = createDictionary(context == null ?
propertyEntries.subList(0, 4).toArray() : propertyEntries.toArray());
- m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties);
+ registrations.add(m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties));
}
private void registerListener(Class<?> listenerClass, boolean useWithWhiteboard) throws InterruptedException
@@ -195,7 +225,7 @@
Dictionary<String, ?> properties = createDictionary(context == null ?
propertyEntries.subList(0, 2).toArray() : propertyEntries.toArray());
- m_context.registerService(listenerClass.getName(), mock(listenerClass), properties);
+ registrations.add(m_context.registerService(listenerClass.getName(), mock(listenerClass), properties));
awaitServiceRegistration();
}
@@ -206,6 +236,7 @@
HTTP_WHITEBOARD_CONTEXT_PATH, path);
ServiceRegistration<?> contextRegistration = m_context.registerService(ServletContextHelper.class.getName(), mock(ServletContextHelper.class), properties);
+ registrations.add(contextRegistration);
awaitServiceRegistration();
return contextRegistration;
}
@@ -383,6 +414,61 @@
}
@Test
+ public void dtosForSuccesfullyRegisteredErrorPageForClientErrorCodes() throws Exception
+ {
+ dtosForSuccesfullyRegisteredErrorPageWithWildcardErrorCode("4xx", 400);
+ }
+
+ @Test
+ public void dtosForSuccesfullyRegisteredErrorPageForClientErrorCodesCaseInsensitive() throws Exception
+ {
+ dtosForSuccesfullyRegisteredErrorPageWithWildcardErrorCode("4xX", 400);
+ }
+
+ @Test
+ public void dtosForSuccesfullyRegisteredErrorPageForServerErrorCodes() throws Exception
+ {
+ dtosForSuccesfullyRegisteredErrorPageWithWildcardErrorCode("5xx", 500);
+ }
+
+ @Test
+ public void dtosForSuccesfullyRegisteredErrorPageForServerErrorCodesCaseInsensitive() throws Exception
+ {
+ dtosForSuccesfullyRegisteredErrorPageWithWildcardErrorCode("5XX", 500);
+ }
+
+ public void dtosForSuccesfullyRegisteredErrorPageWithWildcardErrorCode(String code, long startCode) throws Exception
+ {
+ registerErrorPage("error page 1", asList(code));
+
+ HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+ assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+ RuntimeDTO runtimeDTOWithErrorPage = serviceRuntime.getRuntimeDTO();
+
+ assertEquals(0, runtimeDTOWithErrorPage.failedServletDTOs.length);
+ assertEquals(0, runtimeDTOWithErrorPage.failedErrorPageDTOs.length);
+
+ ServletContextDTO contextDTO = assertDefaultContext(runtimeDTOWithErrorPage);
+ assertEquals(1, contextDTO.errorPageDTOs.length);
+ assertEquals("error page 1", contextDTO.errorPageDTOs[0].name);
+ assertContainsAllHundredFrom(startCode, contextDTO.errorPageDTOs[0].errorCodes);
+ }
+
+ private void assertContainsAllHundredFrom(Long start, long[] errorCodes)
+ {
+ assertEquals(100, errorCodes.length);
+ SortedSet<Long> distinctErrorCodes = new TreeSet<Long>();
+ for (Long code : errorCodes)
+ {
+ distinctErrorCodes.add(code);
+ }
+ assertEquals(100, distinctErrorCodes.size());
+ assertEquals(start, distinctErrorCodes.first());
+ assertEquals(Long.valueOf(start + 99), distinctErrorCodes.last());
+ }
+
+ @Test
public void dtosForSuccesfullyRegisteredListeners() throws Exception
{
// register a servlet context listenere as first listener
@@ -562,7 +648,7 @@
}
};
- m_context.registerService(Servlet.class.getName(), failingServlet, properties);
+ registrations.add(m_context.registerService(Servlet.class.getName(), failingServlet, properties));
awaitServiceRegistration(initLatch);
HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
@@ -575,6 +661,81 @@
}
@Test
+ public void exceptionInServletInitDuringServletRemovalAppearsAsFailure() throws ServletException, InterruptedException
+ {
+ Dictionary<String, ?> properties1 = createDictionary(
+ HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet1",
+ HTTP_WHITEBOARD_SERVLET_NAME, "servlet1");
+
+ final CountDownLatch initLatch1 = new CountDownLatch(1);
+
+ @SuppressWarnings("serial")
+ Servlet failingServlet1 = new TestServlet(initLatch1, null) {
+ @Override
+ public void init() throws ServletException
+ {
+ //fail when initialized the second time
+ if (initLatch1.getCount() == 0)
+ {
+ throw new ServletException();
+ }
+ super.init();
+ }
+ };
+
+ Dictionary<String, ?> properties2 = createDictionary(
+ HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet2",
+ HTTP_WHITEBOARD_SERVLET_NAME, "servlet2");
+
+ final CountDownLatch initLatch2 = new CountDownLatch(1);
+ @SuppressWarnings("serial")
+ Servlet failingServlet2 = new TestServlet(initLatch2, null) {
+ @Override
+ public void init() throws ServletException
+ {
+ //fail when initialized the second time
+ if (initLatch2.getCount() == 0)
+ {
+ throw new ServletException();
+ }
+ super.init();
+ }
+ };
+
+ Dictionary<String, ?> propertiesShadowing = createDictionary(
+ HTTP_WHITEBOARD_SERVLET_PATTERN, asList("/servlet1", "/servlet2"),
+ HTTP_WHITEBOARD_SERVLET_NAME, "servletShadowing",
+ SERVICE_RANKING, Integer.MAX_VALUE);
+
+ CountDownLatch initLatchShadowing = new CountDownLatch(1);
+ Servlet servletShadowing = new TestServlet(initLatchShadowing, null);
+
+ registrations.add(m_context.registerService(Servlet.class.getName(), failingServlet1, properties1));
+ registrations.add(m_context.registerService(Servlet.class.getName(), failingServlet2, properties2));
+ awaitServiceRegistration(initLatch1);
+ awaitServiceRegistration(initLatch2);
+
+ ServiceRegistration<?> shadowingRegistration = m_context.registerService(Servlet.class.getName(), servletShadowing, propertiesShadowing);
+ registrations.add(shadowingRegistration);
+ awaitServiceRegistration(initLatchShadowing);
+
+ HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+ assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+ RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+ assertEquals(2, runtimeDTO.failedServletDTOs.length);
+ assertEquals(FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, runtimeDTO.failedServletDTOs[0].failureReason);
+ assertEquals(FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, runtimeDTO.failedServletDTOs[1].failureReason);
+
+ shadowingRegistration.unregister();
+
+ runtimeDTO = serviceRuntime.getRuntimeDTO();
+ assertEquals(2, runtimeDTO.failedServletDTOs.length);
+ assertEquals(FAILURE_REASON_EXCEPTION_ON_INIT, runtimeDTO.failedServletDTOs[0].failureReason);
+ assertEquals(FAILURE_REASON_EXCEPTION_ON_INIT, runtimeDTO.failedServletDTOs[1].failureReason);
+ }
+
+ @Test
public void exceptionInFilterInitAppearsAsFailure() throws ServletException, InterruptedException
{
Dictionary<String, ?> properties = createDictionary(
@@ -592,7 +753,7 @@
}
};
- m_context.registerService(Filter.class.getName(), failingFilter, properties);
+ registrations.add(m_context.registerService(Filter.class.getName(), failingFilter, properties));
awaitServiceRegistration(initLatch);
HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
@@ -663,7 +824,7 @@
{
Dictionary<String, ?> properties = createDictionary(HTTP_WHITEBOARD_CONTEXT_PATH, "");
- m_context.registerService(ServletContextHelper.class.getName(), mock(ServletContextHelper.class), properties);
+ registrations.add(m_context.registerService(ServletContextHelper.class.getName(), mock(ServletContextHelper.class), properties));
HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
@@ -743,7 +904,7 @@
HTTP_WHITEBOARD_SERVLET_NAME, "servlet",
HTTP_WHITEBOARD_TARGET, "(org.osgi.service.http.port=8282)");
- m_context.registerService(Servlet.class.getName(), new TestServlet(), properties);
+ registrations.add(m_context.registerService(Servlet.class.getName(), new TestServlet(), properties));
awaitServiceRegistration();
HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
@@ -764,7 +925,7 @@
Dictionary<String, ?> properties = createDictionary(HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet");
CountDownLatch initLatch = new CountDownLatch(1);
- m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties);
+ registrations.add(m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties));
awaitServiceRegistration(initLatch);
HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
@@ -781,27 +942,33 @@
// As specified in OSGi Compendium Release 6, Chapter 140.4.1
@Test
- public void patternAndErrorPageSpecifiedInvalidAndAppearsAsFailure() throws InterruptedException
+ public void patternAndErrorPageSpecified() throws InterruptedException
{
Dictionary<String, ?> properties = createDictionary(
HTTP_WHITEBOARD_SERVLET_PATTERN, "/servlet",
HTTP_WHITEBOARD_SERVLET_NAME, "servlet",
HTTP_WHITEBOARD_SERVLET_ERROR_PAGE, asList("400"));
- m_context.registerService(Servlet.class.getName(), new TestServlet(), properties);
+ registrations.add(m_context.registerService(Servlet.class.getName(), new TestServlet(), properties));
awaitServiceRegistration();
HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
- ServletContextDTO defaultContext = assertDefaultContext(serviceRuntime.getRuntimeDTO());
- assertEquals(0, defaultContext.servletDTOs.length);
- assertEquals(0, defaultContext.errorPageDTOs.length);
+ RuntimeDTO runtimeDTO = serviceRuntime.getRuntimeDTO();
+ ServletContextDTO defaultContext = assertDefaultContext(runtimeDTO);
- assertEquals(0, serviceRuntime.getRuntimeDTO().failedServletDTOs.length);
- assertEquals(1, serviceRuntime.getRuntimeDTO().failedErrorPageDTOs.length);
- assertEquals("servlet", serviceRuntime.getRuntimeDTO().failedErrorPageDTOs[0].name);
- assertEquals(FAILURE_REASON_VALIDATION_FAILED, serviceRuntime.getRuntimeDTO().failedErrorPageDTOs[0].failureReason);
+ assertEquals(0, runtimeDTO.failedErrorPageDTOs.length);
+ assertEquals(0, runtimeDTO.failedServletDTOs.length);
+
+ assertEquals(1, defaultContext.servletDTOs.length);
+ assertEquals(1, defaultContext.errorPageDTOs.length);
+
+ assertEquals("servlet", defaultContext.servletDTOs[0].name);
+ assertEquals("servlet", defaultContext.errorPageDTOs[0].name);
+
+ assertArrayEquals(new String[] { "/servlet" }, defaultContext.servletDTOs[0].patterns);
+ assertArrayEquals(new long[] { 400 }, defaultContext.errorPageDTOs[0].errorCodes);
}
// As specified in OSGi Compendium Release 6, Chapter 140.4.1
@@ -828,6 +995,7 @@
CountDownLatch destroyLatch = new CountDownLatch(1);
TestServlet testServlet = new TestServlet(initLatch, destroyLatch);
ServiceRegistration<?> higherRankingServlet = m_context.registerService(Servlet.class.getName(), testServlet, properties);
+ registrations.add(higherRankingServlet);
RuntimeDTO runtimeWithShadowedServlet = serviceRuntime.getRuntimeDTO();
awaitServiceRegistration(initLatch);
@@ -876,6 +1044,7 @@
CountDownLatch destroyLatch = new CountDownLatch(1);
TestServlet testServlet = new TestServlet(initLatch, destroyLatch);
ServiceRegistration<?> higherRankingServlet = m_context.registerService(Servlet.class.getName(), testServlet, properties);
+ registrations.add(higherRankingServlet);
awaitServiceRegistration(initLatch);
RuntimeDTO runtimeWithShadowedErrorPage = serviceRuntime.getRuntimeDTO();
@@ -960,7 +1129,7 @@
{
Dictionary<String, ?> properties = createDictionary(HTTP_WHITEBOARD_LISTENER, "invalid");
- m_context.registerService(ServletRequestListener.class.getName(), mock(ServletRequestListener.class), properties);
+ registrations.add(m_context.registerService(ServletRequestListener.class.getName(), mock(ServletRequestListener.class), properties));
HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
@@ -1004,6 +1173,7 @@
SERVICE_RANKING, Integer.MAX_VALUE);
ServiceRegistration<?> secondContext = m_context.registerService(ServletContextHelper.class.getName(), mock(ServletContextHelper.class), properties);
+ registrations.add(secondContext);
Long secondContextId = (Long) secondContext.getReference().getProperty(Constants.SERVICE_ID);
runtimeDTO = serviceRuntime.getRuntimeDTO();
@@ -1078,7 +1248,7 @@
// Neither pattern nor error page specified
Dictionary<String, ?> properties = createDictionary(HTTP_WHITEBOARD_SERVLET_NAME, "servlet");
- m_context.registerService(Servlet.class.getName(), new TestServlet(), properties);
+ registrations.add(m_context.registerService(Servlet.class.getName(), new TestServlet(), properties));
awaitServiceRegistration();
HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
@@ -1101,7 +1271,7 @@
HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX + "test", "testValue");
CountDownLatch initLatch = new CountDownLatch(1);
- m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties);
+ registrations.add(m_context.registerService(Servlet.class.getName(), new TestServlet(initLatch, null), properties));
awaitServiceRegistration(initLatch);
HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
@@ -1137,6 +1307,37 @@
}
}
+ @Test
+ public void requestInfoDTO() throws Exception
+ {
+ registerServlet("servlet", "/default");
+ registerFilter("filter1", "/default");
+ registerFilter("filter2", "/default");
+
+ HttpServiceRuntime serviceRuntime = (HttpServiceRuntime) getService(HttpServiceRuntime.class.getName());
+ assertNotNull("HttpServiceRuntime unavailable", serviceRuntime);
+
+ ServletContextDTO defaultContext = assertDefaultContext(serviceRuntime.getRuntimeDTO());
+ long defaultContextId = defaultContext.serviceId;
+
+ RequestInfoDTO requestInfoDTO = serviceRuntime.calculateRequestInfoDTO("/default");
+ assertEquals("/default", requestInfoDTO.path);
+ assertEquals(defaultContextId, requestInfoDTO.servletContextId);
+ assertEquals("servlet", requestInfoDTO.servletDTO.name);
+ assertEquals(2, requestInfoDTO.filterDTOs.length);
+ assertEquals("filter1", requestInfoDTO.filterDTOs[0].name);
+ assertEquals("filter2", requestInfoDTO.filterDTOs[1].name);
+ }
+
+ @Test
+ public void serviceEndpointPropertyIsSet()
+ {
+ String[] endpoint = (String[]) m_context.getServiceReference(HttpServiceRuntime.class).getProperty(HTTP_SERVICE_ENDPOINT_ATTRIBUTE);
+ assertEquals(1, endpoint.length);
+ assertTrue(endpoint[0].startsWith("http://"));
+ assertTrue(endpoint[0].endsWith(":8080/"));
+ }
+
private ServletContextDTO assertDefaultContext(RuntimeDTO runtimeDTO)
{
assertTrue(1 < runtimeDTO.servletContextDTOs.length);