Struts2 needs a new AliasInterceptor


Written on April 16, 2008 – 11:00 am | by mpayne

The original aliasInteceptor works fine for gluing together actions with different parameter names that need to be clued together.  The limitation with the existing solution is that properties for both name an alias need to exist in the stack. 

The world keeps evolving though.  Developers make frequent use of richer javascript widgets such as jQuery’s flexgrid or jqGrid. These widgets can consume a specific JSON response and dish out their own unique set of named parameters to the server side.  This presents a challenge when trying to leverage existing back end code that works great, it just doesn’t match up name wise to the parameters names coming in for a specific view.

Assume one has a some abstract PagingQueryAction(children just set query/queryCount implementations) that can accept incoming parameters of:
   
    int pageSize = 10;  // results per page, default 10
    int currentPage;
    String filter;
    String sortorder = “asc”;
    String sortname = “”;

This works fine and dandy for some existing web views, but if one wanted to make use of FlexGrid, they would create setters named.

page 3
qtype name
query
rp 15
sortname iso
sortorder asc

jqGrid has yet another set of name parameters that its submits.

Making new implementations of things because some UI widgets is hardcoded to respond with a specfic set can be a PITA. 

If there existed an AliasInterceptor that would allow one to adapt to these widget requirements people would have another solution at their disposal.

example of a mapping:

<!– usaged
  <param name=”aliases”>#{ ‘incomingName’ : ‘actionPropertyName’}</param>
–>
    <package name=”json” extends=”inventoryDefault” namespace=”/json”>
            <action name=”summaryPagedJSON” class=”stateSummary”>
                 <param name=”pageSize”>15</param> <!– change default here –>
                 <param name=”aliases”>#{ ‘query’ : ‘filter’, ‘rp’:'pageSize’,'page’:'currentPage’ }</param>

                <result name=”success” type=”freemarker”>
                    json-pageSummary.ftl
                </result>
                <result name=”input” type=”freemarker”>
                    json-pageSummary.ftl
                </result>
            </action>
   
If one wanted to adapt the paging action for jqGrid, they’d simply need to
supply an alias parameter of:
  <param name=”aliases”>#{ ’searchString’ : ‘filter’,'page’:'currentPage’, ’sord’:’sortorder’, ’sidx’:’sortname’ }</param>

(Note the freemarker template producing the JSON response may need to differ slighty as well)

This proposed alias interceptor looks for the alias within “invocationParameters” instead of the stack.
Perhaps we need to rename things.  The old AliasInterceptor is name ChainingAliasInterceptor
and the new one is ParameterAliasInterceptor.
Or perhaps the alias functionality should just be built in to the existing ParameterInterceptor.

snippet below
  @Override
    public String intercept(ActionInvocation invocation) throws Exception {

    ActionConfig config = invocation.getProxy().getConfig();
    ActionContext ac = invocation.getInvocationContext();

    // get the action’s parameters
    final Map configParameters = config.getParams();
    final Map invocationParameters = ac.getParameters();

    if (configParameters.containsKey(aliasesKey)) {

        String aliasExpression = (String) configParameters.get(aliasesKey);
        OgnlValueStack stack = (OgnlValueStack) ac.getValueStack();
        Object obj = stack.findValue(aliasExpression);

        if (obj != null && obj instanceof Map) {
        // override
        Map aliases = (Map) obj;
        Iterator itr = aliases.entrySet().iterator();
        while (itr.hasNext()) {
            Map.Entry entry = (Map.Entry) itr.next();
            String alias = entry.getKey().toString();
            String setterName = (String) entry.getValue();
       
            Object value = invocationParameters.get(alias);
            if (null != value) {
            stack.setValue(setterName, value);
           
            }
        }
        } else {
        log.debug(”invalid alias expression:” + aliasesKey);
        }
    }

    return invocation.invoke();
    }

Post a Comment