Fix dispatcher handling
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1691505 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
index 9e3d671..2bffcbd 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/Dispatcher.java
@@ -16,40 +16,17 @@
*/
package org.apache.felix.http.base.internal.dispatch;
-import static javax.servlet.RequestDispatcher.FORWARD_CONTEXT_PATH;
-import static javax.servlet.RequestDispatcher.FORWARD_PATH_INFO;
-import static javax.servlet.RequestDispatcher.FORWARD_QUERY_STRING;
-import static javax.servlet.RequestDispatcher.FORWARD_REQUEST_URI;
-import static javax.servlet.RequestDispatcher.FORWARD_SERVLET_PATH;
-import static javax.servlet.RequestDispatcher.INCLUDE_CONTEXT_PATH;
-import static javax.servlet.RequestDispatcher.INCLUDE_PATH_INFO;
-import static javax.servlet.RequestDispatcher.INCLUDE_QUERY_STRING;
-import static javax.servlet.RequestDispatcher.INCLUDE_REQUEST_URI;
-import static javax.servlet.RequestDispatcher.INCLUDE_SERVLET_PATH;
-import static org.apache.felix.http.base.internal.util.UriUtils.concat;
-import static org.apache.felix.http.base.internal.util.UriUtils.decodePath;
-import static org.apache.felix.http.base.internal.util.UriUtils.removeDotSegments;
-
import java.io.IOException;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
-import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;
import org.apache.felix.http.base.internal.context.ExtServletContext;
@@ -63,490 +40,9 @@
import org.apache.felix.http.base.internal.registry.ServletResolution;
import org.apache.felix.http.base.internal.util.UriUtils;
import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.useradmin.Authorization;
-public final class Dispatcher implements RequestDispatcherProvider
+public final class Dispatcher
{
- /**
- * Wrapper implementation for {@link RequestDispatcher}.
- */
- final class RequestDispatcherImpl implements RequestDispatcher
- {
- private final RequestInfo requestInfo;
- private final ServletResolution resolution;
-
- public RequestDispatcherImpl(final ServletResolution resolution, final RequestInfo requestInfo)
- {
- this.resolution = resolution;
- this.requestInfo = requestInfo;
- }
-
- @Override
- public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException
- {
- if (response.isCommitted())
- {
- throw new ServletException("Response has been committed");
- }
- else
- {
- // See section 9.4 of Servlet 3.0 spec
- response.resetBuffer();
- }
-
- try
- {
- ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request,
- this.resolution.handler.getContext(),
- this.requestInfo,
- DispatcherType.FORWARD,
- this.resolution.handler.getContextServiceId(),
- this.resolution.handler.getServletInfo().isAsyncSupported());
- Dispatcher.this.forward(this.resolution, req, (HttpServletResponse) response);
- }
- finally
- {
- // After a forward has taken place, the results should be committed,
- // see section 9.4 of Servlet 3.0 spec...
- if (!request.isAsyncStarted())
- {
- response.flushBuffer();
- response.getWriter().close();
- }
- }
- }
-
- @Override
- public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException
- {
- ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request,
- this.resolution.handler.getContext(),
- this.requestInfo,
- DispatcherType.INCLUDE,
- this.resolution.handler.getContextServiceId(),
- this.resolution.handler.getServletInfo().isAsyncSupported());
- Dispatcher.this.include(this.resolution, req, (HttpServletResponse) response);
- }
- }
-
- final class ServletResponseWrapper extends HttpServletResponseWrapper
- {
-
- private final HttpServletRequest request;
-
- private final AtomicInteger invocationCount = new AtomicInteger();
-
- private final PerContextHandlerRegistry errorRegistry;
-
- private final String servletName;
-
- public ServletResponseWrapper(@Nonnull final HttpServletRequest req,
- @Nonnull final HttpServletResponse res,
- @CheckForNull final String servletName,
- @CheckForNull final PerContextHandlerRegistry errorRegistry)
- {
- super(res);
- this.request = req;
- this.servletName = servletName;
- this.errorRegistry = errorRegistry;
- }
-
- @Override
- public void sendError(int sc) throws IOException
- {
- sendError(sc, null);
- }
-
- @Override
- public void sendError(final int code, final String message) throws IOException
- {
- resetBuffer();
-
- setStatus(code);
-
- boolean invokeSuper = true;
-
- if ( invocationCount.incrementAndGet() == 1 )
- {
- // If we are allowed to have a body
- if (code != SC_NO_CONTENT &&
- code != SC_NOT_MODIFIED &&
- code != SC_PARTIAL_CONTENT &&
- code >= SC_OK)
- {
- final Throwable exception = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
- final ServletHandler errorResolution = (errorRegistry == null ? null :
- errorRegistry.getErrorHandler(code, exception));
-
- if ( errorResolution != null )
- {
- try
- {
- request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, new Integer(code));
- if ( message != null )
- {
- request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
- }
- request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
- if ( this.servletName != null )
- {
- request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, this.servletName);
- }
-
- final String servletPath = null;
- final String pathInfo = request.getRequestURI();
- final String queryString = null; // XXX
-
- final RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString);
-
- final FilterHandler[] filterHandlers = errorRegistry.getFilterHandlers(errorResolution, DispatcherType.ERROR, request.getRequestURI());
-
- // TODO - is async = false correct?
- invokeChain(errorResolution, filterHandlers, new ServletRequestWrapper(request, errorResolution.getContext(), requestInfo, errorResolution.getContextServiceId(), false), this);
-
- invokeSuper = false;
- }
- catch (final ServletException e)
- {
- // ignore
- }
- finally
- {
- request.removeAttribute(RequestDispatcher.ERROR_STATUS_CODE);
- request.removeAttribute(RequestDispatcher.ERROR_MESSAGE);
- request.removeAttribute(RequestDispatcher.ERROR_REQUEST_URI);
- request.removeAttribute(RequestDispatcher.ERROR_SERVLET_NAME);
- request.removeAttribute(RequestDispatcher.ERROR_EXCEPTION);
- request.removeAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
- }
- }
- }
- }
- if ( invokeSuper )
- {
- super.sendError(code, message);
- }
- }
- }
-
- final class ServletRequestWrapper extends HttpServletRequestWrapper
- {
- private final DispatcherType type;
- private final RequestInfo requestInfo;
- private final ExtServletContext servletContext;
- private final long contextId;
- private final boolean asyncSupported;
-
- public ServletRequestWrapper(HttpServletRequest req, ExtServletContext servletContext, RequestInfo requestInfo, final long contextId,
- final boolean asyncSupported)
- {
- this(req, servletContext, requestInfo, null /* type */, contextId, asyncSupported);
- }
-
- public ServletRequestWrapper(HttpServletRequest req, ExtServletContext servletContext, RequestInfo requestInfo,
- DispatcherType type, final Long contextId, final boolean asyncSupported)
- {
- super(req);
-
- this.asyncSupported = asyncSupported;
- this.servletContext = servletContext;
- this.requestInfo = requestInfo;
- this.type = type;
- this.contextId = contextId;
- }
-
- @Override
- public Object getAttribute(String name)
- {
- HttpServletRequest request = (HttpServletRequest) getRequest();
- if (isInclusionDispatcher())
- {
- // The javax.servlet.include.* attributes refer to the information of the *included* request,
- // meaning that the request information comes from the *original* request...
- if (INCLUDE_REQUEST_URI.equals(name))
- {
- return concat(request.getContextPath(), this.requestInfo.requestURI);
- }
- else if (INCLUDE_CONTEXT_PATH.equals(name))
- {
- return request.getContextPath();
- }
- else if (INCLUDE_SERVLET_PATH.equals(name))
- {
- return this.requestInfo.servletPath;
- }
- else if (INCLUDE_PATH_INFO.equals(name))
- {
- return this.requestInfo.pathInfo;
- }
- else if (INCLUDE_QUERY_STRING.equals(name))
- {
- return this.requestInfo.queryString;
- }
- }
- else if (isForwardingDispatcher())
- {
- // The javax.servlet.forward.* attributes refer to the information of the *original* request,
- // meaning that the request information comes from the *forwarded* request...
- if (FORWARD_REQUEST_URI.equals(name))
- {
- return super.getRequestURI();
- }
- else if (FORWARD_CONTEXT_PATH.equals(name))
- {
- return request.getContextPath();
- }
- else if (FORWARD_SERVLET_PATH.equals(name))
- {
- return super.getServletPath();
- }
- else if (FORWARD_PATH_INFO.equals(name))
- {
- return super.getPathInfo();
- }
- else if (FORWARD_QUERY_STRING.equals(name))
- {
- return super.getQueryString();
- }
- }
- return super.getAttribute(name);
- }
-
- @Override
- public String getAuthType()
- {
- String authType = (String) getAttribute(HttpContext.AUTHENTICATION_TYPE);
- if (authType == null)
- {
- authType = super.getAuthType();
- }
- return authType;
- }
-
- @Override
- public String getContextPath()
- {
- return this.getServletContext().getContextPath();
- }
-
- @Override
- public DispatcherType getDispatcherType()
- {
- return (this.type == null) ? super.getDispatcherType() : this.type;
- }
-
- @Override
- public String getPathInfo()
- {
- if ( this.isInclusionDispatcher() )
- {
- return super.getPathInfo();
- }
- return this.requestInfo.pathInfo;
- }
-
- @Override
- @SuppressWarnings("deprecation")
- public String getPathTranslated()
- {
- final String info = getPathInfo();
- return (null == info) ? null : getRealPath(info);
- }
-
- @Override
- public String getRemoteUser()
- {
- String remoteUser = (String) getAttribute(HttpContext.REMOTE_USER);
- if (remoteUser != null)
- {
- return remoteUser;
- }
-
- return super.getRemoteUser();
- }
-
- @Override
- public RequestDispatcher getRequestDispatcher(String path)
- {
- // See section 9.1 of Servlet 3.0 specification...
- if (path == null)
- {
- return null;
- }
- // Handle relative paths, see Servlet 3.0 spec, section 9.1 last paragraph.
- boolean relPath = !path.startsWith("/") && !"".equals(path);
- if (relPath)
- {
- path = concat(getServletPath(), path);
- }
- return Dispatcher.this.getRequestDispatcher(this.contextId, path);
- }
-
- @Override
- public String getRequestURI()
- {
- if ( isInclusionDispatcher() )
- {
- return super.getRequestURI();
- }
- return concat(getContextPath(), this.requestInfo.requestURI);
- }
-
- @Override
- public ServletContext getServletContext()
- {
- return new ServletContextWrapper(this.contextId, this.servletContext, Dispatcher.this);
- }
-
- @Override
- public String getServletPath()
- {
- if ( isInclusionDispatcher() )
- {
- return super.getServletPath();
- }
- return this.requestInfo.servletPath;
- }
-
- @Override
- public HttpSession getSession() {
- return this.getSession(true);
- }
-
- @Override
- public HttpSession getSession(boolean create)
- {
- // FELIX-2797: wrap the original HttpSession to provide access to the correct ServletContext...
- final HttpSession session = super.getSession(create);
- if (session == null)
- {
- return null;
- }
- // check if internal session is available
- if ( !create && !HttpSessionWrapper.hasSession(this.contextId, session) )
- {
- return null;
- }
- return new HttpSessionWrapper(this.contextId, session, this.servletContext, false);
- }
-
- @Override
- public boolean isUserInRole(String role)
- {
- Authorization authorization = (Authorization) getAttribute(HttpContext.AUTHORIZATION);
- if (authorization != null)
- {
- return authorization.hasRole(role);
- }
-
- return super.isUserInRole(role);
- }
-
- @Override
- public void setAttribute(final String name, final Object value)
- {
- if ( value == null )
- {
- this.removeAttribute(name);
- }
- final Object oldValue = this.getAttribute(name);
- super.setAttribute(name, value);
- if ( this.servletContext.getServletRequestAttributeListener() != null )
- {
- if ( oldValue == null )
- {
- this.servletContext.getServletRequestAttributeListener().attributeAdded(new ServletRequestAttributeEvent(this.servletContext, this, name, value));
- }
- else
- {
- this.servletContext.getServletRequestAttributeListener().attributeReplaced(new ServletRequestAttributeEvent(this.servletContext, this, name, oldValue));
- }
- }
- }
-
- @Override
- public void removeAttribute(final String name) {
- final Object oldValue = this.getAttribute(name);
- if ( oldValue != null )
- {
- super.removeAttribute(name);
- if ( this.servletContext.getServletRequestAttributeListener() != null )
- {
- this.servletContext.getServletRequestAttributeListener().attributeRemoved(new ServletRequestAttributeEvent(this.servletContext, this, name, oldValue));
- }
- }
- }
-
- @Override
- public String toString()
- {
- return getClass().getSimpleName() + "->" + super.getRequest();
- }
-
- private boolean isForwardingDispatcher()
- {
- return (DispatcherType.FORWARD == this.type) && (this.requestInfo != null);
- }
-
- private boolean isInclusionDispatcher()
- {
- return (DispatcherType.INCLUDE == this.type) && (this.requestInfo != null);
- }
-
- @Override
- public AsyncContext startAsync() throws IllegalStateException
- {
- if ( !this.asyncSupported )
- {
- throw new IllegalStateException();
- }
- return super.startAsync();
- }
-
- @Override
- public AsyncContext startAsync(final ServletRequest servletRequest,
- final ServletResponse servletResponse) throws IllegalStateException
- {
- if ( !this.asyncSupported )
- {
- throw new IllegalStateException();
- }
- return super.startAsync(servletRequest, servletResponse);
- }
-
- @Override
- public boolean isAsyncSupported()
- {
- return this.asyncSupported;
- }
- }
-
- private static class RequestInfo
- {
- final String servletPath;
- final String pathInfo;
- final String queryString;
- final String requestURI;
-
- public RequestInfo(String servletPath, String pathInfo, String queryString)
- {
- this.servletPath = servletPath;
- this.pathInfo = pathInfo;
- this.queryString = queryString;
- this.requestURI = UriUtils.compactPath(concat(servletPath, pathInfo));
- }
-
- @Override
- public String toString()
- {
- StringBuilder sb = new StringBuilder("RequestInfo[servletPath =");
- sb.append(this.servletPath).append(", pathInfo = ").append(this.pathInfo);
- sb.append(", queryString = ").append(this.queryString).append("]");
- return sb.toString();
- }
- }
-
private final HandlerRegistry handlerRegistry;
private WhiteboardManager whiteboardManager;
@@ -608,7 +104,7 @@
final ExtServletContext servletContext = pr.handler.getContext();
final RequestInfo requestInfo = new RequestInfo(pr.servletPath, pr.pathInfo, null);
- final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo,
+ final HttpServletRequest wrappedRequest = new ServletRequestWrapper(req, servletContext, requestInfo, null,
pr.handler.getContextServiceId(),
pr.handler.getServletInfo().isAsyncSupported());
final FilterHandler[] filterHandlers = this.handlerRegistry.getFilters(pr, req.getDispatcherType(), pr.requestURI);
@@ -638,54 +134,14 @@
}
}
- @Override
- public RequestDispatcher getNamedDispatcher(final long contextId, final String name)
- {
- final ServletResolution resolution = this.handlerRegistry.resolveServletByName(contextId, name);
- return resolution != null ? new RequestDispatcherImpl(resolution, null) : null;
- }
-
- @Override
- public RequestDispatcher getRequestDispatcher(final long contextId, String path)
- {
- // See section 9.1 of Servlet 3.x specification...
- if (path == null || (!path.startsWith("/") && !"".equals(path)))
- {
- return null;
- }
-
- String query = null;
- int q = 0;
- if ((q = path.indexOf('?')) > 0)
- {
- query = path.substring(q + 1);
- path = path.substring(0, q);
- }
- // TODO remove path parameters...
- String requestURI = decodePath(removeDotSegments(path));
- if ( requestURI == null )
- {
- requestURI = "";
- }
-
- final PathResolution pr = this.handlerRegistry.resolveServlet(requestURI);
- if (pr == null)
- {
- return null;
- }
-
- final RequestInfo requestInfo = new RequestInfo(pr.servletPath, pr.pathInfo, query);
- return new RequestDispatcherImpl(pr, requestInfo);
- }
-
/**
* @param servletHandler the servlet that should handle the forward request;
* @param request the {@link HttpServletRequest};
* @param response the {@link HttpServletResponse};
*/
- void forward(final ServletResolution resolution, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ public void forward(final ServletResolution resolution, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
- final String requestURI = getRequestURI(request);
+ final String requestURI = UriUtils.relativePath(request.getContextPath(), request.getRequestURI());
final FilterHandler[] filterHandlers = this.handlerRegistry.getFilters(resolution, DispatcherType.FORWARD, requestURI);
invokeChain(resolution.handler, filterHandlers, request, response);
@@ -696,19 +152,14 @@
* @param request the {@link HttpServletRequest};
* @param response the {@link HttpServletResponse};
*/
- void include(final ServletResolution resolution, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ public void include(final ServletResolution resolution, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
- final String requestURI = getRequestURI(request);
+ final String requestURI = UriUtils.relativePath(request.getContextPath(), request.getRequestURI());
final FilterHandler[] filterHandlers = this.handlerRegistry.getFilters(resolution, DispatcherType.INCLUDE, requestURI);
invokeChain(resolution.handler, filterHandlers, request, response);
}
- private String getRequestURI(final HttpServletRequest req)
- {
- return UriUtils.relativePath(req.getContextPath(), req.getRequestURI());
- }
-
private void invokeChain(final ServletHandler servletHandler,
final FilterHandler[] filterHandlers,
final HttpServletRequest request,
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
new file mode 100644
index 0000000..9a97cef
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherImpl.java
@@ -0,0 +1,104 @@
+/*
+ * 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.dispatch;
+
+import java.io.IOException;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.FilterChain;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.http.base.internal.handler.FilterHandler;
+import org.apache.felix.http.base.internal.registry.ServletResolution;
+import org.apache.felix.http.base.internal.util.UriUtils;
+
+/**
+ * Wrapper implementation for {@link RequestDispatcher}.
+ */
+public final class RequestDispatcherImpl implements RequestDispatcher
+{
+ private final RequestInfo requestInfo;
+ private final ServletResolution resolution;
+
+ public RequestDispatcherImpl(final ServletResolution resolution,
+ final RequestInfo requestInfo)
+ {
+ System.out.println("New dispatcher with " + requestInfo);
+ this.resolution = resolution;
+ this.requestInfo = requestInfo;
+ }
+
+ @Override
+ public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException
+ {
+ if (response.isCommitted())
+ {
+ throw new ServletException("Response has been committed");
+ }
+ else
+ {
+ // See section 9.4 of Servlet 3.0 spec
+ response.resetBuffer();
+ }
+
+ try
+ {
+ final ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request,
+ this.resolution.handler.getContext(),
+ this.requestInfo,
+ DispatcherType.FORWARD,
+ this.resolution.handler.getContextServiceId(),
+ this.resolution.handler.getServletInfo().isAsyncSupported());
+ final String requestURI = UriUtils.relativePath(req.getContextPath(), req.getRequestURI());
+ final FilterHandler[] filterHandlers = this.resolution.handlerRegistry.getFilterHandlers(this.resolution.handler, DispatcherType.FORWARD, requestURI);
+
+ final FilterChain filterChain = new InvocationChain(resolution.handler, filterHandlers);
+ filterChain.doFilter( req, (HttpServletResponse) response);
+ }
+ finally
+ {
+ // After a forward has taken place, the results should be committed,
+ // see section 9.4 of Servlet 3.0 spec...
+ if (!request.isAsyncStarted())
+ {
+ response.flushBuffer();
+ response.getWriter().close();
+ }
+ }
+ }
+
+ @Override
+ public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException
+ {
+ final ServletRequestWrapper req = new ServletRequestWrapper((HttpServletRequest) request,
+ this.resolution.handler.getContext(),
+ this.requestInfo,
+ DispatcherType.INCLUDE,
+ this.resolution.handler.getContextServiceId(),
+ this.resolution.handler.getServletInfo().isAsyncSupported());
+ final String requestURI = UriUtils.relativePath(req.getContextPath(), req.getRequestURI());
+ final FilterHandler[] filterHandlers = this.resolution.handlerRegistry.getFilterHandlers(this.resolution.handler, DispatcherType.INCLUDE, requestURI);
+
+ final FilterChain filterChain = new InvocationChain(resolution.handler, filterHandlers);
+ filterChain.doFilter( req, (HttpServletResponse) response);
+ }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java
deleted file mode 100644
index 45fab9f..0000000
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestDispatcherProvider.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.dispatch;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
-
-public interface RequestDispatcherProvider
-{
- /**
- * @see ServletContext#getNamedDispatcher(String)
- */
- RequestDispatcher getNamedDispatcher(long contextId, String name);
-
- /**
- * @see ServletContext#getRequestDispatcher(String)
- */
- RequestDispatcher getRequestDispatcher(long contextId, String path);
-}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
new file mode 100644
index 0000000..c7a082f
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/RequestInfo.java
@@ -0,0 +1,46 @@
+/*
+ * 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.dispatch;
+
+import static org.apache.felix.http.base.internal.util.UriUtils.concat;
+
+import org.apache.felix.http.base.internal.util.UriUtils;
+
+public final class RequestInfo
+{
+ final String servletPath;
+ final String pathInfo;
+ final String queryString;
+ final String requestURI;
+
+ public RequestInfo(String servletPath, String pathInfo, String queryString)
+ {
+ this.servletPath = servletPath;
+ this.pathInfo = pathInfo;
+ this.queryString = queryString;
+ this.requestURI = UriUtils.compactPath(concat(servletPath, pathInfo));
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder("RequestInfo[servletPath =");
+ sb.append(this.servletPath).append(", pathInfo = ").append(this.pathInfo);
+ sb.append(", queryString = ").append(this.queryString).append("]");
+ return sb.toString();
+ }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java
deleted file mode 100644
index 882e102..0000000
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletContextWrapper.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.dispatch;
-
-import javax.servlet.RequestDispatcher;
-
-import org.apache.felix.http.base.internal.context.ExtServletContext;
-import org.apache.felix.http.base.internal.context.ExtServletContextWrapper;
-
-class ServletContextWrapper extends ExtServletContextWrapper
-{
- private final RequestDispatcherProvider provider;
-
- private final long contextId;
-
- /**
- * Creates a new {@link ServletContextWrapper} instance.
- */
- public ServletContextWrapper(final long contextId, final ExtServletContext delegate, final RequestDispatcherProvider provider)
- {
- super(delegate);
-
- this.provider = provider;
- this.contextId = contextId;
- }
-
- @Override
- public RequestDispatcher getNamedDispatcher(String name)
- {
- if (name == null)
- {
- return null;
- }
-
- RequestDispatcher dispatcher = this.provider.getNamedDispatcher(contextId, name);
- return dispatcher != null ? dispatcher : super.getNamedDispatcher(name);
- }
-
- @Override
- public RequestDispatcher getRequestDispatcher(String path)
- {
- // See section 9.1 of Servlet 3.x specification...
- if (path == null || (!path.startsWith("/") && !"".equals(path)))
- {
- return null;
- }
-
- RequestDispatcher dispatcher = this.provider.getRequestDispatcher(contextId, path);
- return dispatcher != null ? dispatcher : super.getRequestDispatcher(path);
- }
-}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
new file mode 100644
index 0000000..d2d2519
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
@@ -0,0 +1,335 @@
+/*
+ * 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.dispatch;
+
+import static javax.servlet.RequestDispatcher.FORWARD_CONTEXT_PATH;
+import static javax.servlet.RequestDispatcher.FORWARD_PATH_INFO;
+import static javax.servlet.RequestDispatcher.FORWARD_QUERY_STRING;
+import static javax.servlet.RequestDispatcher.FORWARD_REQUEST_URI;
+import static javax.servlet.RequestDispatcher.FORWARD_SERVLET_PATH;
+import static javax.servlet.RequestDispatcher.INCLUDE_CONTEXT_PATH;
+import static javax.servlet.RequestDispatcher.INCLUDE_PATH_INFO;
+import static javax.servlet.RequestDispatcher.INCLUDE_QUERY_STRING;
+import static javax.servlet.RequestDispatcher.INCLUDE_REQUEST_URI;
+import static javax.servlet.RequestDispatcher.INCLUDE_SERVLET_PATH;
+import static org.apache.felix.http.base.internal.util.UriUtils.concat;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpSession;
+
+import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.handler.HttpSessionWrapper;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.useradmin.Authorization;
+
+final class ServletRequestWrapper extends HttpServletRequestWrapper
+{
+ private final DispatcherType type;
+ private final RequestInfo requestInfo;
+ private final ExtServletContext servletContext;
+ private final long contextId;
+ private final boolean asyncSupported;
+
+ public ServletRequestWrapper(HttpServletRequest req,
+ ExtServletContext servletContext,
+ RequestInfo requestInfo,
+ DispatcherType type,
+ final Long contextId,
+ final boolean asyncSupported)
+ {
+ super(req);
+
+ this.asyncSupported = asyncSupported;
+ this.servletContext = servletContext;
+ this.requestInfo = requestInfo;
+ this.type = type;
+ this.contextId = contextId;
+ }
+
+ @Override
+ public Object getAttribute(String name)
+ {
+ HttpServletRequest request = (HttpServletRequest) getRequest();
+ if (isInclusionDispatcher())
+ {
+ // The javax.servlet.include.* attributes refer to the information of the *included* request,
+ // meaning that the request information comes from the *original* request...
+ if (INCLUDE_REQUEST_URI.equals(name))
+ {
+ return concat(request.getContextPath(), this.requestInfo.requestURI);
+ }
+ else if (INCLUDE_CONTEXT_PATH.equals(name))
+ {
+ return request.getContextPath();
+ }
+ else if (INCLUDE_SERVLET_PATH.equals(name))
+ {
+ return this.requestInfo.servletPath;
+ }
+ else if (INCLUDE_PATH_INFO.equals(name))
+ {
+ return this.requestInfo.pathInfo;
+ }
+ else if (INCLUDE_QUERY_STRING.equals(name))
+ {
+ return this.requestInfo.queryString;
+ }
+ }
+ else if (isForwardingDispatcher())
+ {
+ // The javax.servlet.forward.* attributes refer to the information of the *original* request,
+ // meaning that the request information comes from the *forwarded* request...
+ if (FORWARD_REQUEST_URI.equals(name))
+ {
+ return super.getRequestURI();
+ }
+ else if (FORWARD_CONTEXT_PATH.equals(name))
+ {
+ return request.getContextPath();
+ }
+ else if (FORWARD_SERVLET_PATH.equals(name))
+ {
+ return super.getServletPath();
+ }
+ else if (FORWARD_PATH_INFO.equals(name))
+ {
+ return super.getPathInfo();
+ }
+ else if (FORWARD_QUERY_STRING.equals(name))
+ {
+ return super.getQueryString();
+ }
+ }
+ return super.getAttribute(name);
+ }
+
+ @Override
+ public String getAuthType()
+ {
+ String authType = (String) getAttribute(HttpContext.AUTHENTICATION_TYPE);
+ if (authType == null)
+ {
+ authType = super.getAuthType();
+ }
+ return authType;
+ }
+
+ @Override
+ public String getContextPath()
+ {
+ return this.getServletContext().getContextPath();
+ }
+
+ @Override
+ public DispatcherType getDispatcherType()
+ {
+ return (this.type == null) ? super.getDispatcherType() : this.type;
+ }
+
+ @Override
+ public String getPathInfo()
+ {
+ if ( this.isInclusionDispatcher() )
+ {
+ return super.getPathInfo();
+ }
+ return this.requestInfo.pathInfo;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public String getPathTranslated()
+ {
+ final String info = getPathInfo();
+ return (null == info) ? null : getRealPath(info);
+ }
+
+ @Override
+ public String getRemoteUser()
+ {
+ String remoteUser = (String) getAttribute(HttpContext.REMOTE_USER);
+ if (remoteUser != null)
+ {
+ return remoteUser;
+ }
+
+ return super.getRemoteUser();
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path)
+ {
+ // See section 9.1 of Servlet 3.0 specification...
+ if (path == null)
+ {
+ return null;
+ }
+ // Handle relative paths, see Servlet 3.0 spec, section 9.1 last paragraph.
+ boolean relPath = !path.startsWith("/") && !"".equals(path);
+ if (relPath)
+ {
+ path = concat(getServletPath(), path);
+ }
+ return this.servletContext.getRequestDispatcher(path);
+ }
+
+ @Override
+ public String getRequestURI()
+ {
+ if ( isInclusionDispatcher() )
+ {
+ return super.getRequestURI();
+ }
+ return concat(getContextPath(), this.requestInfo.requestURI);
+ }
+
+ @Override
+ public ServletContext getServletContext()
+ {
+ return this.servletContext;
+ }
+
+ @Override
+ public String getServletPath()
+ {
+ if ( isInclusionDispatcher() )
+ {
+ return super.getServletPath();
+ }
+ return this.requestInfo.servletPath;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return this.getSession(true);
+ }
+
+ @Override
+ public HttpSession getSession(boolean create)
+ {
+ // FELIX-2797: wrap the original HttpSession to provide access to the correct ServletContext...
+ final HttpSession session = super.getSession(create);
+ if (session == null)
+ {
+ return null;
+ }
+ // check if internal session is available
+ if ( !create && !HttpSessionWrapper.hasSession(this.contextId, session) )
+ {
+ return null;
+ }
+ return new HttpSessionWrapper(this.contextId, session, this.servletContext, false);
+ }
+
+ @Override
+ public boolean isUserInRole(String role)
+ {
+ Authorization authorization = (Authorization) getAttribute(HttpContext.AUTHORIZATION);
+ if (authorization != null)
+ {
+ return authorization.hasRole(role);
+ }
+
+ return super.isUserInRole(role);
+ }
+
+ @Override
+ public void setAttribute(final String name, final Object value)
+ {
+ if ( value == null )
+ {
+ this.removeAttribute(name);
+ }
+ final Object oldValue = this.getAttribute(name);
+ super.setAttribute(name, value);
+ if ( this.servletContext.getServletRequestAttributeListener() != null )
+ {
+ if ( oldValue == null )
+ {
+ this.servletContext.getServletRequestAttributeListener().attributeAdded(new ServletRequestAttributeEvent(this.servletContext, this, name, value));
+ }
+ else
+ {
+ this.servletContext.getServletRequestAttributeListener().attributeReplaced(new ServletRequestAttributeEvent(this.servletContext, this, name, oldValue));
+ }
+ }
+ }
+
+ @Override
+ public void removeAttribute(final String name) {
+ final Object oldValue = this.getAttribute(name);
+ if ( oldValue != null )
+ {
+ super.removeAttribute(name);
+ if ( this.servletContext.getServletRequestAttributeListener() != null )
+ {
+ this.servletContext.getServletRequestAttributeListener().attributeRemoved(new ServletRequestAttributeEvent(this.servletContext, this, name, oldValue));
+ }
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getSimpleName() + "->" + super.getRequest();
+ }
+
+ private boolean isForwardingDispatcher()
+ {
+ return (DispatcherType.FORWARD == this.type) && (this.requestInfo != null);
+ }
+
+ private boolean isInclusionDispatcher()
+ {
+ return (DispatcherType.INCLUDE == this.type) && (this.requestInfo != null);
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException
+ {
+ if ( !this.asyncSupported )
+ {
+ throw new IllegalStateException();
+ }
+ return super.startAsync();
+ }
+
+ @Override
+ public AsyncContext startAsync(final ServletRequest servletRequest,
+ final ServletResponse servletResponse) throws IllegalStateException
+ {
+ if ( !this.asyncSupported )
+ {
+ throw new IllegalStateException();
+ }
+ return super.startAsync(servletRequest, servletResponse);
+ }
+
+ @Override
+ public boolean isAsyncSupported()
+ {
+ return this.asyncSupported;
+ }
+}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
new file mode 100644
index 0000000..e12764e
--- /dev/null
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletResponseWrapper.java
@@ -0,0 +1,136 @@
+/*
+ * 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.dispatch;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.servlet.DispatcherType;
+import javax.servlet.FilterChain;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import org.apache.felix.http.base.internal.handler.FilterHandler;
+import org.apache.felix.http.base.internal.handler.ServletHandler;
+import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
+
+final class ServletResponseWrapper extends HttpServletResponseWrapper
+{
+
+ private final HttpServletRequest request;
+
+ private final AtomicInteger invocationCount = new AtomicInteger();
+
+ private final PerContextHandlerRegistry errorRegistry;
+
+ private final String servletName;
+
+ public ServletResponseWrapper(@Nonnull final HttpServletRequest req,
+ @Nonnull final HttpServletResponse res,
+ @CheckForNull final String servletName,
+ @CheckForNull final PerContextHandlerRegistry errorRegistry)
+ {
+ super(res);
+ this.request = req;
+ this.servletName = servletName;
+ this.errorRegistry = errorRegistry;
+ }
+
+ @Override
+ public void sendError(int sc) throws IOException
+ {
+ sendError(sc, null);
+ }
+
+ @Override
+ public void sendError(final int code, final String message) throws IOException
+ {
+ resetBuffer();
+
+ setStatus(code);
+
+ boolean invokeSuper = true;
+
+ if ( invocationCount.incrementAndGet() == 1 )
+ {
+ // If we are allowed to have a body
+ if (code != SC_NO_CONTENT &&
+ code != SC_NOT_MODIFIED &&
+ code != SC_PARTIAL_CONTENT &&
+ code >= SC_OK)
+ {
+ final Throwable exception = (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
+ final ServletHandler errorResolution = (errorRegistry == null ? null :
+ errorRegistry.getErrorHandler(code, exception));
+
+ if ( errorResolution != null )
+ {
+ try
+ {
+ request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, new Integer(code));
+ if ( message != null )
+ {
+ request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message);
+ }
+ request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI());
+ if ( this.servletName != null )
+ {
+ request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, this.servletName);
+ }
+
+ final String servletPath = null;
+ final String pathInfo = request.getRequestURI();
+ final String queryString = null; // XXX
+
+ final RequestInfo requestInfo = new RequestInfo(servletPath, pathInfo, queryString);
+
+ final FilterHandler[] filterHandlers = errorRegistry.getFilterHandlers(errorResolution, DispatcherType.ERROR, request.getRequestURI());
+
+ // TODO - is async = false correct?
+ final ServletRequestWrapper reqWrapper = new ServletRequestWrapper(request, errorResolution.getContext(), requestInfo, null, errorResolution.getContextServiceId(), false);
+ final FilterChain filterChain = new InvocationChain(errorResolution, filterHandlers);
+ filterChain.doFilter(reqWrapper, this);
+
+ invokeSuper = false;
+ }
+ catch (final ServletException e)
+ {
+ // ignore
+ }
+ finally
+ {
+ request.removeAttribute(RequestDispatcher.ERROR_STATUS_CODE);
+ request.removeAttribute(RequestDispatcher.ERROR_MESSAGE);
+ request.removeAttribute(RequestDispatcher.ERROR_REQUEST_URI);
+ request.removeAttribute(RequestDispatcher.ERROR_SERVLET_NAME);
+ request.removeAttribute(RequestDispatcher.ERROR_EXCEPTION);
+ request.removeAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
+ }
+ }
+ }
+ }
+ if ( invokeSuper )
+ {
+ super.sendError(code, message);
+ }
+ }
+}
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 b2734d5..86ebf7a 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
@@ -75,7 +75,13 @@
}
this.bundle = bundle;
- this.contextManager = new ServletContextManager(this.bundle, context, servletAttributeListener, sharedContextAttributes, reqListener, reqAttrListener);
+ this.contextManager = new ServletContextManager(this.bundle,
+ context,
+ servletAttributeListener,
+ sharedContextAttributes,
+ reqListener,
+ reqAttrListener,
+ sharedHttpService.getHandlerRegistry().getRegistry(HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID));
this.sharedHttpService = sharedHttpService;
}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java
index 1871bcf..464f3cc 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextImpl.java
@@ -16,6 +16,9 @@
*/
package org.apache.felix.http.base.internal.service;
+import static org.apache.felix.http.base.internal.util.UriUtils.decodePath;
+import static org.apache.felix.http.base.internal.util.UriUtils.removeDotSegments;
+
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -47,7 +50,14 @@
import javax.servlet.http.HttpSessionListener;
import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.dispatch.RequestDispatcherImpl;
+import org.apache.felix.http.base.internal.dispatch.RequestInfo;
+import org.apache.felix.http.base.internal.handler.ServletHandler;
import org.apache.felix.http.base.internal.logger.SystemLogger;
+import org.apache.felix.http.base.internal.registry.HandlerRegistry;
+import org.apache.felix.http.base.internal.registry.PathResolution;
+import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
+import org.apache.felix.http.base.internal.registry.ServletResolution;
import org.apache.felix.http.base.internal.util.MimeTypes;
import org.osgi.framework.Bundle;
import org.osgi.service.http.HttpContext;
@@ -64,7 +74,8 @@
private final HttpSessionListener httpSessionListener;
private final ServletRequestListener servletRequestListener;
private final ServletRequestAttributeListener servletRequestAttributeListener;
-
+ private final PerContextHandlerRegistry handlerRegistry;
+
public ServletContextImpl(final Bundle bundle,
final ServletContext context,
final HttpContext httpContext,
@@ -73,7 +84,8 @@
final HttpSessionAttributeListener httpSessionAttributeListener,
final HttpSessionListener httpSessionListener,
final ServletRequestListener servletRequestListener,
- final ServletRequestAttributeListener servletRequestAttributeListener)
+ final ServletRequestAttributeListener servletRequestAttributeListener,
+ final PerContextHandlerRegistry registry)
{
this.bundle = bundle;
this.context = context;
@@ -84,6 +96,7 @@
this.httpSessionListener = httpSessionListener;
this.servletRequestAttributeListener = servletRequestAttributeListener;
this.servletRequestListener = servletRequestListener;
+ this.handlerRegistry = registry;
}
@Override
@@ -278,12 +291,6 @@
}
@Override
- public RequestDispatcher getNamedDispatcher(String name)
- {
- return this.context.getNamedDispatcher(name);
- }
-
- @Override
public String getRealPath(String name)
{
URL url = getResource(name);
@@ -295,12 +302,6 @@
}
@Override
- public RequestDispatcher getRequestDispatcher(String uri)
- {
- return this.context.getRequestDispatcher(uri);
- }
-
- @Override
public URL getResource(String path)
{
return this.httpContext.getResource(normalizeResourcePath(path));
@@ -501,6 +502,72 @@
this.context.setSessionTrackingModes(modes);
}
+ @Override
+ public RequestDispatcher getNamedDispatcher(final String name)
+ {
+ if (name == null)
+ {
+ return null;
+ }
+
+ final RequestDispatcher dispatcher;
+ final ServletHandler servletHandler = this.handlerRegistry.resolveServletByName(name);
+ if ( servletHandler != null )
+ {
+ final ServletResolution resolution = new ServletResolution();
+ resolution.handler = servletHandler;
+ resolution.handlerRegistry = this.handlerRegistry;
+ // TODO - what is the path of a named servlet?
+ final RequestInfo requestInfo = new RequestInfo("", null, null);
+ dispatcher = new RequestDispatcherImpl(resolution, requestInfo);
+ }
+ else
+ {
+ dispatcher = null;
+ }
+ return dispatcher;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path)
+ {
+ // See section 9.1 of Servlet 3.x specification...
+ if (path == null || (!path.startsWith("/") && !"".equals(path)))
+ {
+ return null;
+ }
+
+ String query = null;
+ int q = 0;
+ if ((q = path.indexOf('?')) > 0)
+ {
+ query = path.substring(q + 1);
+ path = path.substring(0, q);
+ }
+ // TODO remove path parameters...
+ String requestURI = decodePath(removeDotSegments(path));
+ if ( requestURI == null )
+ {
+ requestURI = "";
+ }
+
+ final RequestDispatcher dispatcher;
+ final PathResolution pathResolution = this.handlerRegistry.resolve(requestURI);
+ if ( pathResolution != null )
+ {
+ final ServletResolution resolution = new ServletResolution();
+ resolution.handler = pathResolution.handler;
+ resolution.handlerRegistry = this.handlerRegistry;
+ final RequestInfo requestInfo = new RequestInfo(pathResolution.servletPath, pathResolution.pathInfo, query);
+ dispatcher = new RequestDispatcherImpl(resolution, requestInfo);
+ }
+ else
+ {
+ dispatcher = null;
+ }
+ return dispatcher;
+ }
+
private String normalizePath(String path)
{
if (path == null)
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextManager.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextManager.java
index bfa50f0..ecb11b9 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextManager.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/ServletContextManager.java
@@ -25,6 +25,8 @@
import javax.servlet.ServletRequestListener;
import org.apache.felix.http.base.internal.context.ExtServletContext;
+import org.apache.felix.http.base.internal.registry.HandlerRegistry;
+import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
import org.osgi.framework.Bundle;
import org.osgi.service.http.HttpContext;
@@ -37,6 +39,7 @@
private final boolean sharedAttributes;
private final ServletRequestListener servletRequestListener;
private final ServletRequestAttributeListener servletRequestAttributeListener;
+ private final PerContextHandlerRegistry handlerRegistry;
public ServletContextManager(
final Bundle bundle,
@@ -44,7 +47,8 @@
final ServletContextAttributeListener attributeListener,
final boolean sharedAttributes,
final ServletRequestListener servletRequestListener,
- final ServletRequestAttributeListener servletRequestAttributeListener)
+ final ServletRequestAttributeListener servletRequestAttributeListener,
+ final PerContextHandlerRegistry registry)
{
this.bundle = bundle;
this.context = context;
@@ -56,6 +60,7 @@
// drops to zero.
this.contextMap = new WeakHashMap<HttpContext, ExtServletContext>();
this.sharedAttributes = sharedAttributes;
+ this.handlerRegistry = registry;
}
public ExtServletContext getServletContext(HttpContext httpContext)
@@ -82,7 +87,8 @@
null,
null,
servletRequestListener,
- servletRequestAttributeListener);
+ servletRequestAttributeListener,
+ handlerRegistry);
this.contextMap.put(httpContext, context);
return context;
}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
index ea25eb4..05e952c 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/service/SharedHttpServiceImpl.java
@@ -128,4 +128,9 @@
this.handlerRegistry.getRegistry(handler.getContextServiceId()).unregisterFilter(handler.getFilterInfo(), destroy);
}
}
+
+ public HandlerRegistry getHandlerRegistry()
+ {
+ return this.handlerRegistry;
+ }
}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java
index 75aa90c..d0340d2 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/SharedServletContextImpl.java
@@ -16,6 +16,9 @@
*/
package org.apache.felix.http.base.internal.whiteboard;
+import static org.apache.felix.http.base.internal.util.UriUtils.decodePath;
+import static org.apache.felix.http.base.internal.util.UriUtils.removeDotSegments;
+
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -40,7 +43,13 @@
import javax.servlet.SessionTrackingMode;
import javax.servlet.descriptor.JspConfigDescriptor;
+import org.apache.felix.http.base.internal.dispatch.RequestDispatcherImpl;
+import org.apache.felix.http.base.internal.dispatch.RequestInfo;
+import org.apache.felix.http.base.internal.handler.ServletHandler;
import org.apache.felix.http.base.internal.logger.SystemLogger;
+import org.apache.felix.http.base.internal.registry.PathResolution;
+import org.apache.felix.http.base.internal.registry.PerContextHandlerRegistry;
+import org.apache.felix.http.base.internal.registry.ServletResolution;
/**
* This servlet context implementation represents the shared
@@ -55,6 +64,7 @@
private final Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();
private final String contextPath;
private final String name;
+ private final PerContextHandlerRegistry registry;
private final ServletContextAttributeListener attributeListener;
private final Map<String, String> initParameters = new HashMap<String, String>();
@@ -62,7 +72,7 @@
final String name,
final String path,
final Map<String, String> initParameters,
- final ServletContextAttributeListener servletContextAttributeListener)
+ final PerContextHandlerRegistry registry)
{
this.context = webContext;
if ( path.equals("/") )
@@ -78,7 +88,8 @@
{
this.initParameters.putAll(initParameters);
}
- this.attributeListener = servletContextAttributeListener;
+ this.attributeListener = registry.getEventListenerRegistry();
+ this.registry = registry;
}
@Override
@@ -295,21 +306,73 @@
@Override
public RequestDispatcher getNamedDispatcher(final String name)
{
- // This is implemented by the ServletContext wrapper created in the Dispatcher
- return null;
+ if (name == null)
+ {
+ return null;
+ }
+
+ final RequestDispatcher dispatcher;
+ final ServletHandler servletHandler = this.registry.resolveServletByName(name);
+ if ( servletHandler != null )
+ {
+ final ServletResolution resolution = new ServletResolution();
+ resolution.handler = servletHandler;
+ resolution.handlerRegistry = this.registry;
+ // TODO - what is the path of a named servlet?
+ final RequestInfo requestInfo = new RequestInfo("", null, null);
+ dispatcher = new RequestDispatcherImpl(resolution, requestInfo);
+ }
+ else
+ {
+ dispatcher = null;
+ }
+ return dispatcher;
}
@Override
- public RequestDispatcher getRequestDispatcher(final String uri)
+ public RequestDispatcher getRequestDispatcher(String path)
{
- // This is implemented by the ServletContext wrapper created in the Dispatcher
- return null;
+ // See section 9.1 of Servlet 3.x specification...
+ if (path == null || (!path.startsWith("/") && !"".equals(path)))
+ {
+ return null;
+ }
+
+ String query = null;
+ int q = 0;
+ if ((q = path.indexOf('?')) > 0)
+ {
+ query = path.substring(q + 1);
+ path = path.substring(0, q);
+ }
+ // TODO remove path parameters...
+ String requestURI = decodePath(removeDotSegments(path));
+ if ( requestURI == null )
+ {
+ requestURI = "";
+ }
+
+ final RequestDispatcher dispatcher;
+ final PathResolution pathResolution = this.registry.resolve(requestURI);
+ if ( pathResolution != null )
+ {
+ final ServletResolution resolution = new ServletResolution();
+ resolution.handler = pathResolution.handler;
+ resolution.handlerRegistry = this.registry;
+ final RequestInfo requestInfo = new RequestInfo(pathResolution.servletPath, pathResolution.pathInfo, query);
+ dispatcher = new RequestDispatcherImpl(resolution, requestInfo);
+ }
+ else
+ {
+ dispatcher = null;
+ }
+ return dispatcher;
}
@Override
public InputStream getResourceAsStream(final String path)
{
- // This is implemented by the ServletContext wrapper created in the Dispatcher
+ // is implemented by {@link PerBundleServletContextImpl}.
return null;
}
diff --git a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
index 6bdca22..e733f05 100644
--- a/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
+++ b/http/base/src/main/java/org/apache/felix/http/base/internal/whiteboard/WhiteboardContextHandler.java
@@ -92,7 +92,7 @@
info.getName(),
info.getPath(),
info.getInitParameters(),
- this.registry.getEventListenerRegistry());
+ this.registry);
final boolean activate = getServletContext(httpBundle) != null;
if ( !activate )
{
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
index 0a3cf91..8920056 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextImplTest.java
@@ -452,7 +452,7 @@
this.httpContext = Mockito.mock(HttpContext.class);
this.listener = new AttributeListener();
this.context = new ServletContextImpl(this.bundle, globalContext, this.httpContext, this.listener, false,
- null, null, null, null);
+ null, null, null, null, null);
}
@Test
@@ -587,9 +587,9 @@
{
ServletContext globalContext = new MockServletContext();
ServletContext ctx1 = new ServletContextImpl(bundle, globalContext, httpContext, listener, true,
- null, null, null, null);
+ null, null, null, null, null);
ServletContext ctx2 = new ServletContextImpl(bundle, globalContext, httpContext, listener, true,
- null, null, null, null);
+ null, null, null, null, null);
Assert.assertNull(ctx1.getAttribute("key1"));
Assert.assertNull(ctx2.getAttribute("key1"));
@@ -698,9 +698,9 @@
{
ServletContext globalContext = new MockServletContext();
ServletContext ctx1 = new ServletContextImpl(bundle, globalContext, httpContext, listener, true,
- null, null, null, null);
+ null, null, null, null, null);
ServletContext ctx2 = new ServletContextImpl(bundle, globalContext, httpContext, listener, true,
- null, null, null, null);
+ null, null, null, null, null);
Enumeration e = ctx1.getAttributeNames();
Assert.assertNotNull(e);
@@ -736,9 +736,9 @@
{
ServletContext globalContext = new MockServletContext();
ServletContext ctx1 = new ServletContextImpl(bundle, globalContext, httpContext, listener, false,
- null, null, null, null);
+ null, null, null, null, null);
ServletContext ctx2 = new ServletContextImpl(bundle, globalContext, httpContext, listener, false,
- null, null, null, null);
+ null, null, null, null, null);
Assert.assertNull(ctx1.getAttribute("key1"));
Assert.assertNull(ctx2.getAttribute("key1"));
@@ -784,9 +784,9 @@
{
ServletContext globalContext = new MockServletContext();
ServletContext ctx1 = new ServletContextImpl(bundle, globalContext, httpContext, listener, false,
- null, null, null, null);
+ null, null, null, null, null);
ServletContext ctx2 = new ServletContextImpl(bundle, globalContext, httpContext, listener, false,
- null, null, null, null);
+ null, null, null, null, null);
Enumeration e = ctx1.getAttributeNames();
Assert.assertNotNull(e);
diff --git a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextManagerTest.java b/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextManagerTest.java
index 2ea84f5..39f79b7 100644
--- a/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextManagerTest.java
+++ b/http/base/src/test/java/org/apache/felix/http/base/internal/context/ServletContextManagerTest.java
@@ -36,7 +36,7 @@
Bundle bundle = Mockito.mock(Bundle.class);
ServletContext globalContext = Mockito.mock(ServletContext.class);
this.manager = new ServletContextManager(bundle, globalContext, null, false,
- null, null);
+ null, null, null);
}
@Test