You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by ar...@cornell.edu on 2003/04/29 14:08:12 UTC

Local Actions and reusability

Hi all,

  I have a feature request (hopefully novel) that I think is easy to 
implement and will streamline my, and I imagine many others', web 
applications.

  I would like to propose adding an optional "id" attribute to the Action 
tag in struts-config.xml, and also a mechanism by which to lookup such 
actions _by id_ as opposed to by path (e.g., by either adding a 
"findInternalForward(String id)" method to ActionMapping, or by a 
policy, for example "paths prefixed with / will be looked up by path 
attribute, otherwise id attribute").  Path attribute would then be optional.

  Nothing changes for actions configured in the normal manner with 
paths.  These actions are visible and routable from direct HTTP 
requests.  On the other hand, adding an 'id' attribute now allows us to 
look up and forward to Actions which are configured but are NOT visible 
to the world, hence "local".

  The utility is as follows: we can now chain multiple non-visible 
Actions without having to define legitimate but unused public paths for 
various actions.  For example, I want to perform a certain universal Action 
for every web page, but then I want to perform certain reusable Actions 
depending on, say, GET parameters.  I can easily write an 
ActionDispatchAction (mostly copy + past DispatchAction) which forwards 
to an internal Action based on GET parameter.  My first mapping forwards 
to my universal action, which then forwards to my ActionDispatchAction, 
which then forwards to the view.  Both the universal and 
ActionDispatchAction could be set up as "local" Actions that are not 
routable by initial HTTP request (it would make no sense to), yet can 
still be chained together, or furthermore, reused by many other Actions.  
The final Action in the chain could even render the content itself!  
Philosophical issues aside, this is often a *very* elegant thing to do, and 
for example, in my specific case, if this suggestion were implemented, my 
entire application could be reduced to a struts-config.xml and a set of 
Actions (some of which were "local"), chained together, the final of which 
is some sort of "render" Action (trust me, my display is complicated enough 
to demand a purely programmitic rendering).

Right now, I have been able to "emulate" this behavior by having action 
definitions forward to other action mappings, bound to fictitious, yet 
world-routable names.  Yes this is very awkward, as I cannot define 
"path-less" actions, so my ActionDispatchAction just creates the Action 
objects itself directly, and then must call setServlet() on them, and 
these cannot them forward back to other Actions defined in such a manner 
(because the ActionMapping will not know anything about them).

Thoughts?

Aaron Hamid
CIT/I&D
Cornell University

---------------------------------------------------------------------
To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: struts-user-help@jakarta.apache.org


Re: Local Actions and reusability

Posted by Aaron R Hamid <ar...@cornell.edu>.
Comments inline

> On Tue, 29 Apr 2003 arh14@cornell.edu wrote:
>
>> Date: Tue, 29 Apr 2003 13:34:31 -0400 (EDT)
>> From: arh14@cornell.edu
>>
>>[SNIP]
>> All that is required is
>> a type of
>> "ActionForward" which does not forward back through the servlet
>> engine, but instead back through another configured Action...I haven't
>> looked at the code (although I've seen pseudo-code description), but
>> this has to be at most a few lines of code.
>>
>> while (actionforward.isLocal()) {
>>   actionforward = actionforward.getLocalAction().execute(mapping,
>> form,
>> request, response); }
>> }
>>
>
> This approach doesn't support the "I'm finished now, so stop delegating
> to any more local actions" mechanism of the Chain of Responsibility
> pattern.

Once an Action returns a non-local ActionForward it will.

> This approach ignores any ActionForward returned by any action other
> than the last one, which violates the assumptions that any Struts
> developer building actions is going to make.

This mystifies me. Struts currently already does not support "any
ActionForward returned by any action other than the last one" because it
only supports ONE Action at a time, which is the last one.  The sample
loop above executes every Action in sequence until a non-local
ActionForward is encountered.

> This approach locks your business logic into Struts APIs (and therefore
> the servlet API as well), making it basically impossible to use that
> logic anywhere else.

Of course nobody is *forcing* anybody to use this approach.  If you need
to implement a chain of responsibility that acts on the servlet request
and response, your classes are going to look very much like the Action
API, and you will end up having to reimplement much of Struts (i.e. your
own controller, your own configuration syntax for defining "actions",
etc.).

> Bottom line -- IMHO, this approach improperly mixes view-tier controller
> functionality (what Struts is for) and business logic controller
> functionality (which is a perfectly reasonable place to use Chain of
> Responsibility, but it should be based on generic APIs for that purpose
> -- not on org.apache.struts.action.Action).

Page transitions are not the only way to affect the view. I can affect the
view for example by submitting a request against the same page with
different parameters, in which case I am right back exactly in the
scenario of struts, delegating control to Actions.  If you have actions
that can be reused by many pages it will be much cleaner to implement
those actions once, than to create N x M action mappings.

Aaron

>
>> Aaron
>
> Craig
>
> --------------------------------------------------------------------- To
> unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org For
> additional commands, e-mail: struts-user-help@jakarta.apache.org




---------------------------------------------------------------------
To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: struts-user-help@jakarta.apache.org


Re: Local Actions and reusability

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On Tue, 29 Apr 2003 arh14@cornell.edu wrote:

> Date: Tue, 29 Apr 2003 13:34:31 -0400 (EDT)
> From: arh14@cornell.edu
> Reply-To: Struts Users Mailing List <st...@jakarta.apache.org>
> To: Struts Users Mailing List <st...@jakarta.apache.org>
> Subject: Re: Local Actions and reusability
>
>
> Yes, that exactly describes my situation.  In fact, I already *have* my
> own "chain of responsibility" classes, but they are integrated into a
> nasty JSP soup, and I am now taking time to step back and consider
> Struts.  What I realized is that the API of my "actions" (I call them
> WebActions), is almost exactly *identical* to the Struts Action API
> (really, all such an API needs is to take a request, response, and return
> a code or forward path).

Almost != Exactly.

  While I am currently "faking" chain of
> responsibility by defining non-public action mappings, and a fairly
> kludgy forwarding scheme, I realized with the *DispatchAction classes
> already available, that it would probably be very trivial to add a single
> attribute to the action mapping definition to achieve what I am trying to
> do.  I also think it does in fact fit with the Struts philosophy, it's
> just a generalization of it.  All that is required is a type of
> "ActionForward" which does not forward back through the servlet engine,
> but instead back through another configured Action...I haven't looked at
> the code (although I've seen pseudo-code description), but this has to be
> at most a few lines of code.
>
> while (actionforward.isLocal()) {
>   actionforward = actionforward.getLocalAction().execute(mapping, form,
> request, response); }
> }
>

This approach doesn't support the "I'm finished now, so stop delegating to
any more local actions" mechanism of the Chain of Responsibility pattern.

This approach ignores any ActionForward returned by any action other than
the last one, which violates the assumptions that any Struts developer
building actions is going to make.

This approach locks your business logic into Struts APIs (and therefore
the servlet API as well), making it basically impossible to use that logic
anywhere else.

Bottom line -- IMHO, this approach improperly mixes view-tier controller
functionality (what Struts is for) and business logic controller
functionality (which is a perfectly reasonable place to use Chain of
Responsibility, but it should be based on generic APIs for that purpose --
not on org.apache.struts.action.Action).

> Aaron

Craig

---------------------------------------------------------------------
To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: struts-user-help@jakarta.apache.org


Re: Local Actions and reusability

Posted by ar...@cornell.edu.
I see how I can go about this now...due to the pluggable nature of struts 
I should be able to define new ActionMapping, RequestProcessor, and 
ActionForward implementations... however it appears that ModuleConfig is 
not yet pluggable, so there is no clean way to modify that implementation.

The way I'd go about this is to relax the requirement of path 
attribute on the action.  A ModuleConfig implementation could then be 
enhanced with findActionConfigById().  If I followed the trail of 
deprecations correctly, forwards to local actions would simply imply 
configuring the className of the forward definition to use something like 
LocalActionForward.  A RequestProcessor subclass could then override 
'processActionPerform' method, to do a simple check in a loop and execute 
any forwards of LocalActionForward type in sequence.  So given that 
ModuleConfig becomes pluggable, all this can be done cleanly without mods 
to Struts codebase itself.

Are there any plans for the completing the pluggability of ModuleConfig?

Aaron

On Tue, 29 Apr 2003 arh14@cornell.edu wrote:

> 
> Yes, that exactly describes my situation.  In fact, I already *have* my 
> own "chain of responsibility" classes, but they are integrated into a 
> nasty JSP soup, and I am now taking time to step back and consider 
> Struts.  What I realized is that the API of my "actions" (I call them 
> WebActions), is almost exactly *identical* to the Struts Action API 
> (really, all such an API needs is to take a request, response, and return 
> a code or forward path).  While I am currently "faking" chain of 
> responsibility by defining non-public action mappings, and a fairly 
> kludgy forwarding scheme, I realized with the *DispatchAction classes 
> already available, that it would probably be very trivial to add a single 
> attribute to the action mapping definition to achieve what I am trying to 
> do.  I also think it does in fact fit with the Struts philosophy, it's 
> just a generalization of it.  All that is required is a type of 
> "ActionForward" which does not forward back through the servlet engine, 
> but instead back through another configured Action...I haven't looked at 
> the code (although I've seen pseudo-code description), but this has to be 
> at most a few lines of code.
> 
> while (actionforward.isLocal()) {
>   actionforward = actionforward.getLocalAction().execute(mapping, form, 
> request, response); }
> }
> 
> Aaron

---------------------------------------------------------------------
To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: struts-user-help@jakarta.apache.org


Re: Local Actions and reusability

Posted by ar...@cornell.edu.
Yes, that exactly describes my situation.  In fact, I already *have* my 
own "chain of responsibility" classes, but they are integrated into a 
nasty JSP soup, and I am now taking time to step back and consider 
Struts.  What I realized is that the API of my "actions" (I call them 
WebActions), is almost exactly *identical* to the Struts Action API 
(really, all such an API needs is to take a request, response, and return 
a code or forward path).  While I am currently "faking" chain of 
responsibility by defining non-public action mappings, and a fairly 
kludgy forwarding scheme, I realized with the *DispatchAction classes 
already available, that it would probably be very trivial to add a single 
attribute to the action mapping definition to achieve what I am trying to 
do.  I also think it does in fact fit with the Struts philosophy, it's 
just a generalization of it.  All that is required is a type of 
"ActionForward" which does not forward back through the servlet engine, 
but instead back through another configured Action...I haven't looked at 
the code (although I've seen pseudo-code description), but this has to be 
at most a few lines of code.

while (actionforward.isLocal()) {
  actionforward = actionforward.getLocalAction().execute(mapping, form, 
request, response); }
}

Aaron

On Tue, 29 Apr 2003, Craig R. McClanahan wrote:

> 
> 
> On Tue, 29 Apr 2003 arh14@cornell.edu wrote:
> 
> > Date: Tue, 29 Apr 2003 08:08:12 -0400 (EDT)
> > From: arh14@cornell.edu
> > Reply-To: Struts Users Mailing List <st...@jakarta.apache.org>
> > To: struts-user@jakarta.apache.org
> > Subject: Local Actions and reusability
> >
> >
> > Hi all,
> >
> >   I have a feature request (hopefully novel) that I think is easy to
> > implement and will streamline my, and I imagine many others', web
> > applications.
> >
> 
> I haven't heard of this particular approach to it (and you could fake it
> by protecting "local" paths with security constraints anyway), but what
> you're trying to accomplish isn't totally novel :-).
> 
> What you're describing is a mechanism to set up a Chain of Responsibility
> pattern between actions.  As a conceptual entity, there's nothing at all
> wrong with this pattern -- it has many attractions.  However, the Action
> mechanisms in Struts are *not* built around this concept, and trying to
> build chains of actions often causes unintended behavior, because Struts
> repeats the entire request processing lifecycle for each action that is
> called (populating new form beans, validation, and all the rest) -- this
> is not what most people really want.
> 
> Furthermore, a classic Chain of Responsibility implementation hands
> processing off to subsequent steps until one of them says "Ok, I finished
> all the processing for this request; you can stop following the chain
> now."  The existing Action API doesn't have any good way to emulate this,
> which makes Action instances unsuitable for chaining even without the
> redundant request processing problems mentioned above.
> 
> Instead, I strongly suggest that you factor the business logic embedded
> into your actions out into separate classes.  Then, build a simple chain
> of resposibility controller (perhaps configured from an XML file)
> *underneath* a single Struts Action.  That way, you get the reuse and
> composability of business logic that you are after, but without all the
> unintended consequences.
> 
> Chain of Responsibility is good.  Chain of Actions is not good.  :-)
> 
> Craig McClanahan
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: struts-user-help@jakarta.apache.org
> 
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: struts-user-help@jakarta.apache.org


