You are viewing a plain text version of this content. The canonical link for it is here.
Posted to pluto-scm@portals.apache.org by at...@apache.org on 2009/05/04 16:39:50 UTC
svn commit: r771319 [1/2] - in /portals/pluto/trunk:
pluto-container-api/src/main/java/org/apache/pluto/container/
pluto-container-api/src/main/java/org/apache/pluto/container/om/portlet/
pluto-container-driver-api/src/main/java/org/apache/pluto/contai...
Author: ate
Date: Mon May 4 14:39:49 2009
New Revision: 771319
URL: http://svn.apache.org/viewvc?rev=771319&view=rev
Log:
PLUTO-557: Fixing the RequestDispatcher implementation to be more web container generic and pluggable through a Service
See: https://issues.apache.org/jira/browse/PLUTO-557
- A new RequestDispatcherService to allow for a pluggable and extendable Servlet RequestDispatcher implementation
The HttpPortletServletRequestWrapper class functionality is split into fine-grained protected method and uses protected or package scope member fields to actually make it easy to extend
- all HttpPortletServletRequestWrapper functionality is now heavily documented both inline and as javadoc
- DispatchDetection (a static enum) for *only* getParameterMap is configurable:
- CHECK_STATE (default): always compare current and previous parameterMap to detect changes
- CHECK_REQUEST_WRAPPER_STACK: always use the request wrapper stack (size) to see if the dispatch level has changed
- EVALUATE: upon the first getParameterMap call check if the request wrapper stack (size) is changed and switch to CHECK_REQUEST_WRAPPER_STACK, otherwise to CHECK_STATE
- the default CHECK_STATE can be overridden as constructor parameter on the (default) RequestDispatcherServiceImpl
- for detecting a dispatch on access to path method or attribute values, this solution can *not* be used
- PortletApplicationDefininition.getServletMappingURLPattern and RequestDispatcherPathInfo/-Provider no longer are needed and removed again (see also: PLUTO-535)
Added:
portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherService.java (with props)
portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/RequestDispatcherServiceImpl.java (with props)
Removed:
portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherPathInfo.java
portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherPathInfoProvider.java
portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/RequestDispatcherPathInfoImpl.java
portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/RequestDispatcherPathInfoProviderImpl.java
Modified:
portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/ContainerServices.java
portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/om/portlet/PortletApplicationDefinition.java
portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/OptionalContainerServices.java
portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PlutoServices.java
portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/HttpServletPortletRequestWrapper.java
portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAppDescriptorServiceImpl.java
portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletContextImpl.java
portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletRequestDispatcherImpl.java
portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/om/portlet/impl/PortletAppType.java
portals/pluto/trunk/pluto-portal-driver/src/main/java/org/apache/pluto/driver/container/DefaultOptionalContainerServices.java
portals/pluto/trunk/pluto-portal-driver/src/main/java/org/apache/pluto/driver/container/DriverPortletContextImpl.java
portals/pluto/trunk/pluto-portal-driver/src/main/java/org/apache/pluto/driver/container/PortalDriverServicesImpl.java
portals/pluto/trunk/pluto-portal-driver/src/main/java/org/apache/pluto/driver/container/PortletContextManager.java
Modified: portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/ContainerServices.java
URL: http://svn.apache.org/viewvc/portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/ContainerServices.java?rev=771319&r1=771318&r2=771319&view=diff
==============================================================================
--- portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/ContainerServices.java (original)
+++ portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/ContainerServices.java Mon May 4 14:39:49 2009
@@ -92,4 +92,10 @@
* @return a CCPPProfileServiceImplementation
*/
CCPPProfileService getCCPPProfileService();
+
+ /**
+ * Returns the RequestDispatcher service implementation
+ * @return a RequestDispatcherService implementation
+ */
+ RequestDispatcherService getRequestDispatcherService();
}
Added: portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherService.java
URL: http://svn.apache.org/viewvc/portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherService.java?rev=771319&view=auto
==============================================================================
--- portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherService.java (added)
+++ portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherService.java Mon May 4 14:39:49 2009
@@ -0,0 +1,52 @@
+/*
+ * 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.pluto.container;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletRequestDispatcher;
+import javax.portlet.PortletResponse;
+import javax.servlet.ServletContext;
+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.pluto.container.om.portlet.PortletApplicationDefinition;
+
+/**
+ * Service to retrieve a RequestDispatcher and corresponding HttpServletRequest and HttpServletResponse wrappers
+ * for usage by the PortletContext and to support custom Servlet Request dispatching.
+ *
+ * @version $Id$
+ */
+public interface RequestDispatcherService
+{
+ PortletRequestDispatcher getRequestDispatcher(ServletContext servletContext, PortletApplicationDefinition app,
+ String path);
+
+ PortletRequestDispatcher getNamedDispatcher(ServletContext servletContext, PortletApplicationDefinition app,
+ String name);
+
+ HttpServletRequestWrapper getRequestWrapper(ServletContext servletContext, HttpServletRequest servletRequest,
+ PortletRequest portletRequest, HttpSession session, boolean included,
+ boolean named);
+
+ HttpServletResponseWrapper getResponseWraper(ServletContext servletContext, HttpServletResponse servletResponse,
+ PortletRequest portletRequest, PortletResponse portletResponse,
+ boolean included);
+}
Propchange: portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherService.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherService.java
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/RequestDispatcherService.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/om/portlet/PortletApplicationDefinition.java
URL: http://svn.apache.org/viewvc/portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/om/portlet/PortletApplicationDefinition.java?rev=771319&r1=771318&r2=771319&view=diff
==============================================================================
--- portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/om/portlet/PortletApplicationDefinition.java (original)
+++ portals/pluto/trunk/pluto-container-api/src/main/java/org/apache/pluto/container/om/portlet/PortletApplicationDefinition.java Mon May 4 14:39:49 2009
@@ -19,7 +19,6 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Set;
import javax.xml.namespace.QName;
@@ -86,9 +85,6 @@
List<? extends ContainerRuntimeOption> getContainerRuntimeOptions();
ContainerRuntimeOption addContainerRuntimeOption(String name);
- Set<String> getServletMappingURLPatterns();
- void addServletMappingURLPattern(String servletMappingURLPattern);
-
Map<Locale, String> getLocaleEncodingMappings();
void addLocaleEncodingMapping(Locale locale, String encoding);
}
\ No newline at end of file
Modified: portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/OptionalContainerServices.java
URL: http://svn.apache.org/viewvc/portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/OptionalContainerServices.java?rev=771319&r1=771318&r2=771319&view=diff
==============================================================================
--- portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/OptionalContainerServices.java (original)
+++ portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/OptionalContainerServices.java Mon May 4 14:39:49 2009
@@ -21,6 +21,7 @@
import org.apache.pluto.container.PortletEnvironmentService;
import org.apache.pluto.container.PortletInvokerService;
import org.apache.pluto.container.PortletPreferencesService;
+import org.apache.pluto.container.RequestDispatcherService;
import org.apache.pluto.container.UserInfoService;
/**
@@ -80,4 +81,9 @@
* @return a CCPPProfileServiceImplementation
*/
CCPPProfileService getCCPPProfileService();
+
+ /**
+ * Returns the RequestDispatcherService
+ */
+ RequestDispatcherService getRequestDispatcherService();
}
Modified: portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PlutoServices.java
URL: http://svn.apache.org/viewvc/portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PlutoServices.java?rev=771319&r1=771318&r2=771319&view=diff
==============================================================================
--- portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PlutoServices.java (original)
+++ portals/pluto/trunk/pluto-container-driver-api/src/main/java/org/apache/pluto/container/driver/PlutoServices.java Mon May 4 14:39:49 2009
@@ -27,6 +27,7 @@
import org.apache.pluto.container.PortletPreferencesService;
import org.apache.pluto.container.PortletRequestContextService;
import org.apache.pluto.container.PortletURLListenerService;
+import org.apache.pluto.container.RequestDispatcherService;
import org.apache.pluto.container.UserInfoService;
@@ -116,4 +117,9 @@
{
return driverServices.getPortletURLListenerService();
}
+
+ public RequestDispatcherService getRequestDispatcherService()
+ {
+ return driverServices.getRequestDispatcherService();
+ }
}
Modified: portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/HttpServletPortletRequestWrapper.java
URL: http://svn.apache.org/viewvc/portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/HttpServletPortletRequestWrapper.java?rev=771319&r1=771318&r2=771319&view=diff
==============================================================================
--- portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/HttpServletPortletRequestWrapper.java (original)
+++ portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/HttpServletPortletRequestWrapper.java Mon May 4 14:39:49 2009
@@ -37,17 +37,13 @@
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletInputStream;
-import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession;
-import org.apache.pluto.container.PortletInvokerService;
-import org.apache.pluto.container.PortletRequestContext;
-import org.apache.pluto.container.RequestDispatcherPathInfo;
-import org.apache.pluto.container.RequestDispatcherPathInfoProvider;
-import org.apache.pluto.container.om.portlet.PortletApplicationDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* @author <a href="mailto:ate@douma.nu">Ate Douma</a>
@@ -55,28 +51,100 @@
*/
public class HttpServletPortletRequestWrapper extends HttpServletRequestWrapper
{
- private static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
- private static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
- private static final String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";
- private static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
- private static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
- private static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
- private static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
- private static final String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";
- private static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
- private static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
-
- private static final HashSet<String> PATHINFO_ATTRIBUTE_NAMES =
- new HashSet<String>(Arrays.asList(new String[] { INCLUDE_CONTEXT_PATH,
- INCLUDE_PATH_INFO,
- INCLUDE_QUERY_STRING,
- INCLUDE_REQUEST_URI,
- INCLUDE_SERVLET_PATH,
- FORWARD_CONTEXT_PATH,
- FORWARD_PATH_INFO,
- FORWARD_QUERY_STRING,
- FORWARD_REQUEST_URI,
- FORWARD_SERVLET_PATH }));
+ private static final Logger logger = LoggerFactory.getLogger(HttpServletPortletRequestWrapper.class);
+
+ protected static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
+ protected static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
+ protected static final String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";
+ protected static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
+ protected static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
+ protected static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
+ protected static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
+ protected static final String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";
+ protected static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
+ protected static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
+
+ protected static final String[] PATH_ATTRIBUTE_INCLUDE_NAMES = { INCLUDE_CONTEXT_PATH,
+ INCLUDE_PATH_INFO,
+ INCLUDE_QUERY_STRING,
+ INCLUDE_REQUEST_URI,
+ INCLUDE_SERVLET_PATH };
+
+ protected static final String[] PATH_ATTRIBUTE_FORWARD_NAMES = { FORWARD_CONTEXT_PATH,
+ FORWARD_PATH_INFO,
+ FORWARD_QUERY_STRING,
+ FORWARD_REQUEST_URI,
+ FORWARD_SERVLET_PATH };
+
+ protected static final String[] PATH_ATTRIBUTE_NAMES = { INCLUDE_CONTEXT_PATH,
+ INCLUDE_PATH_INFO,
+ INCLUDE_QUERY_STRING,
+ INCLUDE_REQUEST_URI,
+ INCLUDE_SERVLET_PATH,
+ FORWARD_CONTEXT_PATH,
+ FORWARD_PATH_INFO,
+ FORWARD_QUERY_STRING,
+ FORWARD_REQUEST_URI,
+ FORWARD_SERVLET_PATH };
+
+ protected static final HashSet<String> PATH_ATTRIBUTE_NAMES_SET =
+ new HashSet<String>(Arrays.asList(PATH_ATTRIBUTE_NAMES));
+
+ /**
+ * PathMethodValues contains the values of a HttpServletRequest PATH methods.
+ */
+ protected static final class PathMethodValues
+ {
+ String contextPath;
+ String servletPath;
+ String pathInfo;
+ String queryString;
+ String requestURI;
+
+ PathMethodValues(){}
+
+ PathMethodValues copy(PathMethodValues pmv)
+ {
+ this.contextPath = pmv.contextPath;
+ this.servletPath = pmv.servletPath;
+ this.pathInfo = pmv.pathInfo;
+ this.queryString = pmv.queryString;
+ this.requestURI = pmv.requestURI;
+ return this;
+ }
+ }
+
+ /**
+ * DispatchDetection defines how a (nested) RequestDispatcher include/forward call will be detected.
+ * <p>
+ * The dispatch detection is used to optimize building the custom parameters map as returned from the
+ * getParametersMap method as rebuilding the parameters map for each and every access can be quite expensive.
+ * </p>
+ * <p>
+ * A parameter map is constant within the scope of one (level of) request dispatching, but a nested request
+ * dispatch using an additional query string on the dispatch path requires merging of its query string parameters
+ * for the duration of that (nested) dispatch.
+ * </p>
+ * <p>
+ * DispatchDetection defines how such a nested dispatch is detected:
+ * <ul>
+ * <li>CHECK_STATE: full compare of the current getRequest().getParameterMap() against the initial getParameterMap()</li>
+ * <li>CHECK_REQUEST_WRAPPER_STACK: check if the webcontainer injected a HttpServletRequestWrapper <em>above</em> this
+ * request as Tomcat does (which usually will be less time/cpu consuming if many parameters are passed in)</li>
+ * <li>EVALUATE: auto detect on first getParameterMap() call if CHECK_REQUEST_WRAPPER_STACK can be used and then switch
+ * to either CHECK_STATE or CHECK_REQUEST_WRAPPER_STACK DispatchDetection</li>
+ * </ul>
+ * </p>
+ * <p>
+ * By default the CHECK_STATE method is used which in most cases is more optimal except when often many request parameters are used.
+ * </p>
+ */
+ static enum DispatchDetection { CHECK_STATE, CHECK_REQUEST_WRAPPER_STACK, EVALUATE };
+
+ /**
+ * Current DispatchDetection mode used, defaults to DispatchDetection.CHECK_STATE
+ */
+ static volatile DispatchDetection dispatchDetection = DispatchDetection.CHECK_STATE;
/**
* Cache for parsed dateHeader values.
@@ -95,36 +163,171 @@
new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
};
+
+ /**
+ * Map of the current, web container provided, PATH_ATTRIBUTE_NAMES attribute values.
+ */
+ protected Map<String,Object> currPathAttributeValues = new HashMap<String,Object>();
+
+ /**
+ * Map of the first, or first after a (PortletRequestDispatcher initiated nested dispatch, web container provided, PATH_ATTRIBUTE_NAMES attribute values.
+ */
+ protected Map<String,Object> dispPathAttributeValues = new HashMap<String, Object>();
+
+ /**
+ * Map of the PATH_ATTRIBUTE_NAMES attribute values provided to the invoking servlet as derived for the current (initial or nested) request dispatch.
+ */
+ protected Map<String,Object> pathAttributeValues = new HashMap<String, Object>();
+
+ /**
+ * Cache of PATH_ATTRIBUTE_NAMES attribute values possibly set using setAttribute.
+ * <p>
+ * This read-through cache protects against concurrent writing to the client request attribute map(s) when using multi-threaded rendering.
+ * </p>
+ */
+ protected Map<String,Object> pathAttributeCache = new HashMap<String, Object>();
+
+ /**
+ * Current getRequest() PATH method values
+ */
+ protected PathMethodValues currPathMethodValues = new PathMethodValues();
- private boolean included;
- private RequestDispatcherPathInfo methodPathInfo;
+ /**
+ * The first, or first after a (PortletRequestDispatcher initiated nested dispatch, web container provided, PATH method values.
+ */
+ protected PathMethodValues dispPathMethodValues = new PathMethodValues();
+
+ /**
+ * PATH method values provided to the invoking servlet as derived fro the current (initial or nested) request dispatch
+ */
+ protected PathMethodValues pathMethodValues = new PathMethodValues();
+
+ /**
+ * The initial, web container provided, PATH method values.
+ * <p>
+ * These values are kept separately from the dispPathMethodValues are the Portlet API retaining those for all further (nested) dispatching.
+ * But this actually only makes sense if the fist dispatch is not done using a NamedDispatcher.
+ * </p>
+ */
+ protected PathMethodValues initPathMethodValues;
+
+ /**
+ * Flag indicating if the current, web container provided, PATH_ATTRIBUTE_INCLUDE_NAMES attribute values are modified
+ */
+ protected boolean attributeIncludeValuesModified;
+
+ /**
+ * Flag indicating if the current, web container provided, PATH_ATTRIBUTE_FORWARD_NAMES attribute values are modified
+ */
+ protected boolean attributeForwardValuesModified;
+
+ /**
+ * Flag indicating if the current, web container provided, PATH method values are modified
+ */
+ protected boolean methodValuesModified;
+
+ /**
+ * Flag indicating if the current (possibly nested) request dispatch is based upon a NamedDispatcher.
+ */
+ protected boolean namedDispatch;
+
+ /**
+ * Flag indicating if the current (possibly nested) request dispatch is <em>intentionally</em> using RequestDispatcher.forward.
+ * <p>Note: it depends on isForwardingPossible() if an actual forward is used or "faked" while performing an include call.</p>
+ */
+ protected boolean forwarded;
+
+ /**
+ * Flag indicating if the initial level of dispatch is detected.
+ */
+ protected boolean dispatched;
+
+ /**
+ * Flag indicating if a nested dispatch is detected.
+ */
+ protected boolean nested;
- private Map<String, String[]> parameterMap;
- private Map<String, String[]> origParameterMap;
+ /**
+ * Current size of the nested HttpServletRequestWrapper stack size, counted from this request up.
+ * <p>
+ * Used together with DispatchDetection mode CHECK_REQUEST_WRAPPER_STACK or EVALUATE to determine if
+ * the current request dispatching "stack" has changed and thus the parameter map needs rebuilding.
+ * </p>
+ * <p>
+ * This type of DispatchDetection only works for web containers like Tomcat which "inject" (and remove) a HttpServletRequestWrapper
+ * of their own on each nested request dispatch call.
+ * </p>
+ */
+ protected int requestWrapperStackSize;
+
+ /**
+ * Initial parameters map as provided by the web container <em>before</em> the initial request dispatch.
+ * <p>
+ * Used for comparision with the current web container provided parameters map to calculate (possible)
+ * merged parameters when the initial (or a nested) request dispatcher was created using additional query string parameters.
+ * </p>
+ */
+ protected Map<String, String[]> origParameterMap;
+
+ /**
+ * Cache of current parameters map as provided by the web container.
+ * <p>
+ * Only used with DispatchDetection != CHECK_REQUEST_WRAPPER_STACK for comparision with the current
+ * current web container provided parameters map to detect a possible nested request dispatch
+ * with additional query string parameters (or a return thereof).
+ * </p>
+ */
+ protected Map<String, String[]> currParameterMap;
+
+ /**
+ * Cache of the derived parameters map to be provided to invoking servlet.
+ * <p>
+ * This parameter map is (re)build on first access to getParametersMap after a (nested) request dispatch or a
+ * return thereof.
+ * </p>
+ */
+ protected Map<String, String[]> parameterMap;
- private ServletRequest initialRequest;
- private ServletRequest currentRequest;
+ protected final ServletContext servletContext;
+ protected final PortletRequest portletRequest;
+ protected final ClientDataRequest clientDataRequest;
+ protected final String lifecyclePhase;
+ protected final boolean renderPhase;
- private final ServletContext servletContext;
- private final PortletRequest portletRequest;
- private final ClientDataRequest clientDataRequest;
- private final String lifecyclePhase;
- private final boolean renderPhase;
- private HttpSession session;
- private Map<String,Object> pathInfoAttributes = new HashMap<String,Object>();
+ protected HttpSession session;
@SuppressWarnings("unchecked")
- public HttpServletPortletRequestWrapper(HttpServletRequest request, ServletContext servletContext, HttpSession session, PortletRequest portletRequest, RequestDispatcherPathInfo pathInfo, boolean included)
+ public HttpServletPortletRequestWrapper(HttpServletRequest request, ServletContext servletContext, HttpSession session, PortletRequest portletRequest, boolean included, boolean namedDispatch)
{
super(request);
- origParameterMap = request.getParameterMap();
this.servletContext = servletContext;
this.session = session;
this.portletRequest = portletRequest;
lifecyclePhase = (String)portletRequest.getAttribute(PortletRequest.LIFECYCLE_PHASE);
clientDataRequest = PortletRequest.ACTION_PHASE.equals(lifecyclePhase) || PortletRequest.RESOURCE_PHASE.equals(lifecyclePhase) ? (ClientDataRequest)portletRequest : null;
renderPhase = PortletRequest.RENDER_PHASE.equals(lifecyclePhase);
- setNewPathInfo(pathInfo, included);
+ this.forwarded = !included;
+ this.namedDispatch = namedDispatch;
+ origParameterMap = new HashMap<String,String[]>(request.getParameterMap());
+ currParameterMap = origParameterMap;
+ for (String name : PATH_ATTRIBUTE_NAMES)
+ {
+ currPathAttributeValues.put(name,request.getAttribute(name));
+ }
+ currPathMethodValues.contextPath = request.getContextPath();
+ currPathMethodValues.servletPath = request.getServletPath();
+ currPathMethodValues.pathInfo = request.getPathInfo();
+ currPathMethodValues.queryString = request.getQueryString();
+ currPathMethodValues.requestURI = request.getRequestURI();
+ if (dispatchDetection != DispatchDetection.CHECK_STATE)
+ {
+ HttpServletRequestWrapper currentRequest = this;
+ while ((currentRequest.getRequest()) instanceof HttpServletRequestWrapper)
+ {
+ requestWrapperStackSize++;
+ currentRequest = (HttpServletRequestWrapper)currentRequest.getRequest();
+ }
+ }
}
/**
@@ -173,87 +376,523 @@
return dateValue.longValue();
}
- public boolean isForwardingPossible()
+ boolean isForwardingPossible()
{
return !renderPhase;
}
-
- public boolean isIncluded()
+
+ /**
+ * Returns the current forwarding state to be cached by the PortletRequestDispatcherImpl
+ * during a nested forward. This state needs to be restored with the restoreFromNestedForward method afterwards.
+ */
+ boolean isForwarded()
+ {
+ return forwarded;
+ }
+
+ /**
+ * Returns the current namedDispatch state to be cached by the PortletRequestDispatcherImpl
+ * during a nested forward. This state needs to be restored with the restoreFromNestedForward method afterwards.
+ */
+ boolean isNamedDispatch()
{
- return included;
+ return namedDispatch;
}
- public void setNewPathInfo(RequestDispatcherPathInfo methodPathInfo, boolean included)
+ /**
+ * Returns a <em>copy</em> of the current dispPathAttributeValues to be cached by the PortletRequestDispatcherImpl
+ * during a nested forward. These need to be restored with the restoreFromNestedForward method afterwards.
+ */
+ Map<String, Object> getPathAttributeValues()
+ {
+ return new HashMap<String, Object>(dispPathAttributeValues);
+ }
+
+ /**
+ * Returns a <em>copy</em> of the current initPathMethodValues (or null) to be cached by the PortletRequestDispatcherImpl
+ * during a nested forward. These need to be restored with the restoreFromNestedForward method afterwards.
+ */
+ PathMethodValues getInitPathMethodValues()
{
- // Only set/override forward attributes if:
- // - first time
- // - current request is a forward and a NamedDispatcher (meaning: no forward attributes)
- boolean setForwardAttributes = this.methodPathInfo == null || (!this.included && this.methodPathInfo.isNamedRequestDispatcher());
- this.initialRequest = getRequest();
- this.methodPathInfo = methodPathInfo;
- if (!methodPathInfo.isNamedRequestDispatcher())
+ return initPathMethodValues != null ? new PathMethodValues().copy(initPathMethodValues) : null;
+ }
+
+ /**
+ * Initiates a nested forward from the PortletRequestDispatcherImpl.
+ */
+ void setNestedForward()
+ {
+ dispatched = false;
+ forwarded = true;
+ namedDispatch = false;
+ }
+
+ /**
+ * Restores the previous request path state as cached by the PortletRequestDispatcherImpl after returning from a nested forward.
+ */
+ void restoreFromNestedForward(boolean forwarded, boolean namedDispatch,
+ PathMethodValues pathMethodValues, Map<String, Object> pathAttributeValues)
+ {
+ this.forwarded = forwarded;
+ this.namedDispatch = namedDispatch;
+ dispPathAttributeValues.clear();
+ dispPathAttributeValues.putAll(pathAttributeValues);
+ updateRequestPathState();
+ }
+
+ /**
+ * Method to check the current web container provided request path state with the cached state to determine if a (nested)
+ * request dispatch has occurred.
+ * <p>
+ * If a (nested) request dispatch has been determined, the derived pathMethodValues and pathAttributeValues are (re)created
+ * to be provided to the invoking servlet as override of the web container "view" of this state.
+ * </p>
+ */
+ protected void updateRequestPathState()
+ {
+ // synchronize current web container path method and attribute values and detect modifications
+ syncDispatcherPathValues();
+
+ // check and evaluate (significant) modifications to the path state
+ if (checkDispatcherPathValuesChanged())
{
- if (included)
+ // dispatch detected
+
+ if (!dispatched)
+ {
+ //initial dispatch or initial dispatch after a nested forward (from PortletRequestDispatcherImpl) detected
+ initFirstDispatchPathValues();
+ }
+ else
+ {
+ // check if (still) within a nested dispatch or returning back to the initial dispatch
+ checkNestedDispatch();
+ }
+ if (!nested)
{
- pathInfoAttributes.put(INCLUDE_CONTEXT_PATH, getContextPath());
- pathInfoAttributes.put(INCLUDE_PATH_INFO, methodPathInfo.getPathInfo());
- pathInfoAttributes.put(INCLUDE_QUERY_STRING, methodPathInfo.getQueryString());
- pathInfoAttributes.put(INCLUDE_REQUEST_URI, methodPathInfo.getRequestURI());
- pathInfoAttributes.put(INCLUDE_SERVLET_PATH, methodPathInfo.getServletPath());
+ // (back to) initial dispatch
+ setupFirstDispatchPathValues();
}
- else if (setForwardAttributes)
+ else // nested
{
- pathInfoAttributes.put(FORWARD_CONTEXT_PATH, getContextPath());
- pathInfoAttributes.put(FORWARD_PATH_INFO, methodPathInfo.getPathInfo());
- pathInfoAttributes.put(FORWARD_QUERY_STRING, methodPathInfo.getQueryString());
- pathInfoAttributes.put(FORWARD_REQUEST_URI, methodPathInfo.getRequestURI());
- pathInfoAttributes.put(FORWARD_SERVLET_PATH, methodPathInfo.getServletPath());
+ // (still) within a nested dispatch
+ setupNestedDispatchPathValues();
}
}
- this.included = included;
}
- public void restorePathInfo(ServletRequest initialRequest, RequestDispatcherPathInfo methodPathInfo, Map<String, Object> pathInfoAttributes, boolean included)
+ private static boolean compareAttributes(Object o1, Object o2)
{
- this.initialRequest = initialRequest;
- this.methodPathInfo = methodPathInfo;
- this.pathInfoAttributes = new HashMap<String,Object>(pathInfoAttributes);
- this.included = included;
+ return (o1 == null && o2 == null) || (o1 != null && o2 != null && o1.equals(o2));
}
- public ServletRequest getInitialRequest()
+ private static String asString(Object o)
{
- return initialRequest;
+ return o != null ? o.toString() : null;
}
- public RequestDispatcherPathInfo getMethodPathInfo()
+ /**
+ * Synchronize and compare current web container provided path state with the previously determined path state.
+ */
+ protected void syncDispatcherPathValues()
{
- return methodPathInfo;
+ HttpServletRequest request = (HttpServletRequest)getRequest();
+ Object attrValue;
+ String methodValue;
+
+ attributeIncludeValuesModified = false;
+ attributeForwardValuesModified = false;
+ methodValuesModified = false;
+
+ for (String name : PATH_ATTRIBUTE_INCLUDE_NAMES)
+ {
+ // first check possible cached path attributes as set through setAttribute
+ attrValue = pathAttributeCache.get(name);
+ if (attrValue == null)
+ {
+ // not cached: get current value from web container
+ attrValue = request.getAttribute(name);
+ }
+ // determine if modified
+ attributeIncludeValuesModified = !attributeIncludeValuesModified ? !compareAttributes(currPathAttributeValues.get(name), attrValue) : true;
+ // save new value for further usage and future modification check
+ currPathAttributeValues.put(name, attrValue);
+ }
+ for (String name : PATH_ATTRIBUTE_FORWARD_NAMES)
+ {
+ // first check possible cached path attributes as set through setAttribute
+ attrValue = pathAttributeCache.get(name);
+ if (attrValue == null)
+ {
+ // not cached: get current value from web container
+ attrValue = request.getAttribute(name);
+ }
+ // determine if modified
+ attributeForwardValuesModified = !attributeForwardValuesModified ? !compareAttributes(currPathAttributeValues.get(name), attrValue) : true;
+ // save new value for further usage and future modification check
+ currPathAttributeValues.put(name, attrValue);
+ }
+
+ // for all path method values:
+ // retrieve them from the current web container
+ // determine if modified
+ // save them further usage and future modification check
+
+ methodValue = request.getContextPath();
+ methodValuesModified = methodValuesModified ? true : !compareAttributes(currPathMethodValues.contextPath, methodValue);
+ currPathMethodValues.contextPath = methodValue;
+
+ methodValue = request.getServletPath();
+ methodValuesModified = methodValuesModified ? true : !compareAttributes(currPathMethodValues.servletPath, methodValue);
+ currPathMethodValues.servletPath = methodValue;
+
+ methodValue = request.getPathInfo();
+ methodValuesModified = methodValuesModified ? true : !compareAttributes(currPathMethodValues.pathInfo, methodValue);
+ currPathMethodValues.pathInfo = methodValue;
+
+ methodValue = request.getQueryString();
+ methodValuesModified = methodValuesModified ? true : !compareAttributes(currPathMethodValues.queryString, methodValue);
+ currPathMethodValues.queryString = methodValue;
+
+ methodValue = request.getRequestURI();
+ methodValuesModified = methodValuesModified ? true : !compareAttributes(currPathMethodValues.requestURI, methodValue);
+ currPathMethodValues.requestURI = methodValue;
}
- public Map<String,Object> getPathInfoAttributes()
+ /**
+ * Check and evaluate (significant) modifications to the path state.
+ */
+ protected boolean checkDispatcherPathValuesChanged()
{
- return new HashMap<String,Object>(pathInfoAttributes);
+ // initial "clearing" of current request path method and/or attribute values might be done by the container while
+ // still preparing for the dispatch: ignore and "swallow" those changes
+ if (methodValuesModified && currPathMethodValues.servletPath == null)
+ {
+ methodValuesModified = false;
+ }
+ if (attributeIncludeValuesModified && currPathAttributeValues.get(INCLUDE_SERVLET_PATH) == null)
+ {
+ attributeIncludeValuesModified = false;
+ }
+ if (attributeForwardValuesModified && currPathAttributeValues.get(FORWARD_SERVLET_PATH) == null)
+ {
+ attributeForwardValuesModified = false;
+ }
+ return (attributeIncludeValuesModified || attributeForwardValuesModified || methodValuesModified);
}
- @Override
- public String getParameter(String name)
+ /**
+ * Initialize first dispatch path state
+ */
+ protected void initFirstDispatchPathValues()
{
- String[] values = this.getParameterMap().get(name);
- return values != null ? values[0] : null;
+ dispatched = true;
+ dispPathMethodValues.copy(currPathMethodValues);
+ dispPathAttributeValues.putAll(currPathAttributeValues);
}
+ /**
+ * Determine if new dispatch path state represents the first dispatch or the first after a nested forward initiated from
+ * RequestDispatcherImpl, or a nested dispatch through ServletContext.getRequestDispatcher() or an include initiated from
+ * PortletRequestDispatcherImpl.
+ */
+ protected void checkNestedDispatch()
+ {
+ nested = false;
+ for (String name : PATH_ATTRIBUTE_NAMES)
+ {
+ if (!compareAttributes(dispPathAttributeValues.get(name), currPathAttributeValues.get(name)))
+ {
+ nested = true;
+ break;
+ }
+ }
+ nested = nested ? true : !compareAttributes(dispPathMethodValues.contextPath, currPathMethodValues.contextPath);
+ nested = nested ? true : !compareAttributes(dispPathMethodValues.servletPath, currPathMethodValues.servletPath);
+ nested = nested ? true : !compareAttributes(dispPathMethodValues.pathInfo, currPathMethodValues.pathInfo);
+ nested = nested ? true : !compareAttributes(dispPathMethodValues.queryString, currPathMethodValues.queryString);
+ nested = nested ? true : !compareAttributes(dispPathMethodValues.requestURI, currPathMethodValues.requestURI);
+ }
+
+ /**
+ * Deriving the path state values as should be provided to the invoking servlet for the first dispatch level.
+ * <p>
+ * Note: we also come here after returning back to the initial dispatch from a nested dispatch
+ * </p>
+ * <pre>
+ * If (namedDispatch):
+ * - All request attribute path values should be "hidden"
+ * - No path method values can/should be provided either, except for getContextPath()
+ * Note: this is a use-case not properly recognized in the portlet spec!
+ * Possibly, we might be *required* to keep the existing path method values as provided by the
+ * web container or maybe provide (only) a "/" as servletPath?
+ * else:
+ * - If (!forwarded) || (forwarded && !isForwardingPossible()):
+ * if (initial path method values determined) // see next If step below
+ * - use initial path method values
+ * else
+ * - use javax.servlet.include.* request attribute values as derived path method values (PLT.19.3.8)
+ * else: // (forwarded && isForwardingPossible())
+ * current (forward) path method values are OK
+ * - If (first dispatched && !namedDispatch)
+ * The current path method values need to be retained for all further (nested) dispatching (see above and below)
+ * - save current path method values as initial path values
+ * - If (!forwarded):
+ * - current javax.servlet.include.* request attribute values are OK
+ * - "hide" possible javax.servlet.forward.* request attribute values
+ * - else if (initial path method values determined) // see previous If step above
+ * - use initial path method values for javax.servlet.forward.* request attribute values
+ * - else if (forwarded && isForwardingPossible()):
+ * - use current path method values for javax.servlet.forward.* request attribute values (PLT.19.4.2)
+ * - "hide" possible javax.servlet.include.* request attribute values
+ * - else: // (forwarded && !isForwardingPossible())
+ * - remap javax.servlet.include.* request attribute values to javax.servlet.forward.* values
+ * - "hide" javax.servlet.include.* request attribute values
+ * </pre>
+ */
+ protected void setupFirstDispatchPathValues()
+ {
+ // Clear possible previously derived pathAttributeValues from a nested dispatch
+ pathAttributeValues.clear();
+ if (namedDispatch)
+ {
+ // only can/must support request.getContextPath()
+ pathMethodValues.contextPath = dispPathMethodValues.contextPath;
+ }
+ else
+ {
+ if (!forwarded || !isForwardingPossible())
+ {
+ if (initPathMethodValues != null)
+ {
+ pathMethodValues.copy(initPathMethodValues);
+ }
+ else
+ {
+ pathMethodValues.contextPath = asString(dispPathAttributeValues.get(INCLUDE_CONTEXT_PATH));
+ pathMethodValues.servletPath = asString(dispPathAttributeValues.get(INCLUDE_SERVLET_PATH));
+ pathMethodValues.pathInfo = asString(dispPathAttributeValues.get(INCLUDE_PATH_INFO));
+ pathMethodValues.queryString = asString(dispPathAttributeValues.get(INCLUDE_QUERY_STRING));
+ pathMethodValues.requestURI = asString(dispPathAttributeValues.get(INCLUDE_REQUEST_URI));
+ }
+ }
+ else // forwarded && isForwardingPossible()
+ {
+ pathMethodValues.copy(dispPathMethodValues);
+ }
+
+ // Save *first time* path method values as the portlet spec requires
+ // retaining those for all further (nested) dispatching:
+ // - includes: these values will override the path method values
+ // - forwards: these values will override the forward attribute values
+ // Note: this only make "sense" after a first !namedDispatch dispatch, e.g. .servletPath != null
+ if (initPathMethodValues == null && pathMethodValues.servletPath != null)
+ {
+ initPathMethodValues = new PathMethodValues().copy(pathMethodValues);
+ }
+
+ if (!forwarded)
+ {
+ pathAttributeValues.put(INCLUDE_CONTEXT_PATH, dispPathAttributeValues.get(INCLUDE_CONTEXT_PATH));
+ pathAttributeValues.put(INCLUDE_SERVLET_PATH, dispPathAttributeValues.get(INCLUDE_SERVLET_PATH));
+ pathAttributeValues.put(INCLUDE_PATH_INFO, dispPathAttributeValues.get(INCLUDE_PATH_INFO));
+ pathAttributeValues.put(INCLUDE_QUERY_STRING, dispPathAttributeValues.get(INCLUDE_QUERY_STRING));
+ pathAttributeValues.put(INCLUDE_REQUEST_URI, dispPathAttributeValues.get(INCLUDE_REQUEST_URI));
+ }
+ else if (initPathMethodValues != null)
+ {
+ pathAttributeValues.put(FORWARD_CONTEXT_PATH, initPathMethodValues.contextPath);
+ pathAttributeValues.put(FORWARD_SERVLET_PATH, initPathMethodValues.servletPath);
+ pathAttributeValues.put(FORWARD_PATH_INFO, initPathMethodValues.pathInfo);
+ pathAttributeValues.put(FORWARD_QUERY_STRING, initPathMethodValues.queryString);
+ pathAttributeValues.put(FORWARD_REQUEST_URI, initPathMethodValues.requestURI);
+ }
+ else if (forwarded && isForwardingPossible())
+ {
+ pathAttributeValues.put(FORWARD_CONTEXT_PATH, dispPathMethodValues.contextPath);
+ pathAttributeValues.put(FORWARD_SERVLET_PATH, dispPathMethodValues.servletPath);
+ pathAttributeValues.put(FORWARD_PATH_INFO, dispPathMethodValues.pathInfo);
+ pathAttributeValues.put(FORWARD_QUERY_STRING, dispPathMethodValues.queryString);
+ pathAttributeValues.put(FORWARD_REQUEST_URI, dispPathMethodValues.requestURI);
+ }
+ else // forwarded && !isForwardingPossible()
+ {
+ pathAttributeValues.put(FORWARD_CONTEXT_PATH, dispPathAttributeValues.get(INCLUDE_CONTEXT_PATH));
+ pathAttributeValues.put(FORWARD_SERVLET_PATH, dispPathAttributeValues.get(INCLUDE_SERVLET_PATH));
+ pathAttributeValues.put(FORWARD_PATH_INFO, dispPathAttributeValues.get(INCLUDE_PATH_INFO));
+ pathAttributeValues.put(FORWARD_QUERY_STRING, dispPathAttributeValues.get(INCLUDE_QUERY_STRING));
+ pathAttributeValues.put(FORWARD_REQUEST_URI, dispPathAttributeValues.get(INCLUDE_REQUEST_URI));
+ }
+ }
+ }
+
+ /**
+ * Deriving the path state values as should be provided to the invoking servlet for a nested dispatch.
+ * <p>
+ * As we are not in "control" here anymore, assume path method values and path INCLUDE attribute values
+ * as provided by the web container to be correct.
+ * </p>
+ * <p>
+ * However we need to retain the initial dispatch forward path attribute values <em>if</em> no new values are provided.
+ * </p>
+ */
+ protected void setupNestedDispatchPathValues()
+ {
+ // Use the web container provided path values instead of the initial dispatch path values
+ // whatever the current path method values: assume them correct
+ pathMethodValues.copy(currPathMethodValues);
+
+ // whatever the current attribute include path values: assume them correct (even if null)
+ pathAttributeValues.put(INCLUDE_CONTEXT_PATH, currPathAttributeValues.get(INCLUDE_CONTEXT_PATH));
+ pathAttributeValues.put(INCLUDE_SERVLET_PATH, currPathAttributeValues.get(INCLUDE_SERVLET_PATH));
+ pathAttributeValues.put(INCLUDE_PATH_INFO, currPathAttributeValues.get(INCLUDE_PATH_INFO));
+ pathAttributeValues.put(INCLUDE_QUERY_STRING, currPathAttributeValues.get(INCLUDE_QUERY_STRING));
+ pathAttributeValues.put(INCLUDE_REQUEST_URI, currPathAttributeValues.get(INCLUDE_REQUEST_URI));
+
+ // However: we need to retain our initial dispatch forward path attribute values *if* no new values are provided
+ // To determine if current forward path attributes are set, only need to check the context path
+ if (attributeForwardValuesModified && currPathAttributeValues.get(FORWARD_CONTEXT_PATH) != null)
+ {
+ pathAttributeValues.put(FORWARD_CONTEXT_PATH, currPathAttributeValues.get(FORWARD_CONTEXT_PATH));
+ pathAttributeValues.put(FORWARD_SERVLET_PATH, currPathAttributeValues.get(FORWARD_SERVLET_PATH));
+ pathAttributeValues.put(FORWARD_PATH_INFO, currPathAttributeValues.get(FORWARD_PATH_INFO));
+ pathAttributeValues.put(FORWARD_QUERY_STRING, currPathAttributeValues.get(FORWARD_QUERY_STRING));
+ pathAttributeValues.put(FORWARD_REQUEST_URI, currPathAttributeValues.get(FORWARD_REQUEST_URI));
+ }
+ }
+
+ /**
+ * Determine if the web container modified the current HttpServletRequestWrapper stack.
+ * <p>
+ * The current HttpServletRequestWrapper hierachy (stack) size is determined and compared against
+ * the previous size.
+ * </p>
+ * <p>
+ * If the size is different the web container "injected" (or removed) a request wrapper of its own
+ * to manage request dispatcher logic like merging additional dispatcher query string parameters.
+ * </p>
+ * <p>
+ * This DispatchDetection solution only works on web containers like Tomcat.
+ * </p>
+ * @return true if the request wrapper stack (size) changed.
+ */
+ protected boolean isRequestWrapperStackChanged()
+ {
+ HttpServletRequestWrapper currentRequest = this;
+ int currentRequestWrapperStackSize = 0;
+ while ((currentRequest.getRequest()) instanceof HttpServletRequestWrapper)
+ {
+ currentRequestWrapperStackSize++;
+ currentRequest = (HttpServletRequestWrapper)currentRequest.getRequest();
+ }
+ if (currentRequestWrapperStackSize != requestWrapperStackSize)
+ {
+ requestWrapperStackSize = currentRequestWrapperStackSize;
+ return true;
+ }
+ return false;
+ }
+ /**
+ * Returns a derived parameters map for the invoking servlet, merging the web container provided parameter map with the portletRequest parameter map
+ * which might contain additional parameters like public render parameters.
+ * <p>
+ * The derived parameters map is cached for the duration of the current request dispatch, and rebuild for every nested dispatch or return thereof.
+ * </p>
+ * <p>
+ * To determine if a nested dispatch occurred (or a return thereof), the current DispatchDetection mode is used:
+ * <ul>
+ * <li>CHECK_STATE: full compare of the current getRequest().getParameterMap() against the initial getParameterMap()</li>
+ * <li>CHECK_REQUEST_WRAPPER_STACK: check if the webcontainer injected a HttpServletRequestWrapper <em>above</em> this
+ * request as Tomcat does (which usually will be less time/cpu consuming if many parameters are passed in)</li>
+ * <li>EVALUATE: auto detect on first getParameterMap() call if CHECK_REQUEST_WRAPPER_STACK can be used and then switch
+ * to either CHECK_STATE or CHECK_REQUEST_WRAPPER_STACK DispatchDetection</li>
+ * </ul>
+ * </p>
+ */
@SuppressWarnings("unchecked")
@Override
public Map<String, String[]> getParameterMap()
{
- if (currentRequest == null || getRequest() != currentRequest)
+ boolean dispatchDetected = false;
+ Map<String, String[]> newParameterMap = null;
+
+ if (dispatchDetection == DispatchDetection.CHECK_REQUEST_WRAPPER_STACK)
{
- currentRequest = getRequest();
- Map<String, String[]> currParameterMap = currentRequest.getParameterMap();
+ if (isRequestWrapperStackChanged())
+ {
+ dispatchDetected = true;
+ }
+ }
+ else
+ {
+ if (dispatchDetection == DispatchDetection.EVALUATE)
+ {
+ if (isRequestWrapperStackChanged())
+ {
+ dispatchDetected = true;
+
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("DispatchDetection: changing from EVALUATE to CHECK_WEBCONTAINER_REQUEST");
+ }
+ dispatchDetection = DispatchDetection.CHECK_REQUEST_WRAPPER_STACK;
+ }
+ }
+ if (!dispatchDetected)
+ {
+ // Use parameters maps comparision to determine if a (nested) dispatch occurred or a return thereof.
+ // Note: if a nested dispatch didn't use additional query string parameters,
+ // no change will (need to) be detected.
+ newParameterMap = getRequest().getParameterMap();
+ if (newParameterMap.size() != currParameterMap.size())
+ {
+ dispatchDetected = true;
+ }
+ else
+ {
+ for (Map.Entry<String,String[]> entry : newParameterMap.entrySet())
+ {
+ String[] newValues = entry.getValue();
+ String[] currValues = currParameterMap.get(entry.getKey());
+ if (currValues == null || newValues.length != currValues.length)
+ {
+ // no need to compare the actual parameter values as per the servlet spec additional
+ // query string parameters always must be prepended so doing a length check is enough.
+ dispatchDetected = true;
+ break;
+ }
+ }
+ }
+ if (dispatchDetected && dispatchDetection == DispatchDetection.EVALUATE)
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("DispatchDetection: changing from EVALUATE to CHECK_STATE");
+ }
+ dispatchDetection = DispatchDetection.CHECK_STATE;
+ }
+ }
+ }
+
+ if (dispatchDetected || parameterMap == null)
+ {
+ if (newParameterMap == null)
+ {
+ newParameterMap = getRequest().getParameterMap();
+ }
+
+ if (dispatchDetection != DispatchDetection.CHECK_REQUEST_WRAPPER_STACK)
+ {
+ // Save the current parameters map for future comparision
+ // Note: this *must* be a copy as some web containers like WebSphere use
+ // a "dynamic" parameters map where the content of the current
+ // parameters map itself is modified...
+ currParameterMap = new HashMap<String,String[]>(newParameterMap);
+ }
Map<String, String[]> diffParameterMap = new HashMap<String, String[]>();
- for (Map.Entry<String,String[]> entry : currParameterMap.entrySet())
+ // determine the "diff" between the original parameters map and the current one
+ for (Map.Entry<String,String[]> entry : newParameterMap.entrySet())
{
String[] values = entry.getValue();
String[] original = origParameterMap.get(entry.getKey());
@@ -274,17 +913,20 @@
diffParameterMap.put(entry.getKey(), diff);
}
}
+ // we might actually see an empty diff when using DispatchDetection.CHECK_REQUEST_WRAPPER_STACK
+ // in which case the work above turned out to be not needed after all and we can retain the
+ // current cached parametersMap...
if (!diffParameterMap.isEmpty())
{
- currParameterMap.clear();
- currParameterMap.putAll(portletRequest.getParameterMap());
+ // build a new parametersMap by merging the diffParametersMap with the portletRequest.parametersMap
+ newParameterMap = new HashMap<String,String[]>(portletRequest.getParameterMap());
for (Map.Entry<String, String[]> entry : diffParameterMap.entrySet())
{
String[] diff = entry.getValue();
- String[] curr = currParameterMap.get(entry.getKey());
+ String[] curr = newParameterMap.get(entry.getKey());
if ( curr == null )
{
- currParameterMap.put(entry.getKey(), diff.clone());
+ newParameterMap.put(entry.getKey(), diff);
}
else
{
@@ -292,145 +934,296 @@
String[] copy = new String[curr.length+diff.length];
System.arraycopy(diff,0,copy,0,diff.length);
System.arraycopy(curr,0,copy,diff.length,curr.length);
- currParameterMap.put(entry.getKey(), copy);
+ newParameterMap.put(entry.getKey(), copy);
}
}
- parameterMap = Collections.unmodifiableMap(currParameterMap);
+ parameterMap = Collections.unmodifiableMap(newParameterMap);
}
- }
+ }
if (parameterMap == null)
{
+ // first time and no web container provided parameters
parameterMap = portletRequest.getParameterMap();
}
return parameterMap;
}
@Override
+ public String getParameter(String name)
+ {
+ // derive from getParametersMap() to ensure the cached parameters map is rebuild
+ // when needed for the current (nested) request dispatch
+ String[] values = this.getParameterMap().get(name);
+ return values != null ? values[0] : null;
+ }
+
+ @Override
public Enumeration<String> getParameterNames()
{
+ // derive from getParametersMap() to ensure the cached parameters map is rebuild
+ // when needed for the current (nested) request dispatch
return Collections.enumeration(this.getParameterMap().keySet());
}
@Override
public String[] getParameterValues(String name)
{
+ // derive from getParametersMap() to ensure the cached parameters map is rebuild
+ // when needed for the current (nested) request dispatch
return this.getParameterMap().get(name);
}
@Override
- public String getAuthType()
+ public String getContextPath()
{
- return portletRequest.getAuthType();
+ // synchronize the derived path state values first
+ updateRequestPathState();
+ // return the derived path method value
+ return pathMethodValues.contextPath;
}
@Override
- public Cookie[] getCookies()
+ public String getPathInfo()
{
- return portletRequest.getCookies();
+ // synchronize the derived path state values first
+ updateRequestPathState();
+ // return the derived path method value
+ return pathMethodValues.pathInfo;
}
@Override
- public long getDateHeader(String name)
+ public String getPathTranslated()
{
- String value = portletRequest.getProperty(name);
- if (value == null)
- {
- return (-1L);
+ // synchronize the derived path state values first
+ updateRequestPathState();
+ // base the return value on the derived path method value
+ if (pathMethodValues.pathInfo != null && pathMethodValues.contextPath.equals(portletRequest.getContextPath()))
+ {
+ // can only (and possibly) do this while still within the same context
+ return servletContext.getRealPath(pathMethodValues.pathInfo);
}
- // Attempt to convert the date header in a variety of formats
- return parseDateHeader(value);
+ return null;
}
@Override
- public String getHeader(String name)
+ public String getQueryString()
{
- return portletRequest.getProperty(name);
+ // synchronize the derived path state values first
+ updateRequestPathState();
+ // return the derived path method value
+ return pathMethodValues.queryString;
}
@Override
- public Enumeration<String> getHeaderNames()
+ public String getRequestURI()
{
- return portletRequest.getPropertyNames();
+ // synchronize the derived path state values first
+ updateRequestPathState();
+ // return the derived path method value
+ return pathMethodValues.requestURI;
}
@Override
- public Enumeration<String> getHeaders(String name)
+ public String getServletPath()
{
- return portletRequest.getProperties(name);
+ // synchronize the derived path state values first
+ updateRequestPathState();
+ // return the derived path method value
+ return pathMethodValues.servletPath;
}
@Override
- public int getIntHeader(String name)
+ public Object getAttribute(String name)
{
- String property = portletRequest.getProperty(name);
- if (property == null)
+ if (PATH_ATTRIBUTE_NAMES_SET.contains(name))
{
- return -1;
+ // synchronize the derived path state values first
+ updateRequestPathState();
+ // return the derived path attribute value
+ return pathAttributeValues.get(name);
}
- return Integer.parseInt(property);
+ // always first try to retrieve the attribute from the web container itself
+ Object value = getRequest().getAttribute(name);
+ return value != null ? value : portletRequest.getAttribute(name);
}
@Override
- public String getMethod()
+ public void setAttribute(String name, Object o)
{
- return renderPhase ? "GET" : super.getMethod();
+ if (PATH_ATTRIBUTE_NAMES_SET.contains(name))
+ {
+ // path attributes are never set/removed directly to/from the
+ // web container but maintained in a separate cache map to
+ // protect against concurrent writing to the client request attribute map(s)
+ // when using multi-threaded rendering.
+ pathAttributeCache.put(name, o);
+ }
+ else
+ {
+ portletRequest.setAttribute(name, o);
+ }
}
-
+
@Override
- public String getContextPath()
+ public void removeAttribute(String name)
{
- return portletRequest.getContextPath();
+ if (PATH_ATTRIBUTE_NAMES_SET.contains(name))
+ {
+ // path attributes are never set/removed directly to/from the
+ // web container but maintained in a separate cache map to
+ // protect against concurrent writing to the client request attribute map(s)
+ // when using multi-threaded rendering.
+ pathAttributeCache.remove(name);
+ }
+ else
+ {
+ portletRequest.removeAttribute(name);
+ }
}
+ @SuppressWarnings("unchecked")
@Override
- public String getPathInfo()
+ public Enumeration<String> getAttributeNames()
+ {
+ HashSet<String> names = new HashSet<String>();
+ Enumeration<String> e;
+ for (e = getRequest().getAttributeNames(); e.hasMoreElements(); )
+ {
+ try
+ {
+ names.add(e.nextElement());
+ }
+ catch(NoSuchElementException nse)
+ {
+ // ignore potential concurrent changes when run in parallel mode
+ }
+ }
+ for (e = portletRequest.getAttributeNames(); e.hasMoreElements(); )
+ {
+ try
+ {
+ names.add(e.nextElement());
+ }
+ catch(NoSuchElementException nse)
+ {
+ // ignore potential concurrent changes when run in parallel mode
+ }
+ }
+ // now synchronize the derived path state values before overriding with (or possibly removing from)
+ // the actual names set to enumerate
+ updateRequestPathState();
+ for (String name : PATH_ATTRIBUTE_NAMES)
+ {
+ if (pathAttributeValues.get(name) != null)
+ {
+ // ensure the derived path attribute name is present in the set
+ names.add(name);
+ }
+ else
+ {
+ // remove a possibly web container provided path attribute name
+ // if it currently should not be present based on our derived path state
+ names.remove(name);
+ }
+ }
+ return Collections.enumeration(names);
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path)
{
- return methodPathInfo.getPathInfo();
+ if (path != null)
+ {
+ // first determine if the web container does know how to dispatch to this path
+ RequestDispatcher dispatcher = super.getRequestDispatcher(path);
+ if (dispatcher != null)
+ {
+ // we have a RequestDispatcher
+ if (!dispatched)
+ {
+ // unlikely, but for sanity sake making sure our internal initial state is created
+ updateRequestPathState();
+ }
+
+ if (forwarded && isForwardingPossible())
+ {
+ // The webcontainer already will have set the initial request forward path attributes
+ // and a subsequent forward (or include) won't need any further special handling
+ // therefore we can simply let the webcontainer handle this itself
+ return dispatcher;
+ }
+ else
+ {
+ // !forwarded || !isForwardingPossible() can and needs to be handled by PortletRequestDispatcherImpl
+ // when the dispatch is going to be done using forward because that will require special overriding
+ // handling because of portlet spec requirements.
+ return new PortletRequestDispatcherImpl(dispatcher, false);
+ }
+ }
+ }
+ return null;
}
@Override
- public String getPathTranslated()
+ public long getDateHeader(String name)
{
- return getPathInfo() != null ? servletContext.getRealPath(getPathInfo()) : null;
+ String value = portletRequest.getProperty(name);
+ if (value == null)
+ {
+ return (-1L);
+ }
+ // Attempt to convert the date header in a variety of formats
+ return parseDateHeader(value);
}
@Override
- public String getQueryString()
+ public String getAuthType()
{
- return methodPathInfo.getQueryString();
+ return portletRequest.getAuthType();
}
@Override
- public String getRemoteUser()
+ public Cookie[] getCookies()
{
- return portletRequest.getRemoteUser();
+ return portletRequest.getCookies();
}
@Override
- public String getRequestedSessionId()
+ public String getHeader(String name)
{
- return portletRequest.getRequestedSessionId();
+ return portletRequest.getProperty(name);
}
@Override
- public String getRequestURI()
+ public Enumeration<String> getHeaderNames()
{
- return methodPathInfo.getRequestURI();
+ return portletRequest.getPropertyNames();
}
@Override
- public StringBuffer getRequestURL()
+ public Enumeration<String> getHeaders(String name)
{
- return null;
+ return portletRequest.getProperties(name);
}
@Override
- public String getServletPath()
+ public int getIntHeader(String name)
{
- return methodPathInfo.getServletPath();
+ String property = portletRequest.getProperty(name);
+ if (property == null)
+ {
+ return -1;
+ }
+ return Integer.parseInt(property);
}
@Override
+ public String getMethod()
+ {
+ return renderPhase ? "GET" : super.getMethod();
+ }
+
+ @Override
public HttpSession getSession()
{
return session != null ? session : super.getSession();
@@ -443,80 +1236,39 @@
}
@Override
- public Principal getUserPrincipal()
+ public String getRemoteUser()
{
- return portletRequest.getUserPrincipal();
+ return portletRequest.getRemoteUser();
}
@Override
- public boolean isRequestedSessionIdValid()
+ public String getRequestedSessionId()
{
- return portletRequest.isRequestedSessionIdValid();
+ return portletRequest.getRequestedSessionId();
}
@Override
- public boolean isUserInRole(String role)
+ public StringBuffer getRequestURL()
{
- return portletRequest.isUserInRole(role);
+ return null;
}
@Override
- public Object getAttribute(String name)
+ public Principal getUserPrincipal()
{
- boolean initialPathInfo = !included || getRequest() == initialRequest;
- if (initialPathInfo && PATHINFO_ATTRIBUTE_NAMES.contains(name))
- {
- return methodPathInfo.isNamedRequestDispatcher() ? null : pathInfoAttributes.get(name);
- }
-
- /*
- * First try to access the attribute from the *parent* request.
- * Webcontainers typically "inject" a custom servletrequest in between the
- * dispatched request (this) and its original "parent", to ensure proper
- * management of requestdispatcher state.
- * Webcontainer specific attributes therefore *must* be accessed from the
- * *current* parent request to ensure proper behavior
- * Without doing this, for instance Tomcat fails to properly match
- * servlet filters properly, if at all...
- * This should not really interfere with normal PortletRequest attribute
- * management as the PortletRequestContext implementation is assumed to
- * encode newly set attributes anyway or store them otherwise, hence going
- * through the current parent request *first* should not yield those
- * attributes.
- */
- Object value = getRequest().getAttribute(name);
- return value != null ? value : portletRequest.getAttribute(name);
+ return portletRequest.getUserPrincipal();
}
- @SuppressWarnings("unchecked")
@Override
- public Enumeration<String> getAttributeNames()
+ public boolean isRequestedSessionIdValid()
{
- HashSet<String> names = new HashSet<String>();
- Enumeration<String> e;
- for (e = getRequest().getAttributeNames(); e.hasMoreElements(); )
- {
- try
- {
- names.add(e.nextElement());
- }
- catch(NoSuchElementException nse)
- {
- // ignore potential concurrent changes when run in parallel mode
- }
- }
- for (e = portletRequest.getAttributeNames(); e.hasMoreElements(); )
- {
- try
- {
- names.add(e.nextElement());
- }
- catch(NoSuchElementException nse)
- {
- // ignore potential concurrent changes when run in parallel mode
- }
- }
- return Collections.enumeration(names);
+ return portletRequest.isRequestedSessionIdValid();
+ }
+
+ @Override
+ public boolean isUserInRole(String role)
+ {
+ return portletRequest.isUserInRole(role);
}
@Override
@@ -526,6 +1278,15 @@
}
@Override
+ public void setCharacterEncoding(String enc) throws UnsupportedEncodingException
+ {
+ if (clientDataRequest != null)
+ {
+ clientDataRequest.setCharacterEncoding(enc);
+ }
+ }
+
+ @Override
public int getContentLength()
{
return clientDataRequest != null ? clientDataRequest.getContentLength() : 0;
@@ -610,52 +1371,6 @@
}
@Override
- public RequestDispatcher getRequestDispatcher(String path)
- {
- if (path != null)
- {
- RequestDispatcher dispatcher = super.getRequestDispatcher(path);
- if (dispatcher != null)
- {
- if (!included && !isForwardingPossible())
- {
- // Special case: current "forward" dispatch is actually done using an "include" (e.g. during RENDER phase)
- // Thus we need to intercept a possible additional "forward" again
- // See also: PLT.19.4, last paragraph
- if (!path.startsWith("/"))
- {
- String servletPath = getServletPath();
- if (servletPath != null)
- {
- path = (servletPath.equals("/") ? "/" : servletPath) + path;
- }
- else
- {
- // Initial servlet dispatch was done using a NamedRequestDispatcher:
- // Impossible to determine the needed servletPath prefix
- // to build a correct RequestDispatcherPathInfo.
- // Only possible "solution" now is to assume "/"
- // However, chances are the webcontainerr then also will have been "lost"
- // and returned a null value for the requestDispatcher above in which case
- // we'll never end up here.
- path = "/" + path;
- }
- }
- PortletRequestContext requestContext = (PortletRequestContext)portletRequest.getAttribute(PortletInvokerService.REQUEST_CONTEXT);
- PortletApplicationDefinition app = requestContext.getPortletWindow().getPortletEntity().getPortletDefinition().getApplication();
- RequestDispatcherPathInfoProvider provider = RequestDispatcherPathInfoProviderImpl.getProvider(requestContext.getPortletConfig().getPortletContext(), app);
- return new PortletRequestDispatcherImpl(dispatcher, provider.getPathInfo(getContextPath(),path));
- }
- else
- {
- return dispatcher;
- }
- }
- }
- return null;
- }
-
- @Override
public String getScheme()
{
return portletRequest.getScheme();
@@ -678,39 +1393,4 @@
{
return portletRequest.isSecure();
}
-
- @Override
- public void removeAttribute(String name)
- {
- if (PATHINFO_ATTRIBUTE_NAMES.contains(name))
- {
- pathInfoAttributes.remove(name);
- }
- else
- {
- portletRequest.removeAttribute(name);
- }
- }
-
- @Override
- public void setAttribute(String name, Object o)
- {
- if (PATHINFO_ATTRIBUTE_NAMES.contains(name))
- {
- pathInfoAttributes.put(name, o);
- }
- else
- {
- portletRequest.setAttribute(name, o);
- }
- }
-
- @Override
- public void setCharacterEncoding(String enc) throws UnsupportedEncodingException
- {
- if (clientDataRequest != null)
- {
- clientDataRequest.setCharacterEncoding(enc);
- }
- }
}
Modified: portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAppDescriptorServiceImpl.java
URL: http://svn.apache.org/viewvc/portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAppDescriptorServiceImpl.java?rev=771319&r1=771318&r2=771319&view=diff
==============================================================================
--- portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAppDescriptorServiceImpl.java (original)
+++ portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletAppDescriptorServiceImpl.java Mon May 4 14:39:49 2009
@@ -222,27 +222,6 @@
NodeList children;
Element element;
- // retrieve servlet-mapping url patterns
- nodes = (NodeList)xpath.evaluate("/"+prefix+"web-app/"+prefix+"servlet-mapping", document, XPathConstants.NODESET);
- if (nodes != null)
- {
- String urlPattern;
-
- for (int i = 0, nsize = nodes.getLength(); i < nsize; i++)
- {
- element = (Element)nodes.item(i);
- children = element.getElementsByTagName("url-pattern");
- if (children != null && children.getLength() != 0)
- {
- urlPattern = children.item(0).getTextContent().trim();
- if (urlPattern.length() > 0)
- {
- pa.getServletMappingURLPatterns().add(urlPattern);
- }
- }
- }
- }
-
// retrieve locale-encoding-mapping
nodes = (NodeList)xpath.evaluate("/"+prefix+"web-app/"+prefix+"locale-encoding-mapping-list/"+prefix+"locale-encoding-mapping", document, XPathConstants.NODESET);
if (nodes != null)
Modified: portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletContextImpl.java
URL: http://svn.apache.org/viewvc/portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletContextImpl.java?rev=771319&r1=771318&r2=771319&view=diff
==============================================================================
--- portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletContextImpl.java (original)
+++ portals/pluto/trunk/pluto-container/src/main/java/org/apache/pluto/container/impl/PortletContextImpl.java Mon May 4 14:39:49 2009
@@ -26,15 +26,10 @@
import javax.portlet.PortletContext;
import javax.portlet.PortletRequestDispatcher;
-import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.apache.pluto.container.ContainerInfo;
-import org.apache.pluto.container.RequestDispatcherPathInfoProvider;
-import org.apache.pluto.container.impl.PortletRequestDispatcherImpl;
-import org.apache.pluto.container.impl.RequestDispatcherPathInfoProviderImpl;
+import org.apache.pluto.container.RequestDispatcherService;
import org.apache.pluto.container.om.portlet.PortletApplicationDefinition;
/**
@@ -44,18 +39,13 @@
*/
public class PortletContextImpl implements PortletContext
{
- /**
- * Logger.
- */
- private static final Logger LOG = LoggerFactory.getLogger(PortletContextImpl.class);
-
-
// Private Member Variables ------------------------------------------------
protected ServletContext servletContext;
protected PortletApplicationDefinition portletApp;
protected ContainerInfo containerInfo;
protected List<String> supportedContainerRuntimeOptions;
+ protected RequestDispatcherService rdService;
// Constructor -------------------------------------------------------------
@@ -67,12 +57,14 @@
public PortletContextImpl(ServletContext servletContext,
PortletApplicationDefinition portletApp,
ContainerInfo containerInfo,
- List<String> supportedContainerRuntimeOptions)
+ List<String> supportedContainerRuntimeOptions,
+ RequestDispatcherService rdService)
{
this.servletContext = servletContext;
this.portletApp = portletApp;
this.containerInfo = containerInfo;
this.supportedContainerRuntimeOptions = supportedContainerRuntimeOptions;
+ this.rdService = rdService;
}
// PortletContext Impl -----------------------------------------------------
@@ -87,58 +79,12 @@
public PortletRequestDispatcher getRequestDispatcher(String path)
{
- if (LOG.isDebugEnabled()) {
- LOG.debug("PortletRequestDispatcher requested: " + path);
- }
-
- // Check if the path name is valid. A valid path name must not be null
- // and must start with a slash '/' as defined by the portlet spec.
- if (path == null || !path.startsWith("/")) {
- if (LOG.isInfoEnabled()) {
- LOG.info("Failed to retrieve PortletRequestDispatcher: "
- + "path name must begin with a slash '/'.");
- }
- return null;
- }
-
- // Construct PortletRequestDispatcher.
- PortletRequestDispatcher portletRequestDispatcher = null;
- try {
- RequestDispatcher servletRequestDispatcher = servletContext.getRequestDispatcher(path);
- if (servletRequestDispatcher != null) {
-
- RequestDispatcherPathInfoProvider provider = RequestDispatcherPathInfoProviderImpl.getProvider(this, portletApp);
- portletRequestDispatcher = new PortletRequestDispatcherImpl(servletRequestDispatcher, provider.getPathInfo(portletApp.getContextPath(), path));
- } else {
- if (LOG.isInfoEnabled()) {
- LOG.info("No matching request dispatcher found for: " + path);
- }
- }
- } catch (Exception ex) {
- // We need to catch exception because of a Tomcat 4.x bug.
- // Tomcat throws an exception instead of return null if the path
- // was not found.
- if (LOG.isInfoEnabled()) {
- LOG.info("Failed to retrieve PortletRequestDispatcher: "
- + ex.getMessage());
- }
- portletRequestDispatcher = null;
- }
- return portletRequestDispatcher;
+ return rdService.getRequestDispatcher(servletContext, portletApp, path);
}
- public PortletRequestDispatcher getNamedDispatcher(String name) {
- RequestDispatcher dispatcher = servletContext.getNamedDispatcher(name);
- if (dispatcher != null)
- {
- RequestDispatcherPathInfoProvider provider = RequestDispatcherPathInfoProviderImpl.getProvider(this, portletApp);
- return new PortletRequestDispatcherImpl(dispatcher, provider.getNamedRequestDispatcherPathInfo());
- }
- if (LOG.isInfoEnabled()) {
- LOG.info("No matching request dispatcher found for name: "
- + name);
- }
- return null;
+ public PortletRequestDispatcher getNamedDispatcher(String name)
+ {
+ return rdService.getNamedDispatcher(servletContext, portletApp, name);
}
public InputStream getResourceAsStream(String path) {