/*
* $Id: RequestUtils.java 727180 2008-12-16 21:54:10Z niallp $
*
* 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.struts.util;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.Globals;
import org.apache.struts.action.*;
import org.apache.struts.config.ActionConfig;
import org.apache.struts.config.FormBeanConfig;
import org.apache.struts.config.ForwardConfig;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.upload.FormFile;
import org.apache.struts.upload.MultipartRequestHandler;
import org.apache.struts.upload.MultipartRequestWrapper;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
/**
* <p>General purpose utility methods related to processing a servlet request
* in the Struts controller framework.</p>
*
* @version $Rev: 727180 $ $Date: 2008-12-17 00:54:10 +0300 (Ср., 17 дек. 2008) $
*/
public class RequestUtils {
// ------------------------------------------------------- Static Variables
/**
* <p>Commons Logging instance.</p>
*/
protected static Log log = LogFactory.getLog(RequestUtils.class);
// --------------------------------------------------------- Public Methods
/**
* <p>Create and return an absolute URL for the specified context-relative
* path, based on the server and context information in the specified
* request.</p>
*
* @param request The servlet request we are processing
* @param path The context-relative path (must start with '/')
* @return absolute URL based on context-relative path
* @throws MalformedURLException if we cannot create an absolute URL
*/
public static URL absoluteURL(HttpServletRequest request, String path)
throws MalformedURLException {
return (new URL(serverURL(request), request.getContextPath() + path));
}
/**
* <p>Return the <code>Class</code> object for the specified fully
* qualified class name, from this web application's class loader.</p>
*
* @param className Fully qualified class name to be loaded
* @return Class object
* @throws ClassNotFoundException if the class cannot be found
*/
public static Class applicationClass(String className)
throws ClassNotFoundException {
return applicationClass(className, null);
}
/**
* <p>Return the <code>Class</code> object for the specified fully
* qualified class name, from this web application's class loader.</p>
*
* @param className Fully qualified class name to be loaded
* @param classLoader The desired classloader to use
* @return Class object
* @throws ClassNotFoundException if the class cannot be found
*/
public static Class applicationClass(String className,
ClassLoader classLoader)
throws ClassNotFoundException {
if (classLoader == null) {
// Look up the class loader to be used
classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = RequestUtils.class.getClassLoader();
}
}
// Attempt to load the specified class
return (classLoader.loadClass(className));
}
/**
* <p>Return a new instance of the specified fully qualified class name,
* after loading the class from this web application's class loader. The
* specified class <strong>MUST</strong> have a public zero-arguments
* constructor.</p>
*
* @param className Fully qualified class name to use
* @return new instance of class
* @throws ClassNotFoundException if the class cannot be found
* @throws IllegalAccessException if the class or its constructor is not
* accessible
* @throws InstantiationException if this class represents an abstract
* class, an interface, an array class, a
* primitive type, or void
* @throws InstantiationException if this class has no zero-arguments
* constructor
*/
public static Object applicationInstance(String className)
throws ClassNotFoundException, IllegalAccessException,
InstantiationException {
return applicationInstance(className, null);
}
/**
* <p>Return a new instance of the specified fully qualified class name,
* after loading the class from this web application's class loader. The
* specified class <strong>MUST</strong> have a public zero-arguments
* constructor.</p>
*
* @param className Fully qualified class name to use
* @param classLoader The desired classloader to use
* @return new instance of class
* @throws ClassNotFoundException if the class cannot be found
* @throws IllegalAccessException if the class or its constructor is not
* accessible
* @throws InstantiationException if this class represents an abstract
* class, an interface, an array class, a
* primitive type, or void
* @throws InstantiationException if this class has no zero-arguments
* constructor
*/
public static Object applicationInstance(String className,
ClassLoader classLoader)
throws ClassNotFoundException, IllegalAccessException,
InstantiationException {
return (applicationClass(className, classLoader).newInstance());
}
/**
* <p>Create (if necessary) and return an <code>ActionForm</code> instance
* appropriate for this request. If no <code>ActionForm</code> instance
* is required, return <code>null</code>.</p>
*
* @param request The servlet request we are processing
* @param mapping The action mapping for this request
* @param moduleConfig The configuration for this module
* @param servlet The action servlet
* @return ActionForm instance associated with this request
*/
public static ActionForm createActionForm(HttpServletRequest request,
ActionMapping mapping, ModuleConfig moduleConfig, ActionServlet servlet) {
// Is there a form bean associated with this mapping?
String attribute = mapping.getAttribute();
if (attribute == null) {
return (null);
}
// Look up the form bean configuration information to use
String name = mapping.getName();
FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
if (config == null) {
log.warn("No FormBeanConfig found under '" + name + "'");
return (null);
}
ActionForm instance =
lookupActionForm(request, attribute, mapping.getScope());
// Can we recycle the existing form bean instance (if there is one)?
if ((instance != null) && config.canReuse(instance)) {
return (instance);
}
return createActionForm(config, servlet);
}
private static ActionForm lookupActionForm(HttpServletRequest request,
String attribute, String scope) {
// Look up any existing form bean instance
if (log.isDebugEnabled()) {
log.debug(" Looking for ActionForm bean instance in scope '"
+ scope + "' under attribute key '" + attribute + "'");
}
ActionForm instance = null;
HttpSession session = null;
if ("request".equals(scope)) {
instance = (ActionForm) request.getAttribute(attribute);
} else {
session = request.getSession();
instance = (ActionForm) session.getAttribute(attribute);
}
return (instance);
}
/**
* <p>Create and return an <code>ActionForm</code> instance appropriate to
* the information in <code>config</code>.</p>
* <p/>
* <p>Does not perform any checks to see if an existing ActionForm exists
* which could be reused.</p>
*
* @param config The configuration for the Form bean which is to be
* created.
* @param servlet The action servlet
* @return ActionForm instance associated with this request
*/
public static ActionForm createActionForm(FormBeanConfig config,
ActionServlet servlet) {
if (config == null) {
return (null);
}
ActionForm instance = null;
// Create and return a new form bean instance
try {
instance = config.createActionForm(servlet);
if (log.isDebugEnabled()) {
log.debug(" Creating new "
+ (config.getDynamic() ? "DynaActionForm" : "ActionForm")
+ " instance of type '" + config.getType() + "'");
log.trace(" --> " + instance);
}
} catch (Throwable t) {
log.error(servlet.getInternal().getMessage("formBean",
config.getType()), t);
}
return (instance);
}
/**
* <p>Retrieves the servlet mapping pattern for the specified {@link ActionServlet}.</p>
*
* @return the servlet mapping
* @see Globals#SERVLET_KEY
* @since Struts 1.3.6
*/
public static String getServletMapping(ActionServlet servlet) {
ServletContext servletContext = servlet.getServletConfig().getServletContext();
return (String) servletContext.getAttribute(Globals.SERVLET_KEY);
}
/**
* <p>Look up and return current user locale, based on the specified
* parameters.</p>
*
* @param request The request used to lookup the Locale
* @param locale Name of the session attribute for our user's Locale. If
* this is <code>null</code>, the default locale key is
* used for the lookup.
* @return current user locale
* @since Struts 1.2
*/
public static Locale getUserLocale(HttpServletRequest request, String locale) {
Locale userLocale = null;
HttpSession session = request.getSession(false);
if (locale == null) {
locale = Globals.LOCALE_KEY;
}
// Only check session if sessions are enabled
if (session != null) {
userLocale = (Locale) session.getAttribute(locale);
}
if (userLocale == null) {
// Returns Locale based on Accept-Language header or the server default
userLocale = request.getLocale();
}
return userLocale;
}
/**
* <p>Populate the properties of the specified JavaBean from the specified
* HTTP request, based on matching each parameter name against the
* corresponding JavaBeans "property setter" methods in the bean's class.
* Suitable conversion is done for argument types as described under
* <code>convert()</code>.</p>
*
* @param bean The JavaBean whose properties are to be set
* @param request The HTTP request whose parameters are to be used to
* populate bean properties
* @throws ServletException if an exception is thrown while setting
* property values
*/
public static void populate(Object bean, HttpServletRequest request)
throws ServletException {
populate(bean, null, null, request);
}
/**
* <p>Populate the properties of the specified JavaBean from the specified
* HTTP request, based on matching each parameter name (plus an optional
* prefix and/or suffix) against the corresponding JavaBeans "property
* setter" methods in the bean's class. Suitable conversion is done for
* argument types as described under <code>setProperties</code>.</p>
* <p/>
* <p>If you specify a non-null <code>prefix</code> and a non-null
* <code>suffix</code>, the parameter name must match
* <strong>both</strong> conditions for its value(s) to be used in
* populating bean properties. If the request's content type is
* "multipart/form-data" and the method is "POST", the
* <code>HttpServletRequest</code> object will be wrapped in a
* <code>MultipartRequestWrapper</code object.</p>
*
* @param bean The JavaBean whose properties are to be set
* @param prefix The prefix (if any) to be prepend to bean property names
* when looking for matching parameters
* @param suffix The suffix (if any) to be appended to bean property
* names when looking for matching parameters
* @param request The HTTP request whose parameters are to be used to
* populate bean properties
* @throws ServletException if an exception is thrown while setting
* property values
*/
public static void populate(Object bean, String prefix, String suffix,
HttpServletRequest request)
throws ServletException {
// Build a list of relevant request parameters from this request
HashMap properties = new HashMap();
// Iterator of parameter names
Enumeration names = null;
// Map for multipart parameters
Map multipartParameters = null;
String contentType = request.getContentType();
String method = request.getMethod();
boolean isMultipart = false;
if (bean instanceof ActionForm) {
((ActionForm) bean).setMultipartRequestHandler(null);
}
MultipartRequestHandler multipartHandler = null;
if ((contentType != null)
&& (contentType.startsWith("multipart/form-data"))
&& (method.equalsIgnoreCase("POST"))) {
// Get the ActionServletWrapper from the form bean
ActionServletWrapper servlet;
if (bean instanceof ActionForm) {
servlet = ((ActionForm) bean).getServletWrapper();
} else {
throw new ServletException("bean that's supposed to be "
+ "populated from a multipart request is not of type "
+ "\"org.apache.struts.action.ActionForm\", but type "
+ "\"" + bean.getClass().getName() + "\"");
}
// Obtain a MultipartRequestHandler
multipartHandler = getMultipartHandler(request);
if (multipartHandler != null) {
isMultipart = true;
// Set servlet and mapping info
servlet.setServletFor(multipartHandler);
multipartHandler.setMapping((ActionMapping) request
.getAttribute(Globals.MAPPING_KEY));
// Initialize multipart request class handler
multipartHandler.handleRequest(request);
//stop here if the maximum length has been exceeded
Boolean maxLengthExceeded =
(Boolean) request.getAttribute(MultipartRequestHandler.ATTRIBUTE_MAX_LENGTH_EXCEEDED);
if ((maxLengthExceeded != null)
&& (maxLengthExceeded.booleanValue())) {
((ActionForm) bean).setMultipartRequestHandler(multipartHandler);
return;
}
//retrieve form values and put into properties
multipartParameters =
getAllParametersForMultipartRequest(request,
multipartHandler);
names = Collections.enumeration(multipartParameters.keySet());
}
}
if (!isMultipart) {
names = request.getParameterNames();
}
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
String stripped = name;
if (prefix != null) {
if (!stripped.startsWith(prefix)) {
continue;
}
stripped = stripped.substring(prefix.length());
}
if (suffix != null) {
if (!stripped.endsWith(suffix)) {
continue;
}
stripped =
stripped.substring(0, stripped.length() - suffix.length());
}
Object parameterValue = null;
if (isMultipart) {
parameterValue = multipartParameters.get(name);
parameterValue = rationalizeMultipleFileProperty(bean, name, parameterValue);
} else {
parameterValue = request.getParameterValues(name);
}
// Populate parameters, except "standard" struts attributes
// such as 'org.apache.struts.action.CANCEL'
if (!(stripped.startsWith("org.apache.struts."))) {
properties.put(stripped, parameterValue);
}
}
// Set the corresponding properties of our bean
try {
BeanUtils.populate(bean, properties);
} catch (Exception e) {
throw new ServletException("BeanUtils.populate", e);
} finally {
if (multipartHandler != null) {
// Set the multipart request handler for our ActionForm.
// If the bean isn't an ActionForm, an exception would have been
// thrown earlier, so it's safe to assume that our bean is
// in fact an ActionForm.
((ActionForm) bean).setMultipartRequestHandler(multipartHandler);
}
}
}
/**
* <p>Populates the parameters of the specified ActionRedirect from
* the specified HTTP request.</p>
*
* @param redirect The ActionRedirect whose parameters are to be set
* @param request The HTTP request whose parameters are to be used
* @since Struts 1.4
*/
public static void populate(ActionRedirect redirect, HttpServletRequest request) {
assert (redirect != null) : "redirect is required";
assert (request != null) : "request is required";
Enumeration e = request.getParameterNames();
while (e.hasMoreElements()) {
String name = (String) e.nextElement();
String[] values = request.getParameterValues(name);
redirect.addParameter(name, values);
}
}
/**
* <p>If the given form bean can accept multiple FormFile objects but the user only uploaded a single, then
* the property will not match the form bean type. This method performs some simple checks to try to accommodate
* that situation.</p>
*
* @param bean
* @param name
* @param parameterValue
* @return
* @throws ServletException if the introspection has any errors.
*/
private static Object rationalizeMultipleFileProperty(Object bean, String name, Object parameterValue) throws ServletException {
if (!(parameterValue instanceof FormFile)) {
return parameterValue;
}
FormFile formFileValue = (FormFile) parameterValue;
try {
Class propertyType = PropertyUtils.getPropertyType(bean, name);
if (propertyType == null) {
return parameterValue;
}
if (List.class.isAssignableFrom(propertyType)) {
ArrayList list = new ArrayList(1);
list.add(formFileValue);
return list;
}
if (propertyType.isArray() && propertyType.getComponentType().equals(FormFile.class)) {
return new FormFile[]{formFileValue};
}
} catch (IllegalAccessException e) {
throw new ServletException(e);
} catch (InvocationTargetException e) {
throw new ServletException(e);
} catch (NoSuchMethodException e) {
throw new ServletException(e);
}
// no changes
return parameterValue;
}
/**
* <p>Try to locate a multipart request handler for this request. First,
* look for a mapping-specific handler stored for us under an attribute.
* If one is not present, use the global multipart handler, if there is
* one.</p>
*
* @param request The HTTP request for which the multipart handler should
* be found.
* @return the multipart handler to use, or null if none is found.
* @throws ServletException if any exception is thrown while attempting to
* locate the multipart handler.
*/
private static MultipartRequestHandler getMultipartHandler(
HttpServletRequest request)
throws ServletException {
MultipartRequestHandler multipartHandler = null;
String multipartClass =
(String) request.getAttribute(Globals.MULTIPART_KEY);
request.removeAttribute(Globals.MULTIPART_KEY);
// Try to initialize the mapping specific request handler
if (multipartClass != null) {
try {
multipartHandler =
(MultipartRequestHandler) applicationInstance(multipartClass);
} catch (ClassNotFoundException cnfe) {
log.error("MultipartRequestHandler class \"" + multipartClass
+ "\" in mapping class not found, "
+ "defaulting to global multipart class");
} catch (InstantiationException ie) {
log.error("InstantiationException when instantiating "
+ "MultipartRequestHandler \"" + multipartClass + "\", "
+ "defaulting to global multipart class, exception: "
+ ie.getMessage());
} catch (IllegalAccessException iae) {
log.error("IllegalAccessException when instantiating "
+ "MultipartRequestHandler \"" + multipartClass + "\", "
+ "defaulting to global multipart class, exception: "
+ iae.getMessage());
}
if (multipartHandler != null) {
return multipartHandler;
}
}
ModuleConfig moduleConfig =
ModuleUtils.getInstance().getModuleConfig(request);
multipartClass = moduleConfig.getControllerConfig().getMultipartClass();
// Try to initialize the global request handler
if (multipartClass != null) {
try {
multipartHandler =
(MultipartRequestHandler) applicationInstance(multipartClass);
} catch (ClassNotFoundException cnfe) {
throw new ServletException("Cannot find multipart class \""
+ multipartClass + "\"", cnfe);
} catch (InstantiationException ie) {
throw new ServletException(
"InstantiationException when instantiating "
+ "multipart class \"" + multipartClass + "\"", ie);
} catch (IllegalAccessException iae) {
throw new ServletException(
"IllegalAccessException when instantiating "
+ "multipart class \"" + multipartClass + "\"", iae);
}
if (multipartHandler != null) {
return multipartHandler;
}
}
return multipartHandler;
}
/**
* <p>Create a <code>Map</code> containing all of the parameters supplied
* for a multipart request, keyed by parameter name. In addition to text
* and file elements from the multipart body, query string parameters are
* included as well.</p>
*
* @param request The (wrapped) HTTP request whose parameters are
* to be added to the map.
* @param multipartHandler The multipart handler used to parse the
* request.
* @return the map containing all parameters for this multipart request.
*/
private static Map getAllParametersForMultipartRequest(
HttpServletRequest request, MultipartRequestHandler multipartHandler) {
Map parameters = new HashMap();
Hashtable elements = multipartHandler.getAllElements();
Enumeration e = elements.keys();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
parameters.put(key, elements.get(key));
}
if (request instanceof MultipartRequestWrapper) {
request =
(HttpServletRequest) ((MultipartRequestWrapper) request)
.getRequest();
e = request.getParameterNames();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
parameters.put(key, request.getParameterValues(key));
}
} else {
log.debug("Gathering multipart parameters for unwrapped request");
}
return parameters;
}
/**
* <p>Compute the printable representation of a URL, leaving off the
* scheme/host/port part if no host is specified. This will typically be
* the case for URLs that were originally created from relative or
* context-relative URIs.</p>
*
* @param url URL to render in a printable representation
* @return printable representation of a URL
*/
public static String printableURL(URL url) {
if (url.getHost() != null) {
return (url.toString());
}
String file = url.getFile();
String ref = url.getRef();
if (ref == null) {
return (file);
} else {
StringBuffer sb = new StringBuffer(file);
sb.append('#');
sb.append(ref);
return (sb.toString());
}
}
/**
* <p>Return the context-relative URL that corresponds to the specified
* {@link ActionConfig}, relative to the module associated with the
* current modules's {@link ModuleConfig}.</p>
*
* @param request The servlet request we are processing
* @param action ActionConfig to be evaluated
* @param pattern URL pattern used to map the controller servlet
* @return context-relative URL relative to the module
* @since Struts 1.1
*/
public static String actionURL(HttpServletRequest request,
ActionConfig action, String pattern) {
StringBuffer sb = new StringBuffer();
if (pattern.endsWith("/*")) {
sb.append(pattern.substring(0, pattern.length() - 2));
sb.append(action.getPath());
} else if (pattern.startsWith("*.")) {
ModuleConfig appConfig =
ModuleUtils.getInstance().getModuleConfig(request);
sb.append(appConfig.getPrefix());
sb.append(action.getPath());
sb.append(pattern.substring(1));
} else {
throw new IllegalArgumentException(pattern);
}
return sb.toString();
}
/**
* <p>Return the context-relative URL that corresponds to the specified
* <code>ForwardConfig</code>. The URL is calculated based on the
* properties of the {@link ForwardConfig} instance as follows:</p>
* <p/>
* <ul>
* <p/>
* <p/>
* <li>If the <code>contextRelative</code> property is set, it is assumed
* that the <code>path</code> property contains a path that is already
* context-relative:
* <p/>
* <ul>
* <p/>
* <li>If the <code>path</code> property value starts with a slash, it is
* returned unmodified.</li> <li>If the <code>path</code> property value
* does not start with a slash, a slash is prepended.</li>
* <p/>
* </ul></li>
* <p/>
* <li>Acquire the <code>forwardPattern</code> property from the
* <code>ControllerConfig</code> for the application module used to
* process this request. If no pattern was configured, default to a
* pattern of <code>$M$P</code>, which is compatible with the hard-coded
* mapping behavior in Struts 1.0.</li>
* <p/>
* <li>Process the acquired <code>forwardPattern</code>, performing the
* following substitutions:
* <p/>
* <ul>
* <p/>
* <li><strong>$M</strong> - Replaced by the module prefix for the
* application module processing this request.</li>
* <p/>
* <li><strong>$P</strong> - Replaced by the <code>path</code> property of
* the specified {@link ForwardConfig}, prepended with a slash if it does
* not start with one.</li>
* <p/>
* <li><strong>$$</strong> - Replaced by a single dollar sign
* character.</li>
* <p/>
* <li><strong>$x</strong> (where "x" is any charater not listed above) -
* Silently omit these two characters from the result value. (This has
* the side effect of causing all other $+letter combinations to be
* reserved.)</li>
* <p/>
* </ul></li>
* <p/>
* </ul>
*
* @param request The servlet request we are processing
* @param forward ForwardConfig to be evaluated
* @return context-relative URL
* @since Struts 1.1
*/
public static String forwardURL(HttpServletRequest request,
ForwardConfig forward) {
return forwardURL(request, forward, null);
}
/**
* <p>Return the context-relative URL that corresponds to the specified
* <code>ForwardConfig</code>. The URL is calculated based on the
* properties of the {@link ForwardConfig} instance as follows:</p>
* <p/>
* <ul>
* <p/>
* <li>If the <code>contextRelative</code> property is set, it is assumed
* that the <code>path</code> property contains a path that is already
* context-relative: <ul>
* <p/>
* <li>If the <code>path</code> property value starts with a slash, it is
* returned unmodified.</li> <li>If the <code>path</code> property value
* does not start with a slash, a slash is prepended.</li>
* <p/>
* </ul></li>
* <p/>
* <li>Acquire the <code>forwardPattern</code> property from the
* <code>ControllerConfig</code> for the application module used to
* process this request. If no pattern was configured, default to a
* pattern of <code>$M$P</code>, which is compatible with the hard-coded
* mapping behavior in Struts 1.0.</li>
* <p/>
* <li>Process the acquired <code>forwardPattern</code>, performing the
* following substitutions: <ul> <li><strong>$M</strong> - Replaced by the
* module prefix for the application module processing this request.</li>
* <p/>
* <li><strong>$P</strong> - Replaced by the <code>path</code> property of
* the specified {@link ForwardConfig}, prepended with a slash if it does
* not start with one.</li>
* <p/>
* <li><strong>$$</strong> - Replaced by a single dollar sign
* character.</li>
* <p/>
* <li><strong>$x</strong> (where "x" is any charater not listed above) -
* Silently omit these two characters from the result value. (This has
* the side effect of causing all other $+letter combinations to be
* reserved.)</li>
* <p/>
* </ul></li></ul>
*
* @param request The servlet request we are processing
* @param forward ForwardConfig to be evaluated
* @param moduleConfig Base forward on this module config.
* @return context-relative URL
* @since Struts 1.2
*/
public static String forwardURL(HttpServletRequest request,
ForwardConfig forward, ModuleConfig moduleConfig) {
//load the current moduleConfig, if null
if (moduleConfig == null) {
moduleConfig = ModuleUtils.getInstance().getModuleConfig(request);
}
String path = forward.getPath();
//load default prefix
String prefix = moduleConfig.getPrefix();
//override prefix if supplied by forward
if (forward.getModule() != null) {
prefix = forward.getModule();
if ("/".equals(prefix)) {
prefix = "";
}
}
StringBuffer sb = new StringBuffer();
// Calculate a context relative path for this ForwardConfig
String forwardPattern =
moduleConfig.getControllerConfig().getForwardPattern();
if (forwardPattern == null) {
// Performance optimization for previous default behavior
sb.append(prefix);
// smoothly insert a '/' if needed
if (!path.startsWith("/")) {
sb.append("/");
}
sb.append(path);
} else {
boolean dollar = false;
for (int i = 0; i < forwardPattern.length(); i++) {
char ch = forwardPattern.charAt(i);
if (dollar) {
switch (ch) {
case 'M':
sb.append(prefix);
break;
case 'P':
// add '/' if needed
if (!path.startsWith("/")) {
sb.append("/");
}
sb.append(path);
break;
case '$':
sb.append('$');
break;
default:
; // Silently swallow
}
dollar = false;
continue;
} else if (ch == '$') {
dollar = true;
} else {
sb.append(ch);
}
}
}
return (sb.toString());
}
/**
* <p>Return the URL representing the current request. This is equivalent
* to <code>HttpServletRequest.getRequestURL</code> in Servlet 2.3.</p>
*
* @param request The servlet request we are processing
* @return URL representing the current request
* @throws MalformedURLException if a URL cannot be created
*/
public static URL requestURL(HttpServletRequest request)
throws MalformedURLException {
StringBuffer url = requestToServerUriStringBuffer(request);
return (new URL(url.toString()));
}
/**
* <p>Return the URL representing the scheme, server, and port number of
* the current request. Server-relative URLs can be created by simply
* appending the server-relative path (starting with '/') to this.</p>
*
* @param request The servlet request we are processing
* @return URL representing the scheme, server, and port number of the
* current request
* @throws MalformedURLException if a URL cannot be created
*/
public static URL serverURL(HttpServletRequest request)
throws MalformedURLException {
StringBuffer url = requestToServerStringBuffer(request);
return (new URL(url.toString()));
}
/**
* <p>Return the string representing the scheme, server, and port number
* of the current request. Server-relative URLs can be created by simply
* appending the server-relative path (starting with '/') to this.</p>
*
* @param request The servlet request we are processing
* @return URL representing the scheme, server, and port number of the
* current request
* @since Struts 1.2.0
*/
public static StringBuffer requestToServerUriStringBuffer(
HttpServletRequest request) {
StringBuffer serverUri =
createServerUriStringBuffer(request.getScheme(),
request.getServerName(), request.getServerPort(),
request.getRequestURI());
return serverUri;
}
/**
* <p>Return <code>StringBuffer</code> representing the scheme, server,
* and port number of the current request. Server-relative URLs can be
* created by simply appending the server-relative path (starting with
* '/') to this.</p>
*
* @param request The servlet request we are processing
* @return URL representing the scheme, server, and port number of the
* current request
* @since Struts 1.2.0
*/
public static StringBuffer requestToServerStringBuffer(
HttpServletRequest request) {
return createServerStringBuffer(request.getScheme(),
request.getServerName(), request.getServerPort());
}
/**
* <p>Return <code>StringBuffer</code> representing the scheme, server,
* and port number of the current request.</p>
*
* @param scheme The scheme name to use
* @param server The server name to use
* @param port The port value to use
* @return StringBuffer in the form scheme: server: port
* @since Struts 1.2.0
*/
public static StringBuffer createServerStringBuffer(String scheme,
String server, int port) {
StringBuffer url = new StringBuffer();
if (port < 0) {
port = 80; // Work around java.net.URL bug
}
url.append(scheme);
url.append("://");
url.append(server);
if ((scheme.equals("http") && (port != 80))
|| (scheme.equals("https") && (port != 443))) {
url.append(':');
url.append(port);
}
return url;
}
/**
* <p>Return <code>StringBuffer</code> representing the scheme, server,
* and port number of the current request.</p>
*
* @param scheme The scheme name to use
* @param server The server name to use
* @param port The port value to use
* @param uri The uri value to use
* @return StringBuffer in the form scheme: server: port
* @since Struts 1.2.0
*/
public static StringBuffer createServerUriStringBuffer(String scheme,
String server, int port, String uri) {
StringBuffer serverUri = createServerStringBuffer(scheme, server, port);
serverUri.append(uri);
return serverUri;
}
/**
* <p>Returns the true path of the destination action if the specified forward
* is an action-aliased URL. This method version forms the URL based on
* the current request; selecting the current module if the forward does not
* explicitly contain a module path.</p>
*
* @param forward the forward config
* @param request the current request
* @param servlet the servlet handling the current request
* @return the context-relative URL of the action if the forward has an action identifier; otherwise <code>null</code>.
* @since Struts 1.3.6
*/
public static String actionIdURL(ForwardConfig forward, HttpServletRequest request, ActionServlet servlet) {
ModuleConfig moduleConfig = null;
if (forward.getModule() != null) {
String prefix = forward.getModule();
moduleConfig = ModuleUtils.getInstance().getModuleConfig(prefix, servlet.getServletContext());
} else {
moduleConfig = ModuleUtils.getInstance().getModuleConfig(request);
}
return actionIdURL(forward.getPath(), moduleConfig, servlet);
}
/**
* <p>Returns the true path of the destination action if the specified forward
* is an action-aliased URL. This method version forms the URL based on
* the specified module.
*
* @param originalPath the action-aliased path
* @param moduleConfig the module config for this request
* @param servlet the servlet handling the current request
* @return the context-relative URL of the action if the path has an action identifier; otherwise <code>null</code>.
* @since Struts 1.3.6
*/
public static String actionIdURL(String originalPath, ModuleConfig moduleConfig, ActionServlet servlet) {
if (originalPath.startsWith("http") || originalPath.startsWith("/")) {
return null;
}
// Split the forward path into the resource and query string;
// it is possible a forward (or redirect) has added parameters.
String actionId = null;
String qs = null;
int qpos = originalPath.indexOf("?");
if (qpos == -1) {
actionId = originalPath;
} else {
actionId = originalPath.substring(0, qpos);
qs = originalPath.substring(qpos);
}
// Find the action of the given actionId
ActionConfig actionConfig = moduleConfig.findActionConfigId(actionId);
if (actionConfig == null) {
if (log.isDebugEnabled()) {
log.debug("No actionId found for " + actionId);
}
return null;
}
String path = actionConfig.getPath();
String mapping = RequestUtils.getServletMapping(servlet);
StringBuffer actionIdPath = new StringBuffer();
// Form the path based on the servlet mapping pattern
if (mapping.startsWith("*")) {
actionIdPath.append(path);
actionIdPath.append(mapping.substring(1));
} else if (mapping.startsWith("/")) { // implied ends with a *
mapping = mapping.substring(0, mapping.length() - 1);
if (mapping.endsWith("/") && path.startsWith("/")) {
actionIdPath.append(mapping);
actionIdPath.append(path.substring(1));
} else {
actionIdPath.append(mapping);
actionIdPath.append(path);
}
} else {
log.warn("Unknown servlet mapping pattern");
actionIdPath.append(path);
}
// Lastly add any query parameters (the ? is part of the query string)
if (qs != null) {
actionIdPath.append(qs);
}
// Return the path
if (log.isDebugEnabled()) {
log.debug(originalPath + " unaliased to " + actionIdPath.toString());
}
return actionIdPath.toString();
}
/**
* Determines whether the current request is forwarded.
*
* @param request current HTTP request
* @return true if the request is forwarded; otherwise false
* @since Struts 1.4
*/
public static boolean isRequestForwarded(HttpServletRequest request) {
return (request.getAttribute("javax.servlet.forward.request_uri") != null);
}
/**
* Determines whether the current request is included.
*
* @param request current HTTP request
* @return true if the request is included; otherwise false
* @since Struts 1.4
*/
public static boolean isRequestIncluded(HttpServletRequest request) {
return (request.getAttribute("javax.servlet.include.request_uri") != null);
}
/**
* Verifies whether current request is forwarded from one action to
* another or not.
*
* @param request current HTTP request
* @return true if the request is chained; otherwise false
* @since Struts 1.4
*/
public static boolean isRequestChained(HttpServletRequest request) {
return (request.getAttribute(Globals.CHAIN_KEY) != null);
}
}