At 4:20 PM -0700 9/8/05, Michael Jouravlev wrote:
I still have couple of questions before checking out the 1.3 source code.
I'm going to take them out of order, as some are simpler than others.
(1) The first one is where to check 1.3 out from?
You figured this one out: http://struts.apache.org/acquiring.html has
information about all the many ways to acquire Struts. Frankly, if
you have Maven installed, it's really not a big deal to check out
code from the repository, and it may be easier to keep up with
incremental changes. Do what works for you, of course.
(4) Neither Bill's article nor Vic's example stress out the scope of
the Context. Is it filled out for each request? Can I set up the scope
for the Context? Considering that Context has accessors for request,
session and servletcontext, it should be a long-term object. Whom it
belongs to? Should access to it be synchronized?
The ActionContext instance is request scoped. It is created by the
Request Processor before the base chain command is invoked. Struts
will never spawn an additional thread which might contend for simple
properties of the ActionContext, so unless you have some exotic
programming models, it is probably save to consider it threadsafe.
Of course, the ActionContext may well have references to things which
may require more careful access, including but not limited to the
HttpSession.
(5) It is nice that process() is changed into a chain, but what are
the relations and dependencies between the commands? How do they
affect each other? What do they store in the context and what do they
expect? What would be the effect of removing a standard command or
adding a new one? This question does not require immediate answer,
rather a reminder for better docs ;-)
I won't try to answer it all now, but note that as we stand right
now, there are still some unfortunate internal dependencies on order
of execution which were just a result of an imperfect first pass at
translating the original RequestProcessor into the chain based one.
Of course several commands expect one or two objects to be in the
context, and this should be documented more clearly; however,
particularly regarding post-form-validation behavior, there's too
much hard coded logic testing things like "is the form valid." The
chain's control logic should actually prevent the context from
reaching a command which has that concern, but the initial
commons-chain implementation (as well, perhaps, as the nature of
expressing conditional logic in XML) make that harder than it should
be. This is something which is relatively likely to change before
Struts 1.3 goes GA. Not radically, but enough that if you are
customizing the chain-config.xml for your app, you should pay close
attention to changes in interim releases and discussions on the dev
list.
(well, it turns out that I answered more of this later than I thought
I would, in answering item 6, so read on if your curiosity has been
piqued!)
(2) How tight is integration between commands from chain-config.xml
and actions from struts-config.xml ? Should not it be possible to
define actions in chain-config.xml as commands? I know that actions
have more attributes and they have <forward> elements, but tighter
integration would be a great thing.
I look at Vic's example [3]:
=== cut here ===
<action path="/testAct" command="testCmd" catalog="testCat"
name="testBean" scope="session" validate="false">
<forward name="Success" path="/WEB-INF/modules/test/inf/test.jsp"/>
</action>
The classes (now there can be more than one!) to be executed in the
testCmd chain are specified in a chain-config.xml, similar to
struts-config.xml
<catalog name="testCat">
<chain name="testCmd">
<command name="testCmd1" className="com.mD.test.NewCmd"/>
<command name="testCmd2" className="com.mD.test.New2Cmd"/>
</chain>
</catalog>
=== cut here ===
Instead of one config file I have two files now. Um, I would rather
had less XML than more.
Command returns true or false, Action returns ActionForward. How does
this work? Where the action forward is returned to? Is it set into the
context?
There are a few questions in here. First, the explicit ones at the
end: the command which executes an action takes the ActionForward
which is returned and places it in the ActionContext in "the right
place." If you chose to attach a command to an <action> mapping and
leave out the "type" attribute, then your command should assume the
responsibility of populating the "actionConfig" property of the
ActionContext, which is the net effect of the ExecuteAction command.
Note that it is possible to have a command execute in addition to
having an Action execute. After some discussions about Struts Ti on
the dev list, I now wonder if we should have (or ought yet to) set
that up so that the looked up command is somehow used as the first in
a chain which is also composed of the rest of those standard
commands. I'm not entirely sure how this would happen, but it would
allow you to set up a Filter instead of a simple command, and
therefore have access to the action context twice, much like the
WebWork interceptors that have inspired some of Don's thinking in
Struts Ti. I think this is something relatively reachable, but since
I've never programmed with the Interceptor model, I don't think I'll
lead the charge on it without some more obvious interest from other
users. (not to mention my previously referenced lack of time for
substantial new development lately.)
I agree that it's kind of awkward to have to define commands in two
places. This is something that needs watching and constructive
feedback from a user community. You can't simply define the commands
in a chain-config because Struts would never know how to link them to
an action path. So much behavior in Struts is driven around the
ActionConfig -- not just the action class, but the form
instantiation, whether or not validation happens, what the real
resolution paths of logically named forwards are....
On the other hand, it has been discussed that one might make it so
that the <action> mapping itself could specify a command class,
either by developing a richer interpretation of the "type" attribute,
or by adding a new attribute like "commandClass".
At my job, we want our controller beans managed by Spring, so they
can have simple access to business services and DAOs, so we are
already accustomed to having another config file -- but it's Spring
and not commons-chain which instantiates our commands. We then use
arbitrary config properties on the ActionConfig and a custom chain
command which analyzes those properties to find and execute a Spring
Bean chain command. It's working quite nicely for us, but even if
Struts had a dependency on Spring, I'm not sure that I'd push
everyone to do it this way.
(6) Bill's article [2] shows a login interceptor implemented as
command, but all it does is displays 403 error. Well, it reminds that
request and response objects did not go nowhere, and can be used, but
what I would like to see is not short-circuiting the chain, but
redirecting to a login action. I am not sure how this is going to work
in the chain. Should I somehow preselect the interceptor action (login
action) before SelectAction command? Or exactly in this command? What
about other commands like PopulateActionForm or ValidateActionForm? I
do not need to execute them, but I need to execute CreateAction and
ExecuteAction, which are in the end of the chain. How do I jump to
them across other commands that I do not need? Or this use case should
be handled by creating a new small chain specifically for login
action, which would include only SelectAction, CreateAction and
ExecuteAction, and then short-circuiting?
This relates to the aforementioned shortcoming in the current chain
design (although perhaps not exclusively.) I think that problems
like this are also behind some of the thinking behind Struts Ti,
although you'd really have to ask Don Brown. Anyway, in Struts 1.3,
what are now two fundamental steps of the base "servlet-standard"
chain should be broken into at least three if not more.
Right now, it's
1) process-action
2) process-view
It should be more like
1) preprocess-request
SelectLocale
SetOriginalURI
RequestNoCache
SetContentType
SelectAction
AuthorizeAction
2) process-form
CreateActionForm
PopulateActionForm
ValidateActionForm
3a) process-valid-form
ExecuteCommand
SelectForward
SelectInclude
PerformInclude
CreateAction
ExecuteAction
3b) process-invalid-form
SelectInput
4) process-view
(as now)
Handling the conditional branch between 3a and 3b is where
commons-chain falls short right now. The commands on each chain
should never execute if their basic condition is not met, but they
shouldn't have to know their basic condition - it's this hardcoded
logic which I would like to see change before we call Struts 1.3 a GA
release.
What is needed is a conditional lookup command which only executes
the command it looks up in certain cases. I've experimented with
some things here and discussed them on the dev list before, but
haven't settled on a preferred solution myself. Here's where early
adopter users will provide very valuable feedback, if not code!
Joe
--
Joe Germuska
[EMAIL PROTECTED]
http://blog.germuska.com
"Narrow minds are weapons made for mass destruction" -The Ex