You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by Wendy Smoak <ws...@gmail.com> on 2005/12/09 02:26:06 UTC

Chain questions

I need help with Commons Chain and Struts in combination.  I've read
the Commons Chain docs, including the cookbook, which uses a
CommandAction in the Chain version of mailreader.

Then in Extras we have ChainAction and DispatchChainAction.  I assume
I'm supposed to use one of those instead of including a special Action
in my webapp.

The Javadocs for both of them suggest configuring a type from the
oas.chain.legacy package, which does not seem to exist.  For example:

http://struts.apache.org/struts-extras/apidocs/org/apache/struts/actions/DispatchChainAction.html
<action path="/myaction"
           type="org.apache.struts.chain.legacy.DispatchAction"
           name="myform"
          scope="request"
          ...

Is the Javadoc just wrong, or is there some history regarding the the
oas.chain.legacy package that I missed?

Would someone like to talk me out of wanting a
LookupDispatchChainAction? :)  I'm in the minority who has no problem
with LDA, and the app that could benefit from breaking up and reusing
the application logic makes heavy use of LookupDispatchAction.  I'm
not quite sure how I'm going to get from the button text to the right
command, but maybe it will become apparent when I actually try it.

Thanks,
--
Wendy

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


Re: Chain questions

Posted by Martin Cooper <ma...@apache.org>.
On 12/9/05, Ted Husted <te...@gmail.com> wrote:
>
> On 12/8/05, Martin Cooper <ma...@apache.org> 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: dev-unsubscribe@struts.apache.org
> For additional commands, e-mail: dev-help@struts.apache.org
>
>

Re: Chain questions

Posted by Ted Husted <te...@gmail.com>.
On 12/8/05, Martin Cooper <ma...@apache.org> 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.

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: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org


Re: Chain questions

Posted by Martin Cooper <ma...@apache.org>.
On 12/8/05, Joe Germuska <Jo...@germuska.com> wrote:
>
> At 6:26 PM -0700 12/8/05, Wendy Smoak wrote:
> >I need help with Commons Chain and Struts in combination.  I've read
> >the Commons Chain docs, including the cookbook, which uses a
> >CommandAction in the Chain version of mailreader.
> >
> >Then in Extras we have ChainAction and DispatchChainAction.  I assume
> >I'm supposed to use one of those instead of including a special Action
> >in my webapp.
>
>
> I suppose you could just use the "command" (and optionally "catalog")
> attribute of the action mapping and not specify any "type."  (Yet
> another way to do it!)


That's what we (at my day job) would be using if we were on 1.3.x. Since
we're on 1.2.8, though, we use ChainAction to get (almost) the same effect.
It worries some people that ChainAction is in a "legacy" package, and there
are issues with non-default catalogs, but for the most part it works very
well.

If you're using a Chain action, then why would you want dispatch
> also?  Are you talking about dispatching to a chain, instead of
> dispatching to a method by reflection?  If that's the case, you could
> do it using the commons-chain Lookup Command, although it might be
> more elegant with a command that could use an expression to determine
> the name of the chain to which to dispatch.  (I know there's an
> outstanding patch for adding expression evaluation to commons-chain,
> but I'm still waffling on the implementation (especially if Struts Ti
> is going to preference OGNL to JEXL, which has been my expression
> language of choice, but more because I just don't have time to
> implement patches with proper care right now...)
>
> For me, I haven't come up with any very compelling use cases for
> chaining action logic together.  Somehow there never seems to be that
> much reusability.  I guess some of the stuff that I'm pushing back
> into the "model" and using chains for is stuff that could be done at
> the controller layer in a lighter model, but I have specific use
> cases for triggering the behavior both from the webapp and from other
> processes.
>
> In any case, I wouldn't be surprised if there isn't some cleaning up
> to be done in this area -- not a lot of people have set out to use
> chains and commands instead of actions, so there aren't a lot of
> "best practices" just yet.  You get to discover them!


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 had some initial pain when we got ourselves into an "everything is a
command" mentality, leading to common commands showing up in almost every
chain, but we recovered from that. ;-) We made minor changes to the request
processor chain, mainly for error handling and Tiles (and the combination),
but otherwise it's been pretty painless.

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. 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. ;-)

--
Martin Cooper


Joe
>
> --
> Joe Germuska
> Joe@Germuska.com
> http://blog.germuska.com
> "Narrow minds are weapons made for mass destruction"  -The Ex
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> For additional commands, e-mail: dev-help@struts.apache.org
>
>

Re: Chain questions

Posted by Wendy Smoak <ws...@gmail.com>.
On 12/8/05, Joe Germuska <Jo...@germuska.com> wrote:

> Are you talking about dispatching to a chain, instead of
> dispatching to a method by reflection?  If that's the case, you could
> do it using the commons-chain Lookup Command, although it might be
> more elegant ...

Yes, I was looking for the equivalent of LookupDispatchAction which
goes from button text to resource key to method.  Otherwise it looks
like I'd have to change the forms to include the command in a request
parameter so DispatchChainAction would work.

I haven't touched the application code yet, and may not-- in part this
is an exercise to familiarize myself with some of the things that have
been added since I last looked.

