> -----Original Message-----
> From: Ted Husted [mailto:[EMAIL PROTECTED]]
> So, if we're talking about one ActionMapping forwarding (or 
> redirecting) to another ActionMapping, then sure. Everything is 
> above board, and you can follow the bouncing ball through the 
> Struts Config and see what's happening. 

Ah, that's what I use.  I think.  That is, if I'm going to cause two
different Actions' perform() methods to be invoked during the same browser
request, then I always do it via a mapping.findForward(XYZ) call instead of
a new ActionForward(someComputedString) call.

> But, then there's Action chaining. Here, people have an Action 
> class create an ActionForward on the fly, jam in some parameters, 
> and toss it back to the controller. This is where Action classes 
> start binding to Action classes, and the mudslide begins. 

Agreed.  Mudslides are kind of tasty, though.

> It's my feeling that if Action classes start creating query 
> strings and need to be coded in terms of what they need to send to 
> the "next" Action, then you're starting to use Action classes to 
> implement a business facade. Action classes should be clients of 
> the facade, not the facade itself.

One variation on this that I don't think suffers from the same problems is
to do something like:

  // Work has completed by this point, let's say.
  request.setAttribute(resultOfWork);
  return mapping.findForward(DONE);

...where the "next" Action selected by the ActionMapping may very well be
expecting resultOfWork to be present as a request attribute for
presentation/UI-layer purposes only.  That is, the semantics of putting
resultOfWork into the request must not require that there be a "next"
Action--it's just something this Action has to do, regardless of whether
someone else down the line consumes it or not.

> In the current example, using an ActionMapping to call a 
> DeleteAction and have it route back to some list afterwards seems 
> fine to me. So, long as the DeleteAction doesn't know or care if 
> its going back to a particular list or a given form. IMHO, an 
> Action class should just return a simple semantic like "success", 
> "failure", "cancel", and so forth, and let the ActionMapping 
> decide how to handle the given gesture. 

Right; Actions are web GUI EventListeners.  The difference between this (and
lots of other web-centric) event handling system and the Java beans event
handling system is that the event type is basically the same: you get a
request event that has a logical hashtable in it of parameters and values,
and an identifier (the path) that tells you what kind of event it is.

> And following Laird's example, an application could also include a 
> workflow engine that would return a semantic to go get the 
> whatchacallit. But the ActionMappings would hook up the semantic 
> with the actual URI. The real "presentation logic" is that there's 
> a JSP stored at /WEB-INF/pages/whatchacallit. On top of that, 
> there's application/workflow logic that might say the semantic 
> "whatchamcallit" should display the form that collects the 
> whatchallit property.

Minor quibble: in my mind, the *application* doesn't say to display
anything.  The presentation layer, which for these purposes I'm separating
from the application, does.  I only make this point because to me what
you're calling the application workflow is really a property of the
GUI/presentation layer, not the application.  From my previous example, the
application domain/business logic domain begins when the frobnicate() method
is called, and ends once it returns.  All the machinery to gather the
requisite parameters and to render the response is presentation logic.  Call
it workflow if you must, but it's not workflow that's essential to the task
(that of frobnication :-)) at hand.

> Where things get messy is that sometimes people come up with a 
> multi-step server-side workflow, where they want to, say, copy and 
> delete (or move) a record, and then return to a list. So you got 
> the copy action looking at some flag that says "do delete next", 
> and so it sets something in the request or action form, and 
> forwards on to delete, which then looks at something that tells it 
> to forward on to a list.  

You must have been looking at some of the code that I'm currently forced to
maintain.  :-)

> The business facade is your application's 
> internal API. It defines what the application can do, what it 
> needs to do it, and what it returns when something is done. The 
> Action classes interact with the business facade by allowing 
> access to the facade from the web tier. Other tiers could also 
> interact with the same facade from other platforms.

Yes, exactly.  One of the things I was trying to articulate (badly) in an
earlier message was that if you do this right, you can swap out GUIs at
configuration time.  The way that I'm currently trying to do this is by
approaching application design from an event perspective ("what events
should any GUI for this application be expected to fire to the application
itself?").  You set up a central event registry for these things, and have
that central event registry also register listeners for those events.  The
benefits of this approach are that you absolutely and totally enforce
separation between the gymnastics you go through on the presentation layer
from those you go through on the business layer--if the presentation layer
can only talk to the business layer via these centrally defined events, then
the task becomes, how do I use my GUI toolkit to generate these events and
listen for application events coming back from the business tier?

So my Actions for this application are not necessarily super *simple*, but
all that they do is to take the presentation layer data (ActionForms, paths,
URLs, ActionMappings, ActionForwards, notions of "pages", sessions, etc.)
and convert, munge, mash and translate it into Java beans event data ("get
the request parameter; find the user data; etc.; fire a SaveUserDataEvent
instance to all registered listeners).  Then another method on the Action
listens for the "return" event (UserDataSavedEvent) that's fired by the
business tier.  So all the application knows is that some UI somewhere fired
a SaveUserDataEvent, and when that happens it knows to save the user data
and fire a UserDataSavedEvent in return.

You can see that to make this work with Swing all you have to do is hook up
a bunch of ButtonListeners and the like and get them to fire
SaveUserDataEvents in turn, and no application layer code needs to change.

(I'm currently using this approach for a for-fun maunscript tracking
software program that I'm writing--one set of customers wants it to be web
based, and the other set wants it to be a desktop application.  If I pull
this off, I can web enable it by dropping different UI jars into place with
the application's core jar and it should just work.)

Cheers,
Laird

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

Reply via email to