Re: Local Actions and reusability

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On Tue, 29 Apr 2003 arh14@cornell.edu wrote:

> Date: Tue, 29 Apr 2003 08:08:12 -0400 (EDT)
> From: arh14@cornell.edu
> Reply-To: Struts Users Mailing List <st...@jakarta.apache.org>
> To: struts-user@jakarta.apache.org
> Subject: Local Actions and reusability
>
>
> Hi all,
>
>   I have a feature request (hopefully novel) that I think is easy to
> implement and will streamline my, and I imagine many others', web
> applications.
>

I haven't heard of this particular approach to it (and you could fake it
by protecting "local" paths with security constraints anyway), but what
you're trying to accomplish isn't totally novel :-).

What you're describing is a mechanism to set up a Chain of Responsibility
pattern between actions.  As a conceptual entity, there's nothing at all
wrong with this pattern -- it has many attractions.  However, the Action
mechanisms in Struts are *not* built around this concept, and trying to
build chains of actions often causes unintended behavior, because Struts
repeats the entire request processing lifecycle for each action that is
called (populating new form beans, validation, and all the rest) -- this
is not what most people really want.

Furthermore, a classic Chain of Responsibility implementation hands
processing off to subsequent steps until one of them says "Ok, I finished
all the processing for this request; you can stop following the chain
now."  The existing Action API doesn't have any good way to emulate this,
which makes Action instances unsuitable for chaining even without the
redundant request processing problems mentioned above.

Instead, I strongly suggest that you factor the business logic embedded
into your actions out into separate classes.  Then, build a simple chain
of resposibility controller (perhaps configured from an XML file)
*underneath* a single Struts Action.  That way, you get the reuse and
composability of business logic that you are after, but without all the
unintended consequences.

Chain of Responsibility is good.  Chain of Actions is not good.  :-)

Craig McClanahan


---------------------------------------------------------------------
To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: struts-user-help@jakarta.apache.org