FELIX-4894 : Implement cross context shadowing
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1680558 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
index 3ca94be..d4a9b6c 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistry.java
@@ -160,6 +160,8 @@
final ServletHandler old = list.get(0);
old.destroy();
errorCodesMap.put(code, newList);
+ final ErrorRegistrationStatus oldStatus = statusMapping.get(old.getServletInfo());
+ oldStatus.errorCodeMapping.put(code, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
}
}
else
@@ -197,6 +199,8 @@
final ServletHandler old = list.get(0);
old.destroy();
exceptionsMap.put(exception, newList);
+ final ErrorRegistrationStatus oldStatus = statusMapping.get(old.getServletInfo());
+ oldStatus.exceptionMapping.put(exception, DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE);
}
}
else
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterHandlerMapping.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterHandlerMapping.java
index 5c089c1..4e25065 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterHandlerMapping.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/FilterHandlerMapping.java
@@ -121,7 +121,7 @@
return add(mappings);
}
- FilterHandlerMapping add(@Nonnull final Map<Pattern, FilterHandler> mappings)
+ private FilterHandlerMapping add(@Nonnull final Map<Pattern, FilterHandler> mappings)
{
final Map<Pattern, Collection<FilterHandler>> newMappings = getAllMappings();
addMappings(mappings, newMappings);
@@ -146,21 +146,13 @@
return remove(mappings);
}
- FilterHandlerMapping remove(Map<Pattern, FilterHandler> mappings)
+ private FilterHandlerMapping remove(Map<Pattern, FilterHandler> mappings)
{
Map<Pattern, Collection<FilterHandler>> newMappings = getAllMappings();
removeMappings(mappings, newMappings);
return new FilterHandlerMapping(newMappings);
}
- FilterHandlerMapping update(Map<Pattern, FilterHandler> add, Map<Pattern, FilterHandler> remove)
- {
- Map<Pattern, Collection<FilterHandler>> newMappings = getAllMappings();
- removeMappings(remove, newMappings);
- addMappings(add, newMappings);
- return new FilterHandlerMapping(newMappings);
- }
-
private void addMappings(Map<Pattern, FilterHandler> mappings, Map<Pattern, Collection<FilterHandler>> target)
{
for (Map.Entry<Pattern, FilterHandler> mapping : mappings.entrySet())
@@ -211,17 +203,6 @@
}
/**
- * Returns whether this mapping contains the specified handler.
- *
- * @return <code>true</code> if the handlers contains the specified handler,
- * <code>false</code> otherwise
- */
- public boolean contains(FilterHandler handler)
- {
- return mappedHandlers.contains(handler);
- }
-
- /**
* Returns all matching handlers for the given path.
*
* @param path the path that should match, cannot be <code>null</code>.
@@ -233,59 +214,6 @@
}
/**
- * Returns the best matching handler for the given path, according to the rules defined in section 12.1 of Servlet 3.0 specification:
- * <ul>
- * <li>find an exact match of the path of the request to the path of the handler. A successful match selects the handler;</li>
- * <li>recursively try to match the longest path-prefix. This is done by stepping down the path tree a directory at a time, using the
- * '/' character as a path separator. The longest match determines the servlet selected;</li>
- * <li>if the last segment in the URL path contains an extension (e.g. .jsp), the servlet container will try to match a servlet that
- * handles requests for the extension. An extension is defined as the part of the last segment after the last '.' character.</li>
- * </ul>
- *
- * @param path the path that should match, cannot be <code>null</code>.
- * @return the best matching handler for the given path, or <code>null</code> in case no handler matched.
- */
- FilterHandler getBestMatch(String path)
- {
- List<FilterHandler> allMatches = getAllMatches(path, true /* firstOnly */);
- return allMatches.isEmpty() ? null : allMatches.get(0);
- }
-
- /**
- * Returns the (first) handler identified by the given name.
- *
- * @param name the name of the handler to return, can be <code>null</code> in which case this method will return <code>null</code>.
- * @return the element with the given name, or <code>null</code> if not found, or the given argument was <code>null</code>.
- */
- FilterHandler getByName(String name)
- {
- if (name == null)
- {
- return null;
- }
-
- for (FilterHandler element : this.mappedHandlers)
- {
- if (name.equals(element.getName()))
- {
- return element;
- }
- }
-
- return null;
- }
-
- /**
- * Provides information on whether there are elements mapped or not.
- *
- * @return <code>false</code> if there is at least one element mapped, <code>true</code> otherwise.
- */
- boolean isEmpty()
- {
- return this.mappedHandlers.isEmpty();
- }
-
- /**
* Performs the actual matching, yielding a list of either the first or all matching patterns.
*
* @param path the path to match, can be <code>null</code> in which case an empty string is
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
index a5888c7..c71e1c2 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/registry/PerContextHandlerRegistry.java
@@ -96,12 +96,6 @@
@Override
public int compareTo(@Nonnull final PerContextHandlerRegistry other)
{
- // the context of the HttpService is the least element
- if (this.serviceId == 0 ^ other.serviceId == 0)
- {
- return this.serviceId == 0 ? -1 : 1;
- }
-
final int result = Integer.compare(other.path.length(), this.path.length());
if ( result == 0 ) {
if (this.ranking == other.ranking)
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java
index f4cc50f..62dac22 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/registry/ErrorPageRegistryTest.java
@@ -44,6 +44,7 @@
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.runtime.dto.DTOConstants;
import org.osgi.service.http.runtime.dto.ServletContextDTO;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
@@ -67,7 +68,7 @@
holder.failedErrorPageDTOs.clear();
}
- @Test public void testSingleServlet() throws InvalidSyntaxException, ServletException
+ @Test public void testSingleErrorPage() throws InvalidSyntaxException, ServletException
{
final FailedDTOHolder holder = new FailedDTOHolder();
final ServletContextDTO dto = new ServletContextDTO();
@@ -98,12 +99,11 @@
reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
assertNull(dto.resourceDTOs);
assertNull(dto.servletDTOs);
- assertTrue(holder.failedResourceDTOs.isEmpty());
- assertTrue(holder.failedServletDTOs.isEmpty());
assertNotNull(dto.errorPageDTOs);
assertEquals(1, dto.errorPageDTOs.length);
assertEquals(1, dto.errorPageDTOs[0].errorCodes.length);
assertEquals(404, dto.errorPageDTOs[0].errorCodes[0]);
+ assertTrue(holder.failedErrorPageDTOs.isEmpty());
// test error handling
assertNotNull(reg.get(new IOException(), 404));
@@ -125,6 +125,104 @@
assertEmpty(dto, holder);
}
+ @Test public void testSimpleHiding() throws InvalidSyntaxException, ServletException
+ {
+ final FailedDTOHolder holder = new FailedDTOHolder();
+ final ServletContextDTO dto = new ServletContextDTO();
+
+ final Map<ServletInfo, ErrorPageRegistry.ErrorRegistrationStatus> status = reg.getStatusMapping();
+ // empty reg
+ assertEquals(0, status.size());
+ // check DTO
+ reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
+ assertEmpty(dto, holder);
+
+ // register error pages
+ final ServletHandler h1 = createServletHandler(1L, 0, "404", "java.io.IOException");
+ reg.addServlet(h1);
+ final ServletHandler h2 = createServletHandler(2L, 10, "404", "some.other.Exception");
+ reg.addServlet(h2);
+
+ verify(h1.getServlet()).init(Matchers.any(ServletConfig.class));
+ verify(h2.getServlet()).init(Matchers.any(ServletConfig.class));
+
+ // two entries in reg
+ assertEquals(2, status.size());
+ assertNotNull(status.get(h1.getServletInfo()));
+ assertEquals(1, status.get(h1.getServletInfo()).exceptionMapping.size());
+ assertEquals(-1, (int)status.get(h1.getServletInfo()).exceptionMapping.get("java.io.IOException"));
+ assertEquals(1, status.get(h1.getServletInfo()).errorCodeMapping.size());
+ assertEquals(DTOConstants.FAILURE_REASON_SHADOWED_BY_OTHER_SERVICE, (int)status.get(h1.getServletInfo()).errorCodeMapping.get(404L));
+ assertNotNull(status.get(h2.getServletInfo()));
+ assertEquals(1, status.get(h2.getServletInfo()).exceptionMapping.size());
+ assertEquals(-1, (int)status.get(h2.getServletInfo()).exceptionMapping.get("some.other.Exception"));
+ assertEquals(1, status.get(h2.getServletInfo()).errorCodeMapping.size());
+ assertEquals(-1, (int)status.get(h2.getServletInfo()).errorCodeMapping.get(404L));
+
+ // check DTO
+ clear(dto, holder);
+ reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
+ assertNull(dto.resourceDTOs);
+ assertNull(dto.servletDTOs);
+ assertNotNull(dto.errorPageDTOs);
+ assertEquals(2, dto.errorPageDTOs.length);
+ assertEquals(0, dto.errorPageDTOs[0].errorCodes.length);
+ assertEquals(1, dto.errorPageDTOs[1].errorCodes.length);
+ assertEquals(404, dto.errorPageDTOs[1].errorCodes[0]);
+ assertEquals(1, dto.errorPageDTOs[0].exceptions.length);
+ assertEquals(1, dto.errorPageDTOs[1].exceptions.length);
+ assertEquals("java.io.IOException", dto.errorPageDTOs[0].exceptions[0]);
+ assertEquals("some.other.Exception", dto.errorPageDTOs[1].exceptions[0]);
+ assertEquals(1, holder.failedErrorPageDTOs.size());
+ assertEquals(1L, holder.failedErrorPageDTOs.iterator().next().serviceId);
+ assertEquals(1, holder.failedErrorPageDTOs.iterator().next().errorCodes.length);
+ assertEquals(404, holder.failedErrorPageDTOs.iterator().next().errorCodes[0]);
+ assertEquals(0, holder.failedErrorPageDTOs.iterator().next().exceptions.length);
+
+ // remove second page
+ final Servlet s2 = h2.getServlet();
+ reg.removeServlet(h2.getServletInfo(), true);
+ verify(s2).destroy();
+
+ // one entry in reg
+ assertEquals(1, status.size());
+ assertNotNull(status.get(h1.getServletInfo()));
+ assertEquals(1, status.get(h1.getServletInfo()).exceptionMapping.size());
+ assertEquals(-1, (int)status.get(h1.getServletInfo()).exceptionMapping.get("java.io.IOException"));
+ assertEquals(1, status.get(h1.getServletInfo()).errorCodeMapping.size());
+ assertEquals(-1, (int)status.get(h1.getServletInfo()).errorCodeMapping.get(404L));
+
+ // check DTO
+ clear(dto, holder);
+ reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
+ assertNull(dto.resourceDTOs);
+ assertNull(dto.servletDTOs);
+ assertNotNull(dto.errorPageDTOs);
+ assertEquals(1, dto.errorPageDTOs.length);
+ assertEquals(1, dto.errorPageDTOs[0].errorCodes.length);
+ assertEquals(404, dto.errorPageDTOs[0].errorCodes[0]);
+ assertTrue(holder.failedErrorPageDTOs.isEmpty());
+
+ // test error handling
+ assertNotNull(reg.get(new IOException(), 404));
+ assertNotNull(reg.get(new RuntimeException(), 404));
+ assertNotNull(reg.get(new IOException(), 500));
+ assertNotNull(reg.get(new FileNotFoundException(), 500));
+ assertNull(reg.get(new RuntimeException(), 500));
+
+ // remove first page
+ final Servlet s1 = h1.getServlet();
+ reg.removeServlet(h1.getServletInfo(), true);
+ verify(s1).destroy();
+
+ // empty again
+ assertEquals(0, status.size());
+ // check DTO
+ clear(dto, holder);
+ reg.getRuntimeInfo(dto, holder.failedErrorPageDTOs);
+ assertEmpty(dto, holder);
+ }
+
private static ServletInfo createServletInfo(final long id, final int ranking, final String... codes) throws InvalidSyntaxException
{
final BundleContext bCtx = mock(BundleContext.class);