John Yu wrote:
> I'm wondering if it makes sense to extend Struts' mapping architecture
> so that it will also look into a 'magic' url parameter and dispatch
> accordingly.
>
> For example, if the URL is
>
> MyAction.do?subAction=Create
>
> the ActionServlet will dispatch the request to the MyActionCreate
> class given the following (enhanced) action mapping.
>
> <action path="MyAction" subAction="Create" type="MyActionCreate"
> .../>
Actions can forward to other ActionMappings, if the mappings are exposed
as ActionForwards. If that's something you would like to do, you can use
a generic dispatcher that would look for the "subaction" parameter and
return the appropriate forward to another mapping.
Here's an example perform() that can forward anywhere given
"/do/Dispatch?forward=forwardName".
// -- Locals
ActionForward thisForward = null;
String wantForward = null;
// -- Check check request for forward
wantForward = request.getParameter("forward");
// -- If found, consult mappings
if (wantForward!=null)
thisForward = mapping.findForward(wantForward);
// -- If anything not found, dispatch error
if (thisForward==null) {
thisForward = mapping.findForward("error");
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("action.missing.parameter"));
saveErrors(request, errors);
}
return thisForward;
Here's a simple "Hello World" action to test it:
response.setContentType("text/plain");
PrintWriter writer = response.getWriter();
writer.println("Hello from: " + mapping.getPath());
return(null);
And some sample mappings:
<!-- Dispatcher action mapping -->
<action
path="/Dispatch"
type="ext.http.DispatchForward"
scope="request"
validate="false">
<forward
name="test1"
path="/do/Test1"/>
<forward
name="test2"
path="/do/Test2"/>
</action>
<action
path="/Test1"
type="ext.http.Test1"
scope="request"
validate="false">
</action>
<action
path="/Test2"
type="ext.http.Test1"
scope="request"
validate="false">
</action>
If you ask for "do/Dispatch?task=test1" you get "Hello from test1" if
you open "do/Dispatch?task=test2" you get "Hello from test2". (Note that
an Action knows which path is used to call it, which is another way you
can have Actions do different things based on the mapping context.)
I only just wrote this, and it seems OK, but be warned that it is alpha
code ;o)
A couple of things to keep in mind:
+ You never really call an Action. You reference an ActionMapping, and
the Controller calls the Action from that.
+ The ActionForms are populated from the request when the controller
invokes the Action for a mapping. So if you forward the request to
another mapping, it would populate the form for that mapping from the
forwarded request.
+ Actions are not bound to ActionForms. The form is bound by the
ActionMapping, and an Action can be used in any number of mappings.
+ Many times developers use the same or related names for an Action and
the path to an ActionMapping. That is only a convenience. In Struts, you
can only specify a "logical" path to an ActionMapping. What is behind
that mapping is determined by the configuration file, and therefore
belongs to the controller layer.
Meanwhile ... a similar thing to the DispatchForward class given above
can be done using the optional DispatchAction class in Struts 1.0
(org.apache.struts.actions.DispatchAction). Here you can create
alternate "perform" methods in a single action, and call one or the
another in the request. So you could have
public ActionForward retrieve(ActionMapping mapping, ...
public ActionForward update(ActionMapping mapping, ...
and then call one or the other using "myDispatchAction?method=retrieve"
or "myDispatchAction?method=update". See the Struts JavaDoc for details.
Very neat, really.
-Ted.