On 12/9/05, Ted Husted <[EMAIL PROTECTED]> wrote:
>
> On 12/8/05, Martin Cooper <[EMAIL PROTECTED]> wrote:
> > We don't have any of our own Action classes in the main app that's under
> > heavy development right now. It's all chains and commands. Most of our
> > action mappings correspond to a chain of two commands, where the first
> deals
> > with the incoming request and the second deals with preparing for the
> > response. In some cases, we have chunks of prep work that are reused
> across
> > multiple response types, so we break those out into additional commands.
>
> We do much the same. We extended the Catalog so that it can be used to
> run Commands. When we run a Command via our exended Catalog, it
> utilizes a standard "preopt" Chain and a "postopt" Chain to wrap the
> Command (or chain) that we actually want to run, creating a request
> processor on the business layer. The wrapping is done by creating a
> new Chain at runtime, with the instant command in the middle, and
> executing that. No fancy wiring :)
>
> WebWork does much the same thing with Interceptors. The main
> difference seems to be that Inteceptors have the notion of "before"
> and "after" (or preopt and postopt) built in. In a WebWork
> application, each action can reuse or extend the default request
> processor ("Inteceptor stack"), or declare its own.
>
>
> > It's interesting to compare this approach with what we did at my last
> > company, before we had this handy dandy chain doodad to play with.
> There, I
> > created a request handler / display handler dual that was similar in
> effect
> > to what I described above. In some ways, Chain saved me from having to
> > recreate that.
>
> In my travels, I often see companies building internal frameworks to
> fill the role of Chain, and WebWork did much the same thing with
> Inteceptors. Inteceptors just beg the question, "What am I
> intercepting?" ::). In Chain, everything is a Command that can be
> composed into a Chain (or "stack"), and "interception" is a relative
> term.
>
>
> > On the other hand, the way chains handle context makes them
> > sometimes too flexible, making code reviews more important when the
> compiler
> > isn't doing the design checking for you. ;-)
>
> One cure for that is to extend Context and Command "in anger", with
> whatever design niceities you like, starting by extending execute to
> call your own instance of Context.
>
>                 public abstract boolean myExecute(MyContext context);
>
>                 public  boolean execute(Context _context)
>                 {
>                         MyContext context = (MyContext) _context;
>                         return myExecute(context);
>                 }
>
> Context may be a Map, but it can also have whatever type-safe
> properties and other helper methods you might need.


Right, and we have some of that. But that's in part what I meant about code
reviews being more important, because some developer who 'just wants to make
it work" could simply avoid extending that flavour of command and extend the
base one instead, thus circumventing the design intent.

The solution at my last company required that each "chain" be composed of
(zero or) one request handler followed by (zero or) one display handler,
where the handlers were two distinct types, with access to only those things
they should have access to. Circumventing that would have required
abandoning all of the infrastructure around it and implementing a raw
Action.

I don't think one of these approaches is better than the other. It's horses
for courses. But in these days of bringing in cheap and often inexperienced
help to "get it done", I'm always looking for ways to enforce the design
rather than just encouraging people to follow it. ;-)

--
Martin Cooper


Here, we've extended Context to include Struts-like error-handling:
>
> * http://tinyurl.com/cgqe9
>
> so that the business layer can report back to the presentation layer.
>
> Here, we've extended Command to support validation and persistence.
>
> * http://tinyurl.com/drzor
>
> What I've really enjoyed about working with Chain is that it's easy to
> catch and retain any errors. We do this by using the Catalog like a
> Controller and giving it an Execute method of its own. If an error
> occurs, it crams the message into the "Fault" property built into our
> Context.
>
>                 public void ExecuteRequest(IRequestContext context)
>                 {
>                         IRequestCommand command = VerifyRequest(context);
>                         if (context.IsNominal)
>                         {
>                                 try
>                                 {
>                                         command.Execute(context);
>                                 }
>                                 catch (Exception e)
>                                 {
>                                         context.Fault = e;
>                                 }
>                         }
>
>                 }
>
> Then, in a test, it's easy to check to see if an Exception were thrown
>
>                 public void AssertNoFault(IRequestContext context)
>                 {
>                         bool hasFault = context.HasFault;
>                         if (hasFault)
>                                 Assert.Fail(context.Fault.Message);
>                 }
>
> In an application, it's just as easy to display *any* exception as a
> global validation error, without extra coding.
>
> >
> > --
> > Martin Cooper
>
> -Ted.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>

Reply via email to