com.opensymphony.xwork2.ActionChainResult Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xwork Show documentation
Show all versions of xwork Show documentation
XWork is an command-pattern framework that is used to power WebWork
as well as other applications. XWork provides an Inversion of Control
container, a powerful expression language, data type conversion,
validation, and pluggable configuration.
/*
* Copyright (c) 2002-2006 by OpenSymphony
* All rights reserved.
*/
package com.opensymphony.xwork2;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.LinkedList;
/**
*
*
* This result invokes an entire other action, complete with it's own interceptor stack and result.
*
*
*
* This result type takes the following parameters:
*
*
*
*
*
* - actionName (default) - the name of the action that will be chained to
*
* - namespace - used to determine which namespace the Action is in that we're chaining. If namespace is null,
* this defaults to the current namespace
*
* - method - used to specify another method on target action to be invoked.
* If null, this defaults to execute method
*
* - skipActions - (optional) the list of comma separated action names for the
* actions that could be chained to
*
*
*
*
*
* Example:
*
*
* <package name="public" extends="webwork-default">
* <!-- Chain creatAccount to login, using the default parameter -->
* <action name="createAccount" class="...">
* <result type="chain">login</result>
* </action>
*
* <action name="login" class="...">
* <!-- Chain to another namespace -->
* <result type="chain">
* <param name="actionName">dashboard</param>
* <param name="namespace">/secure</param>
* </result>
* </action>
* </package>
*
* <package name="secure" extends="webwork-default" namespace="/secure">
* <action name="dashboard" class="...">
* <result>dashboard.jsp</result>
* </action>
* </package>
*
*
* @author Alexandru Popescu
*/
public class ActionChainResult implements Result {
private static final Log log = LogFactory.getLog(ActionChainResult.class);
/**
* The result parameter name to set the name of the action to chain to.
*/
public static final String DEFAULT_PARAM = "actionName";
/**
* The action context key to save the chain history.
*/
private static final String CHAIN_HISTORY = "CHAIN_HISTORY";
/**
* The result parameter name to set the name of the action to chain to.
*/
public static final String SKIP_ACTIONS_PARAM = "skipActions";
private ActionProxy proxy;
private String actionName;
private String namespace;
private String methodName;
/**
* The list of actions to skip.
*/
private String skipActions;
private ActionProxyFactory actionProxyFactory;
public ActionChainResult() {
super();
}
public ActionChainResult(String namespace, String actionName, String methodName) {
this.namespace = namespace;
this.actionName = actionName;
this.methodName = methodName;
}
public ActionChainResult(String namespace, String actionName, String methodName, String skipActions) {
this.namespace = namespace;
this.actionName = actionName;
this.methodName = methodName;
this.skipActions = skipActions;
}
/**
* @param actionProxyFactory the actionProxyFactory to set
*/
@Inject
public void setActionProxyFactory(ActionProxyFactory actionProxyFactory) {
this.actionProxyFactory = actionProxyFactory;
}
/**
* Set the action name.
*
* @param actionName The action name.
*/
public void setActionName(String actionName) {
this.actionName = actionName;
}
/**
* sets the namespace of the Action that we're chaining to. if namespace
* is null, this defaults to the current namespace.
*
* @param namespace the name of the namespace we're chaining to
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* Set the list of actions to skip.
* To test if an action should not throe an infinite recursion,
* only the action name is used, not the namespace.
*
* @param actions The list of action name separated by a white space.
*/
public void setSkipActions(String actions) {
this.skipActions = actions;
}
public void setMethod(String method) {
this.methodName = method;
}
public ActionProxy getProxy() {
return proxy;
}
/**
* Get the XWork chain history.
* The stack is a list of namespace/action!method
keys.
*/
public static LinkedList getChainHistory() {
LinkedList chainHistory = (LinkedList) ActionContext.getContext().get(CHAIN_HISTORY);
// Add if not exists
if (chainHistory == null) {
chainHistory = new LinkedList();
ActionContext.getContext().put(CHAIN_HISTORY, chainHistory);
}
return chainHistory;
}
/**
* @param invocation the DefaultActionInvocation calling the action call stack
*/
public void execute(ActionInvocation invocation) throws Exception {
// if the finalNamespace wasn't explicitly defined, assume the current one
if (this.namespace == null) {
this.namespace = invocation.getProxy().getNamespace();
}
ValueStack stack = ActionContext.getContext().getValueStack();
String finalNamespace = TextParseUtil.translateVariables(namespace, stack);
String finalActionName = TextParseUtil.translateVariables(actionName, stack);
String finalMethodName = this.methodName != null
? TextParseUtil.translateVariables(this.methodName, stack)
: null;
if (isInChainHistory(finalNamespace, finalActionName, finalMethodName)) {
addToHistory(finalNamespace, finalActionName, finalMethodName);
throw new XWorkException("Infinite recursion detected: "
+ ActionChainResult.getChainHistory().toString());
}
if (ActionChainResult.getChainHistory().isEmpty() && invocation != null && invocation.getProxy() != null) {
addToHistory(finalNamespace, invocation.getProxy().getActionName(), invocation.getProxy().getMethod());
}
addToHistory(finalNamespace, finalActionName, finalMethodName);
HashMap extraContext = new HashMap();
extraContext.put(ActionContext.VALUE_STACK, ActionContext.getContext().getValueStack());
extraContext.put(ActionContext.PARAMETERS, ActionContext.getContext().getParameters());
extraContext.put(CHAIN_HISTORY, ActionChainResult.getChainHistory());
if (log.isDebugEnabled()) {
log.debug("Chaining to action " + finalActionName);
}
proxy = actionProxyFactory.createActionProxy(finalNamespace, finalActionName, extraContext);
if (null != finalMethodName) {
proxy.setMethod(finalMethodName);
}
proxy.execute();
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final ActionChainResult that = (ActionChainResult) o;
if (actionName != null ? !actionName.equals(that.actionName) : that.actionName != null) return false;
if (methodName != null ? !methodName.equals(that.methodName) : that.methodName != null) return false;
if (namespace != null ? !namespace.equals(that.namespace) : that.namespace != null) return false;
return true;
}
public int hashCode() {
int result;
result = (actionName != null ? actionName.hashCode() : 0);
result = 31 * result + (namespace != null ? namespace.hashCode() : 0);
result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
return result;
}
private boolean isInChainHistory(String namespace, String actionName, String methodName) {
LinkedList chainHistory = ActionChainResult.getChainHistory();
if (chainHistory == null) {
return false;
} else {
// Actions to skip
Set skipActionsList = new HashSet();
if (skipActions != null && skipActions.length() > 0) {
ValueStack stack = ActionContext.getContext().getValueStack();
String finalSkipActions = TextParseUtil.translateVariables(this.skipActions, stack);
skipActionsList.addAll(TextParseUtil.commaDelimitedStringToSet(finalSkipActions));
}
if (!skipActionsList.contains(actionName)) {
// Get if key is in the chain history
return chainHistory.contains(makeKey(namespace, actionName, methodName));
}
return false;
}
}
private void addToHistory(String namespace, String actionName, String methodName) {
LinkedList chainHistory = ActionChainResult.getChainHistory();
chainHistory.add(makeKey(namespace, actionName, methodName));
}
private String makeKey(String namespace, String actionName, String methodName) {
if (null == methodName) {
return namespace + "/" + actionName;
}
return namespace + "/" + actionName + "!" + methodName;
}
}