At 12:43 PM -0700 1/6/05, Wendy Smoak wrote:
Can someone explain what Struts Chain is or point me to some documentation?
I see it mentioned occasionally, but I can't find anything that sets out
what it is, how it works, and why I might want to use it.

Geez, you want documentation?

Actually, I was starting to update the current docs the other night, and it made me realize that there are things I'd like to change, so that they work the way I want to write about them :^)

Anyway, to begin with: if you have never cared about the RequestProcessor class, short of, perhaps specifying to use the TilesRequestProcessor, then you can safely continue to not care about it, ignoring the fact that a different class is doing what should amount to the same thing.

(The one exception being that you'll have to take some steps to use tiles, but since you'll also have to start using the struts-tiles JAR, I imagine we'll have a simple list of steps and most people still won't need to know much more about it.)

What is it:

struts-chain is a replacement for the original RequestProcessor, designed to eliminate the problem of integrating multiple libraries which extend the request-processing life-cycle (RPLC). The fact that RequestProcessor was a class and not an interface, coupled with Java's single-inheritance model, made it extremely cumbersome for developers to create reusable libraries which modified parts of the RPLC. Also, it had a fair amount of logic embedded in its central "process()" method which was the backbone of the process. The idea was that you would only override methods called by that one, never changing the base "process()" method itself. If you wanted to add entirely new steps which weren't in there, it was pretty challenging.

How it works:

This first part is not specific to chain; it's how Struts has worked since 1.1:
the ActionServlet's doGet(request,response) method is called. The ActionServlet looks up the module for the request, and retrieve's that module's request processor. It calls "process(request,response)" on the RequestProcessor, which does just about everything else that you think of as Struts.


In Struts 1.3.x, "everything else that you think of as Struts" is implemented as a series of commons-chain "Command" objects, each of which is responsible for doing just a small part. A Command executes on a Context, which it reads to figure out the current application state, and which it updates so that later commands can take advantage of its work. So now, instead of subclassing RequestProcessor (and probably also TilesRequestProcessor, if you're trying to make a library), you can simply change the configuration which indicates the type and order of commands to be executed.

Why you might want to use it:

Well, I hate to break it to you, but you don't have a choice! That's not true, actually you could change the struts-config to use the original RequestProcessor, but by default, it uses the chain-based one and a default chain configuration which will be included with Struts. But it can continue to be invisible to you if you prefer it that way.

But the question is more "why would I want to change the RPLC" than "Why would I want to use Struts Chain to do it." Without a common context of complex applications to discuss, it is hard to describe solutions which can be more gracefully achieved by extending or modifying the RPLC. (Plus I've come to take it for granted, from before there was a Struts Chain with which to achieve it.)

Here's some examples of how we use a chain-based request processor in a current production app.

[A] Early in every request, see if any user authentication system has authenticated a current user. Our client uses Netegrity SiteMinder, so we have one command which looks for the request header that it adds and copies it to a different location. For testing, though, we have a much simpler method which simply looks for a request parameter with a special name, and puts it in the same location that the SiteMinder command uses. After each of these guys has had a chance to operate, another command looks in that location, and, if it finds an authenticated user ID, it makes sure that the request has a fully populated User object available, either by verifying that the current session User matches the ID or creating and populating a User if it doesn't match, or if its missing.

You might have done this in RequestProcessor.preProcess in the past, but you would have had to put all three pieces in one method, and it's a lot harder to pass configuration values in that way. The way that the chain digester processes the config XML, you can specify all kinds of per-command config values very simply and in a way where their connection to the thing that uses them is very clear.

[B] We also have a command which does an auth check; it tests the active ActionMapping and, if it's of a specific "secure" type, it uses properties from the action mapping to determine whether the current user can access the action. RequestProcessor had a single method where you could have overridden the JAAS roles-based auth control that Struts provides out of the box.

[C] We have a method which establishes an ActionContext class, which we pass into our Action.execute() methods instead of the tradition mapping/form/req/resp signature. This ActionContext knows where in the request or session scope to find important values, or classes and returns them in a typesafe fashion, which I find preferable to having a number of constants for putting things into the request or the session and a bunch of casting when you take the things back out.

[D] And finally, we have a PagePrep action which operates between the return from the Action and the tiles processing. This is the thing I'm always talking about which provides us with a straightforward way to prepopulate forms, set up menus and select lists, and otherwise shepherd data around so that the Actions and the JSPs on either side can be a bit simpler and clearer.
------
In addition to all of these things, I have hopes that the chain model will make it easier to develop widely sharable libraries for things like access control, workflow management, and possibly even more sophisticated configurable applications and reusable control-level components. I'd love for someone else to solve the workflow problem for me once and for all!


We'll see if that comes true, but I think it's much more palatable to do that kind of stuff now than it was with the original RequestProcessor..

Hope this helps,
        Joe

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


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



Reply via email to