> In any case, I wouldn't be surprised if there isn't some cleaning up
> to be done in this area -- not a lot of people have set out to use
> chains and commands instead of actions, so there aren't a lot of
> "best practices" just yet.  You get to discover them!

No wonder it seems like the manual is missing a few pages... ;)

Thanks for the insights on how you're all using it-- including the
answer to the mystery of where the "legacy" package name in the
Javadoc came from.

--
Wendy

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


Re: Chain questions

Posted by Joe Germuska <Jo...@Germuska.com>.
At 6:26 PM -0700 12/8/05, Wendy Smoak wrote:
>I need help with Commons Chain and Struts in combination.  I've read
>the Commons Chain docs, including the cookbook, which uses a
>CommandAction in the Chain version of mailreader.
>
>Then in Extras we have ChainAction and DispatchChainAction.  I assume
>I'm supposed to use one of those instead of including a special Action
>in my webapp.


I suppose you could just use the "command" (and optionally "catalog") 
attribute of the action mapping and not specify any "type."  (Yet 
another way to do it!)

If you're using a Chain action, then why would you want dispatch 
also?  Are you talking about dispatching to a chain, instead of 
dispatching to a method by reflection?  If that's the case, you could 
do it using the commons-chain Lookup Command, although it might be 
more elegant with a command that could use an expression to determine 
the name of the chain to which to dispatch.  (I know there's an 
outstanding patch for adding expression evaluation to commons-chain, 
but I'm still waffling on the implementation (especially if Struts Ti 
is going to preference OGNL to JEXL, which has been my expression 
language of choice, but more because I just don't have time to 
implement patches with proper care right now...)

For me, I haven't come up with any very compelling use cases for 
chaining action logic together.  Somehow there never seems to be that 
much reusability.  I guess some of the stuff that I'm pushing back 
into the "model" and using chains for is stuff that could be done at 
the controller layer in a lighter model, but I have specific use 
cases for triggering the behavior both from the webapp and from other 
processes.

In any case, I wouldn't be surprised if there isn't some cleaning up 
to be done in this area -- not a lot of people have set out to use 
chains and commands instead of actions, so there aren't a lot of 
"best practices" just yet.  You get to discover them!

Joe

-- 
Joe Germuska            
Joe@Germuska.com  
http://blog.germuska.com    
"Narrow minds are weapons made for mass destruction"  -The Ex

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


Re: Chain questions

Posted by "Frank W. Zammetti" <fz...@omnytex.com>.
My experience echos Ted's...

I just recently completed a relatively small webapp where data the user 
entered had to run through a series of rules, and the rules were 
tailored to a specific client.  And, it was a all-or-nothing situation, 
i.e., the data either passes all the rules or fails if any one rule 
fails.  A CoR pattern seemed like the obvious solution, and that's how I 
wound up doing it, to great success (although I used the CoR 
implementation in Java Web Parts because it has some added capabilites, 
but it's the same underlying concept).

As Ted says, I execute the Chain from an Action, treating it just like 
any business facade.  While I could see having a Chain be an Action in 
some cases, executing the Chain from an Action (or business delegate 
maybe more likely) I would suspect will be the most common usage pattern.

Not that any of this answers your original question Wendy :)

Frank

Ted Husted wrote:
> On 12/8/05, Wendy Smoak <ws...@gmail.com> wrote:
> 
>>Then in Extras we have ChainAction and DispatchChainAction.  I assume
>>I'm supposed to use one of those instead of including a special Action
>>in my webapp.
> 
> 
> I don't think anyone knows what we are "suppose" to do yet.
> Personally, I'd lean toward calling Chain from an Action, like any
> other business facade. I don't see the value-add in mixing the
> business chain in the with presentation layer. I've been using a port
> of Chain very successfully in ASP.NET just by calling it from the
> equivalent of an Action. I also used this approach in the (unfinished)
> Chain MailReader in the sandbox.
> 
> I haven't tried the new Struts Chain gizmos yet, so I can't help you
> on that score. :(
> 
> -Ted.
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
> For additional commands, e-mail: dev-help@struts.apache.org
> 
> 
> 
> 

-- 
Frank W. Zammetti
Founder and Chief Software Architect
Omnytex Technologies
http://www.omnytex.com
AIM: fzammetti
Yahoo: fzammetti
MSN: fzammetti@hotmail.com

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


Re: Chain questions

Posted by Ted Husted <te...@gmail.com>.
On 12/8/05, Wendy Smoak <ws...@gmail.com> wrote:
> Then in Extras we have ChainAction and DispatchChainAction.  I assume
> I'm supposed to use one of those instead of including a special Action
> in my webapp.

I don't think anyone knows what we are "suppose" to do yet.
Personally, I'd lean toward calling Chain from an Action, like any
other business facade. I don't see the value-add in mixing the
business chain in the with presentation layer. I've been using a port
of Chain very successfully in ASP.NET just by calling it from the
equivalent of an Action. I also used this approach in the (unfinished)
Chain MailReader in the sandbox.

I haven't tried the new Struts Chain gizmos yet, so I can't help you
on that score. :(

-Ted.

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