org.apache.struts2.result.StrutsResultSupport Maven / Gradle / Ivy
/*
* 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.struts2.result;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.util.TextParseUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsStatics;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
/**
*
*
* A base class for all Struts action execution results.
* The "location" param is the default parameter, meaning the most common usage of this result would be:
*
*
*
* This class provides two common parameters for any subclass:
*
*
*
* - location - the location to go to after execution (could be a jsp page or another action).
* It can be parsed as per the rules definied in the
* {@link TextParseUtil#translateVariables(java.lang.String, com.opensymphony.xwork2.util.ValueStack) translateVariables}
* method
* - parse - true by default. If set to false, the location param will not be parsed for expressions
* - encode - false by default. If set to false, the location param will not be url encoded. This only have effect when parse is true
*
*
*
* NOTE:
* The encode param will only have effect when parse is true
*
*
*
*
*
*
*
* In the struts.xml configuration file, these would be included as:
*
*
*
* <result name="success" type="redirect">
* <param name="location">foo.jsp</param>
* </result>
*
* or
*
*
* <result name="success" type="redirect" >
* <param name="location">foo.jsp?url=${myUrl}</param>
* <param name="parse">true</param>
* <param name="encode">true</param>
* </result>
*
*
* In the above case, myUrl will be parsed against Ognl Value Stack and then
* URL encoded.1
*
*
* or when using the default parameter feature
*
*
*
* <result name="success" type="redirect">foo.jsp</result>
*
*
* You should subclass this class if you're interested in adding more parameters or functionality
* to your Result. If you do subclass this class you will need to
* override {@link #doExecute(String, ActionInvocation)}.
*
*
*
* Any custom result can be defined in struts.xml as:
*
*
*
* <result-types>
* ...
* <result-type name="myresult" class="com.foo.MyResult" />
* </result-types>
*
*
*
* Please see the {@link com.opensymphony.xwork2.Result} class for more info on Results in general.
*
*
*
* @see com.opensymphony.xwork2.Result
*/
public abstract class StrutsResultSupport implements Result, StrutsStatics {
private static final Logger LOG = LogManager.getLogger(StrutsResultSupport.class);
/** The default parameter */
public static final String DEFAULT_PARAM = "location";
/** use UTF-8 as this is the recommended encoding by W3C to avoid incompatibilities. */
public static final String DEFAULT_URL_ENCODING = "UTF-8";
protected boolean parseLocation = true;
private boolean parse;
private boolean encode;
private String location;
private String lastFinalLocation;
public StrutsResultSupport() {
this(null, true, false);
}
public StrutsResultSupport(String location) {
this(location, true, false);
}
public StrutsResultSupport(String location, boolean parse, boolean encode) {
this.location = location;
this.parse = parse;
this.encode = encode;
}
/**
* The location to go to after action execution. This could be a JSP page or another action.
* The location can contain OGNL expressions which will be evaulated if the parse
* parameter is set to true.
*
* @param location the location to go to after action execution.
* @see #setParse(boolean)
*/
public void setLocation(String location) {
this.location = location;
}
/**
* Gets the location it was created with, mainly for testing
*
* @return the location
*/
public String getLocation() {
return location;
}
/**
* Returns the last parsed and encoded location value
*
* @return the last final location
*/
public String getLastFinalLocation() {
return lastFinalLocation;
}
/**
* Set parse to true to indicate that the location should be parsed as an OGNL expression. This
* is set to true by default.
*
* @param parse true if the location parameter is an OGNL expression, false otherwise.
*/
public void setParse(boolean parse) {
this.parse = parse;
}
/**
* Set encode to true to indicate that the location should be url encoded. This is set to
* true by default
*
* @param encode true if the location parameter should be url encode, false otherwise.
*/
public void setEncode(boolean encode) {
this.encode = encode;
}
/**
* Implementation of the execute method from the Result interface. This will call
* the abstract method {@link #doExecute(String, ActionInvocation)} after optionally evaluating the
* location as an OGNL evaluation.
*
* @param invocation the execution state of the action.
* @throws Exception if an error occurs while executing the result.
*/
public void execute(ActionInvocation invocation) throws Exception {
lastFinalLocation = parseLocation ? conditionalParse(location, invocation) : location;
doExecute(lastFinalLocation, invocation);
}
/**
* Parses the parameter for OGNL expressions against the valuestack
*
* @param param The parameter value
* @param invocation The action invocation instance
* @return the resulting string
*/
protected String conditionalParse(String param, ActionInvocation invocation) {
if (parse && param != null && invocation != null) {
return TextParseUtil.translateVariables(
param,
invocation.getStack(),
new EncodingParsedValueEvaluator());
} else {
return param;
}
}
/**
* As {@link #conditionalParse(String, ActionInvocation)} but does not
* convert found object into String. If found object is a collection it is
* returned if found object is not a collection it is wrapped in one.
*
* @param param parameter
* @param invocation action invocation
* @param excludeEmptyElements 'true' for excluding empty elements
* @return the parsed collection of strings
*/
protected Collection conditionalParseCollection(String param, ActionInvocation invocation, boolean excludeEmptyElements) {
if (parse && param != null && invocation != null) {
return TextParseUtil.translateVariablesCollection(
param,
invocation.getStack(),
excludeEmptyElements,
new EncodingParsedValueEvaluator());
} else {
Collection collection = new ArrayList<>(1);
collection.add(param);
return collection;
}
}
/**
* {@link com.opensymphony.xwork2.util.TextParseUtil.ParsedValueEvaluator} to do URL encoding for found values. To be
* used for single strings or collections.
*
*/
private final class EncodingParsedValueEvaluator implements TextParseUtil.ParsedValueEvaluator {
public Object evaluate(String parsedValue) {
if (encode) {
if (parsedValue != null) {
try {
return URLEncoder.encode(parsedValue, DEFAULT_URL_ENCODING);
}
catch(UnsupportedEncodingException e) {
LOG.warn("error while trying to encode [{}]", parsedValue, e);
}
}
}
return parsedValue;
}
}
/**
* Executes the result given a final location (jsp page, action, etc) and the action invocation
* (the state in which the action was executed). Subclasses must implement this class to handle
* custom logic for result handling.
*
* @param finalLocation the location (jsp page, action, etc) to go to.
* @param invocation the execution state of the action.
* @throws Exception if an error occurs while executing the result.
*/
protected abstract void doExecute(String finalLocation, ActionInvocation invocation) throws Exception;
}