FileDocCategorySizeDatePackage
DefaultActionMapper.javaAPI DocExample18273Mon Jul 23 13:26:36 BST 2007org.apache.struts2.dispatcher.mapper

DefaultActionMapper

public class DefaultActionMapper extends Object implements ActionMapper
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.exection.

To help with dealing with buttons and other related requirements, this mapper (and other {@link 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 - redirect-action: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 -->
<a:form action="baz">
<a:textfield label="Enter your name" name="person.name"/>
<a:submit value="Create person"/>
<a:submit name="method:anotherMethod" value="Cancel"/>
</a: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 -->
<a:form action="baz">
<a:textfield label="Enter your name" name="person.name"/>
<a:submit value="Create person"/>
<a:submit name="action:anotherAction" value="Cancel"/>
</a: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 -->
<a:form action="baz">
<a:textfield label="Enter your name" name="person.name"/>
<a:submit value="Create person"/>
<a:submit name="redirect:www.google.com" value="Cancel"/>
</a: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 -->
<a:form action="baz">
<a:textfield label="Enter your name" name="person.name"/>
<a:submit value="Create person"/>
<a:submit name="redirect-action:dashboard" value="Cancel"/>
</a:form>
<!-- END SNIPPET: redirect-action-example -->

Fields Summary
static final String
METHOD_PREFIX
static final String
ACTION_PREFIX
static final String
REDIRECT_PREFIX
static final String
REDIRECT_ACTION_PREFIX
private boolean
allowDynamicMethodCalls
private boolean
allowSlashesInActionNames
private boolean
alwaysSelectFullNamespace
private org.apache.struts2.util.PrefixTrie
prefixTrie
List
extensions
private com.opensymphony.xwork2.inject.Container
container
Constructors Summary
public DefaultActionMapper()


      
        prefixTrie = new PrefixTrie() {
            {
                put(METHOD_PREFIX, new ParameterAction() {
                    public void execute(String key, ActionMapping mapping) {
                        mapping
                                .setMethod(key
                                        .substring(METHOD_PREFIX.length()));
                    }
                });

                put(ACTION_PREFIX, new ParameterAction() {
                    public void execute(String key, ActionMapping mapping) {
                        String name = key.substring(ACTION_PREFIX.length());
                        if (allowDynamicMethodCalls) {
                            int bang = name.indexOf('!");
                            if (bang != -1) {
                                String method = name.substring(bang + 1);
                                mapping.setMethod(method);
                                name = name.substring(0, bang);
                            }
                        }
                        mapping.setName(name);
                    }
                });

                put(REDIRECT_PREFIX, new ParameterAction() {
                    public void execute(String key, ActionMapping mapping) {
                        ServletRedirectResult redirect = new ServletRedirectResult();
                        container.inject(redirect);
                        redirect.setLocation(key.substring(REDIRECT_PREFIX
                                .length()));
                        mapping.setResult(redirect);
                    }
                });

                put(REDIRECT_ACTION_PREFIX, new ParameterAction() {
                    public void execute(String key, ActionMapping mapping) {
                        String location = key.substring(REDIRECT_ACTION_PREFIX
                                .length());
                        ServletRedirectResult redirect = new ServletRedirectResult();
                        container.inject(redirect);
                        String extension = getDefaultExtension();
                        if (extension != null) {
                            location += "." + extension;
                        }
                        redirect.setLocation(location);
                        mapping.setResult(redirect);
                    }
                });
            }
        };
    
Methods Summary
java.lang.StringdropExtension(java.lang.String name)
Drops the extension from the action name

param
name The action name
return
The action name without its extension

        if (extensions == null) {
            return name;
        }
        Iterator it = extensions.iterator();
        while (it.hasNext()) {
            String extension = "." + (String) it.next();
            if (name.endsWith(extension)) {
                name = name.substring(0, name.length() - extension.length());
                return name;
            }
        }
        return null;
    
java.lang.StringgetDefaultExtension()
Returns null if no extension is specified.

        if (extensions == null) {
            return null;
        } else {
            return (String) extensions.get(0);
        }
    
public ActionMappinggetMapping(javax.servlet.http.HttpServletRequest request, com.opensymphony.xwork2.config.ConfigurationManager configManager)

        ActionMapping mapping = new ActionMapping();
        String uri = getUri(request);

        uri = dropExtension(uri);
        if (uri == null) {
            return null;
        }

        parseNameAndNamespace(uri, mapping, configManager);

        handleSpecialParameters(request, mapping);

        if (mapping.getName() == null) {
            return null;
        }

        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;
    
java.lang.StringgetUri(javax.servlet.http.HttpServletRequest request)
Gets the uri from the request

param
request The request
return
The uri

        // 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());
    
public java.lang.StringgetUriFromActionMapping(ActionMapping mapping)

        StringBuffer uri = new StringBuffer();

        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 = getDefaultExtension();
        if (extension != null) {
            if (uri.indexOf('." + extension) == -1) {
                uri.append(".").append(extension);
                if (params.length() > 0) {
                    uri.append(params);
                }
            }
        }

        return uri.toString();
    
public voidhandleSpecialParameters(javax.servlet.http.HttpServletRequest request, ActionMapping mapping)
Special parameters, as described in the class-level comment, are searched for and handled.

param
request The request
param
mapping The action 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;
                }
            }
        }
    
public booleanisSlashesInActionNames()

		return allowSlashesInActionNames;
	
voidparseNameAndNamespace(java.lang.String uri, ActionMapping mapping, com.opensymphony.xwork2.config.ConfigurationManager configManager)
Parses the name and namespace from the uri

param
uri The uri
param
mapping The action mapping to populate

        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 = "";
            // Find the longest matching namespace, defaulting to the default
            for (Iterator i = config.getPackageConfigs().values().iterator(); i
                    .hasNext();) {
                String ns = ((PackageConfig) i.next()).getNamespace();
                if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/")) {
                    if (ns.length() > namespace.length()) {
                        namespace = ns;
                    }
                }
            }

            name = uri.substring(namespace.length() + 1);
        }

        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);
    
public voidsetAllowDynamicMethodCalls(java.lang.String allow)

        allowDynamicMethodCalls = "true".equals(allow);
    
public voidsetAlwaysSelectFullNamespace(java.lang.String val)

        this.alwaysSelectFullNamespace = "true".equals(val);
    
public voidsetContainer(com.opensymphony.xwork2.inject.Container container)

        this.container = container;
    
public voidsetExtensions(java.lang.String extensions)

        if (!"".equals(extensions)) {
            this.extensions = Arrays.asList(extensions.split(","));
        } else {
            this.extensions = null;
        }
    
public voidsetSlashesInActionNames(java.lang.String allow)

        allowSlashesInActionNames = "true".equals(allow);