List-

I'm looking for ideas on implementing a published interface for action
mappings. By publishing an interface, I mean to define (preferably in the
action mapping itself) what parameters the action class is expecting to be
available, to avoid having to scan through the class to determine what
parameters it is expecting in the request. I've recently discovered the
<set-property> tag (I'm always the last to know.) for defining attributes of
a mapping outside the struts-config DTD.

After playing around with the idea for a few hours, I came up with the
following:

Extended mapping-
-------------------------------
First step is to extend the ActionMapping class. In addition to the stand
action mapping properties and method, you will define a bean pattern for
property "params". Because there are N-number of params possible, the
implementation of this property would be something like:

< ExtendedActionMapping.java >
public class ExtendedActionMapping extends ActionMapping {
    protected ArrayList params = new ArrayList();
    public void setParams(String value) {
        params.add(value);
    }
    public String[] getParams() {
        return (params.toArray(new String[params.size()]));
    }
}
< / ExtendedActionMapping.java >

The web.xml for your action servlet should be modified to specify this class
for your action mapping. Now that you've got this mapping set, the digester
can process a mapping like:

<action path="/blah" type="MyAction">
    <set-property property="params" value="A-PARAM"/>
</action>

Dynamic params-
-------------------------------
Because the set-property interface allows you to specify only a property and
it's string value, it's necessary to provide a means to define more detail
about your params. For example- your param could be expected as a request
parameter, or possibly as a property of a session-scoped form bean
unassociated with the mapping you are defining. It would also be nice if the
actual param values were provided to the action instead of just the name of
the variables.

So- instead of using <set-property> to declare just the variable name, we
get a little fancy. We'll use an expression which can be matched to an RE
pattern. For example, my action below is expecting a parameter (in the
request scope) called "locationId":

<action path="/blah" type="MyAction">
    <set-property property="params" value="request{locationId}"/>
    <set-property property="params" value="form{loginForm, userId}"/>
</action>

This string/expression "request{locationId}" will be available as a param in
the mapping instance. What good does that do us you might ask? Well, we'll
need to examine this "expression" and somehow retrieve the value it refers
to. To accomplish this, we'll need to sub-class a base action which has
implemented functionality to deal with these expressions. To help us parse
the expressions we have the following classes:

Params - a collection of Param instances. Params implements a "findParam"
method which matches an expression to a param instance:
findParam(expression) returns a Param

Param - an interface defining 2 methods:
    getPattern()- returns a regular expression pattern which matches
expressions this param is capable of handling
    getValue(expression, request)- parses the expression and uses the
request scope to retrieve the param value from
        whatever source necessary.

Here's a param example:

public class RequestParam implements Param {
    protected String pattern = "^request{([A-Za-z]*)}$";
    public String getPattern() { return this.pattern; }
    public String getName(expression) {
        RE re = new RE(getPattern());
        re.match(expression);
        return (re.getParen(1));
    }
    public String getValue(String expression, HttpRequest request) {
        RE re = new RE(getPattern());
        re.match(expression);
        String paramName = re.getParen(1);
        return (request.getParameter(paramName));
     }
}

The pattern for this class ("^request{([A-Za-z]*)}$") will match an
expression like: "request{locationId}". The responsibility of the Params
instance is to match this class with the defined param. Our RequestParam
class is then capable of parsing this expression to determine the name of
the desired request parameter. A similar implementation of this would be to
retrieve properties of form beans using a pattern like: "form{FORM-NAME,
PROPERTY}". Within the FormBeanParam class we would parse the expression to
determine that form bean name and the desired property. We could then use
the PropertyUtils to retrieve this value.

BaseAction-
------------------------
So back to our BaseAction implementation. The BaseAction will hold an
instance of the params collection. By placing the base action first in the
execution chain (i.e. by defining execute(mapping, form, request, response))
we have our processing hook. So we perform something like this:

public class BaseAction extends Action {

protected Params params = new Params();
public BaseAction() {
    params.addParam(new RequestParam());
    params.addParam(new FormBeanParam());
}

public ActionForward execute(mapping, form, request, response) {
    Hashtable paramMap = new Hashtable();
    if (mapping.getParams().length > 0) {
        String[] params = mapping.getParams();
        for (int i = 0; i < params.length; i++) {
            String expression = params[i];
            Param param = params.findParam(expression);
            paramMap.put(param.getName(expression),
param.getValue(expression));
        }
    }
    // Now we call our super-class action implementation, with our paramMap
in the signature.
    return (super.execute(mapping, form, paramMap, request, response));
}
}

So within our action, we now have a map of our expected parameters. Within
the base action, we might have thrown an exception or something if an
expected param could not be discovered, this negates the need for any logic
to check for the existance of parameters or the like within our action
class. Because we are using patterns to create a relationship to our
parameter logic, it's an easy matter to add another attribute to the
expression which declares a variable to be required, or not. You could even
define what exception is thrown when a parameter is not present (but that
would be going a little overboard)

Within our system at work, we use a method similar to this (just not as
flexible) to identify constants as parameters to actions. For example, when
building a link like:

<a href="/someaction.do?param=USER_ID">link</a>

One would generally need either a tag or some script to look up the user id
and add it to the link. What we've done instead is match this parameter
value to a logic implementation which is capable of returning the user id
value, and this behavior is completely transparent.

Any ideas? Responses?

thanks

Jason Stiefel
[EMAIL PROTECTED]




--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to