org.apache.struts2.dispatcher.mapper
public class: DefaultActionMapper [javadoc |
source]
java.lang.Object
org.apache.struts2.dispatcher.mapper.DefaultActionMapper
All Implemented Interfaces:
ActionMapper
Direct Known Subclasses:
Restful2ActionMapper, RestActionMapper
Default action mapper implementation, using the standard *.[ext] (where ext
usually "action") pattern. The extension is looked up from the Struts
configuration key
struts.action.extension.
To help with dealing with buttons and other related requirements, this
mapper (and other
ActionMapper s, we hope) has the ability to name a
button with some predefined prefix and have that button name alter the
execution behaviour. The four prefixes are:
- Method prefix - method:default
- Action prefix - action:dashboard
- Redirect prefix - redirect:cancel.jsp
- Redirect-action prefix - redirectAction:cancel
In addition to these four prefixes, this mapper also understands the
action naming pattern of
foo!bar in either the extension form (eg:
foo!bar.action) or in the prefix form (eg: action:foo!bar). This syntax tells
this mapper to map to the action named
foo and the method
bar.
Method Prefix
With method-prefix, instead of calling baz action's execute() method (by
default if it isn't overriden in struts.xml to be something else), the baz
action's anotherMethod() will be called. A very elegant way determine which
button is clicked. Alternatively, one would have submit button set a
particular value on the action when clicked, and the execute() method decides
on what to do with the setted value depending on which button is clicked.
<!-- START SNIPPET: method-example -->
<s:form action="baz">
<s:textfield label="Enter your name" name="person.name"/>
<s:submit value="Create person"/>
<s:submit name="method:anotherMethod" value="Cancel"/>
</s:form>
<!-- END SNIPPET: method-example -->
Action prefix
With action-prefix, instead of executing baz action's execute() method (by
default if it isn't overriden in struts.xml to be something else), the
anotherAction action's execute() method (assuming again if it isn't overriden
with something else in struts.xml) will be executed.
<!-- START SNIPPET: action-example -->
<s:form action="baz">
<s:textfield label="Enter your name" name="person.name"/>
<s:submit value="Create person"/>
<s:submit name="action:anotherAction" value="Cancel"/>
</s:form>
<!-- END SNIPPET: action-example -->
Redirect prefix
With redirect-prefix, instead of executing baz action's execute() method (by
default it isn't overriden in struts.xml to be something else), it will get
redirected to, in this case to www.google.com. Internally it uses
ServletRedirectResult to do the task.
<!-- START SNIPPET: redirect-example -->
<s:form action="baz">
<s:textfield label="Enter your name" name="person.name"/>
<s:submit value="Create person"/>
<s:submit name="redirect:www.google.com" value="Cancel"/>
</s:form>
<!-- END SNIPPET: redirect-example -->
Redirect-action prefix
With redirect-action-prefix, instead of executing baz action's execute()
method (by default it isn't overriden in struts.xml to be something else), it
will get redirected to, in this case 'dashboard.action'. Internally it uses
ServletRedirectResult to do the task and read off the extension from the
struts.properties.
<!-- START SNIPPET: redirect-action-example -->
<s:form action="baz">
<s:textfield label="Enter your name" name="person.name"/>
<s:submit value="Create person"/>
<s:submit name="redirectAction:dashboard" value="Cancel"/>
</s:form>
<!-- END SNIPPET: redirect-action-example -->
| Field Summary |
|---|
| protected static final String | METHOD_PREFIX | |
| protected static final String | ACTION_PREFIX | |
| protected static final String | REDIRECT_PREFIX | |
| protected static final String | REDIRECT_ACTION_PREFIX | |
| protected boolean | allowDynamicMethodCalls | |
| protected boolean | allowSlashesInActionNames | |
| protected boolean | alwaysSelectFullNamespace | |
| protected PrefixTrie | prefixTrie | |
| protected List<String> | extensions | |
| protected Container | container | |
| Method from org.apache.struts2.dispatcher.mapper.DefaultActionMapper Summary: |
|---|
|
addParameterAction, dropExtension, dropExtension, getDefaultExtension, getMapping, getMappingFromActionName, getUri, getUriFromActionMapping, handleSpecialParameters, isSlashesInActionNames, parseActionName, parseNameAndNamespace, setAllowDynamicMethodCalls, setAlwaysSelectFullNamespace, setContainer, setExtensions, setSlashesInActionNames |
| Methods from java.lang.Object: |
|---|
|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Method from org.apache.struts2.dispatcher.mapper.DefaultActionMapper Detail: |
protected void addParameterAction(String prefix,
ParameterAction parameterAction) {
prefixTrie.put(prefix, parameterAction);
}
Adds a parameter action. Should only be called during initialization |
protected String dropExtension(String name) {
return dropExtension(name, new ActionMapping());
} Deprecated! Since - 2.1, use #dropExtension(java.lang.String,org.apache.struts2.dispatcher.mapper.ActionMapping) instead
Drops the extension from the action name |
protected String dropExtension(String name,
ActionMapping mapping) {
if (extensions == null) {
return name;
}
for (String ext : extensions) {
if ("".equals(ext)) {
// This should also handle cases such as /foo/bar-1.0/description. It is tricky to
// distinquish /foo/bar-1.0 but perhaps adding a numeric check in the future could
// work
int index = name.lastIndexOf('.');
if (index == -1 || name.indexOf('/', index) >= 0) {
return name;
}
} else {
String extension = "." + ext;
if (name.endsWith(extension)) {
name = name.substring(0, name.length() - extension.length());
mapping.setExtension(ext);
return name;
}
}
}
return null;
}
Drops the extension from the action name, storing it in the mapping for later use |
protected String getDefaultExtension() {
if (extensions == null) {
return null;
} else {
return (String) extensions.get(0);
}
}
Returns null if no extension is specified. |
public ActionMapping getMapping(HttpServletRequest request,
ConfigurationManager configManager) {
ActionMapping mapping = new ActionMapping();
String uri = getUri(request);
int indexOfSemicolon = uri.indexOf(";");
uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;
uri = dropExtension(uri, mapping);
if (uri == null) {
return null;
}
parseNameAndNamespace(uri, mapping, configManager);
handleSpecialParameters(request, mapping);
if (mapping.getName() == null) {
return null;
}
parseActionName(mapping);
return mapping;
}
|
public ActionMapping getMappingFromActionName(String actionName) {
ActionMapping mapping = new ActionMapping();
mapping.setName(actionName);
return parseActionName(mapping);
}
|
protected String getUri(HttpServletRequest request) {
// handle http dispatcher includes.
String uri = (String) request
.getAttribute("javax.servlet.include.servlet_path");
if (uri != null) {
return uri;
}
uri = RequestUtils.getServletPath(request);
if (uri != null && !"".equals(uri)) {
return uri;
}
uri = request.getRequestURI();
return uri.substring(request.getContextPath().length());
}
Gets the uri from the request |
public String getUriFromActionMapping(ActionMapping mapping) {
StringBuilder uri = new StringBuilder();
if (mapping.getNamespace() != null) {
uri.append(mapping.getNamespace());
if (!"/".equals(mapping.getNamespace())) {
uri.append("/");
}
}
String name = mapping.getName();
String params = "";
if (name.indexOf('?') != -1) {
params = name.substring(name.indexOf('?'));
name = name.substring(0, name.indexOf('?'));
}
uri.append(name);
if (null != mapping.getMethod() && !"".equals(mapping.getMethod())) {
uri.append("!").append(mapping.getMethod());
}
String extension = mapping.getExtension();
if (extension == null) {
extension = getDefaultExtension();
// Look for the current extension, if available
ActionContext context = ActionContext.getContext();
if (context != null) {
ActionMapping orig = (ActionMapping) context.get(ServletActionContext.ACTION_MAPPING);
if (orig != null) {
extension = orig.getExtension();
}
}
}
if (extension != null) {
if (extension.length() == 0 || (extension.length() > 0 && uri.indexOf('.' + extension) == -1)) {
if (extension.length() > 0) {
uri.append(".").append(extension);
}
if (params.length() > 0) {
uri.append(params);
}
}
}
return uri.toString();
}
|
public void handleSpecialParameters(HttpServletRequest request,
ActionMapping mapping) {
// handle special parameter prefixes.
Set< String > uniqueParameters = new HashSet< String >();
Map parameterMap = request.getParameterMap();
for (Iterator iterator = parameterMap.keySet().iterator(); iterator
.hasNext();) {
String key = (String) iterator.next();
// Strip off the image button location info, if found
if (key.endsWith(".x") || key.endsWith(".y")) {
key = key.substring(0, key.length() - 2);
}
// Ensure a parameter doesn't get processed twice
if (!uniqueParameters.contains(key)) {
ParameterAction parameterAction = (ParameterAction) prefixTrie
.get(key);
if (parameterAction != null) {
parameterAction.execute(key, mapping);
uniqueParameters.add(key);
break;
}
}
}
}
Special parameters, as described in the class-level comment, are searched
for and handled. |
public boolean isSlashesInActionNames() {
return allowSlashesInActionNames;
}
|
protected ActionMapping parseActionName(ActionMapping mapping) {
if (mapping.getName() == null) {
return mapping;
}
if (allowDynamicMethodCalls) {
// handle "name!method" convention.
String name = mapping.getName();
int exclamation = name.lastIndexOf("!");
if (exclamation != -1) {
mapping.setName(name.substring(0, exclamation));
mapping.setMethod(name.substring(exclamation + 1));
}
}
return mapping;
}
|
protected void parseNameAndNamespace(String uri,
ActionMapping mapping,
ConfigurationManager configManager) {
String namespace, name;
int lastSlash = uri.lastIndexOf("/");
if (lastSlash == -1) {
namespace = "";
name = uri;
} else if (lastSlash == 0) {
// ww-1046, assume it is the root namespace, it will fallback to
// default
// namespace anyway if not found in root namespace.
namespace = "/";
name = uri.substring(lastSlash + 1);
} else if (alwaysSelectFullNamespace) {
// Simply select the namespace as everything before the last slash
namespace = uri.substring(0, lastSlash);
name = uri.substring(lastSlash + 1);
} else {
// Try to find the namespace in those defined, defaulting to ""
Configuration config = configManager.getConfiguration();
String prefix = uri.substring(0, lastSlash);
namespace = "";
boolean rootAvailable = false;
// Find the longest matching namespace, defaulting to the default
for (Object cfg : config.getPackageConfigs().values()) {
String ns = ((PackageConfig) cfg).getNamespace();
if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) {
if (ns.length() > namespace.length()) {
namespace = ns;
}
}
if ("/".equals(ns)) {
rootAvailable = true;
}
}
name = uri.substring(namespace.length() + 1);
// Still none found, use root namespace if found
if (rootAvailable && "".equals(namespace)) {
namespace = "/";
}
}
if (!allowSlashesInActionNames && name != null) {
int pos = name.lastIndexOf('/');
if (pos > -1 && pos < name.length() - 1) {
name = name.substring(pos + 1);
}
}
mapping.setNamespace(namespace);
mapping.setName(name);
}
Parses the name and namespace from the uri |
public void setAllowDynamicMethodCalls(String allow) {
allowDynamicMethodCalls = "true".equals(allow);
}
|
public void setAlwaysSelectFullNamespace(String val) {
this.alwaysSelectFullNamespace = "true".equals(val);
}
|
public void setContainer(Container container) {
this.container = container;
}
|
public void setExtensions(String extensions) {
if (extensions != null && !"".equals(extensions)) {
List< String > list = new ArrayList< String >();
String[] tokens = extensions.split(",");
for (String token : tokens) {
list.add(token);
}
if (extensions.endsWith(",")) {
list.add("");
}
this.extensions = Collections.unmodifiableList(list);
} else {
this.extensions = null;
}
}
|
public void setSlashesInActionNames(String allow) {
allowSlashesInActionNames = "true".equals(allow);
}
|