You seem to be assuming that commons-chain is, or is intended to be, a workflow engine. It's not. It's fundamental plumbing that might or might not be used in the creation of a workflow engine, but would certainly not be the only API exposed to users.It looks to me that I threw a disturbing idea. Now I change the subject for more discussions of different opinions.
Craig mentioned the "go to" statement in programming languages and hinted it could be an evil if Chain implement the semantics of "go to" (I just called it "jump behavior").
If we recognize Chain as a high level pattern regulator, I would not agree such a comparison is appropriate unless someone could convince me the following observations are questionable.
* I studied several workflow engines (not page flow stuff, they
manage persisted workload for people) They all implement,
one way or another, the "jump behavior". I could not see
they violate the OO design principles as high level
regulators.
* Struts itself, as a MVC pattern regulator in its core, implements the "go to" semantics when Action returns aIn terms of the chain implementation of the request processing lifecycle, this is just an unconditional command in the chain (it's implemented in o.a.s.c.servlet.PerformForward). No skipping or stepping is requried. See
ForwardConfig. It does a "go to" the next page, right? -:)
contrib/struts-chain/src/conf/chain-config.xml
for the entire definition. You'll note that it requires no skipping -- just the conditional behavior on validation failures, which is modelled as a branch to a separately named command.
Note that even the notion of "if" is not built in to the fundamental chain APIs, because it doesn't belong there. It is not part of the fundamental pattern (which was modelled on the description from the GoF book).In another word, IMHO, low level language principles may not be applicable to high level pattern/structure regulators. Hope people re-think it.
I also recognize the facts that we do not want to overgrow
Chain into an xml based rule engine. It should be just chain.
But for such a simple requirement, one way is to model it
as a "if" decision (Craig way), another way is to model it
as a pseudo controller (Ted way). They are kind of cumbersome to use. It violates the "Simple thing should
be simple" principle - a principle that supercedes other
programming principles. The Filter thing could offer a
simple solution, but I haven't looked it in details yet.
Filter is there because one model of using a chain is to have early commands in the chain look up some resources (say, grab a JDBC connection from a connection pool), expose it in the context, and then return false so that the chain continues. However, you want to make sure that you can return the connection to the pool when you're done, so the Chain you are running promises to call your postprocess() method on the way back out of the chain. So, a pseudocode model of a Command to expose a connection might look something like this:
public class AllocateConnection implements Filter {
public boolean execute(Context context) throws Exception {
DataSource ds = ... look up your DataSource via JNDI or whatever ...
Connectoin conn = ds.getConnection();
context.put("connection", connection);
return (false); // continue the chain
}
public void postprocess(Context context, Exception exception) { Connection conn = (Connection) context.remove("connection"); conn.close(); // Return it to the pool }
}
This is a nicely encapsulated resource allocation command that can be reused in any application chain that needs database connections. The subsequent commands that *use* the connection don't have any clue how it got there; they just assume that one will be made available in the context under an agreed-upon key.
Thus, Filter doesn't help you deal with control flow.
The "jump behavior" requirement is very obvious in Java Server Faces Specification too. When the renderResponse() is called on FacesContext, the controlIn terms of how you would implement it in a chain, its exactly the same as the Struts case -- no skipping or "start at this index" is required. Simply model the "Render Response" phase as a separately named chain, and execute it conditionally (just as I did in the Struts lifecycle for what happens on input validation failure) from each of the places where you can branch to Render Response.
is transferred to the Render Response phase after
the current phase. This is another evidence of the
"jump behavior" in high level pattern regulators.
I would like people to open mind and think, if weIt's not just an issue of simplicity, it's an issue of necessity. You haven't yet shown me a use case where commons-chain is the right design pattern for implementing something, but it cannot be done (or cannot be done gracefully) without the "start at index" or "skip this step" capability.
add a method in Chain that allows us to execute
the chain starting with a given index (currently
the starting index is 0). Will that make the thing simple?
Or the idea is still disturbing somewhere?
Additionally, basing starting and/or stopping points on indexes into the chain is horribly fragile -- as soon as I add or remove steps elsewhere in the chain, I've just broken your logic, and introduced a bug in something I did not directly change. That would be bad, so I'm also opposed to the idea on technical grounds.
Finally, even if you do have a use case that needs this capability, there's nothing stopping you from implementing an extended Chain that does it. I contend we should not put anything like that into the fundamental APIs unless it's absolutely vital.
JingCraig
Netspread Carrier http://www.netspread.com
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]