On Wed, 13 Aug 2003, PILGRIM, Peter, FM wrote: > In the excitment I got caught up the discussion about customised > action forward, whereas the original design intention got chucked > to the side, namely a ``composable request processor''. So let > me spend some time discussing this: > > Now I am at work. I said `RequestProcessor' currently could be > rewritten as a `Chain', because it aggregates a many `Command's. > But I am wondering about that statement. It would be seem > to me `RequestProcessor' is a very complex `Command' > > Going back to the original "Decomposable request Processor" thread > there were at least two concerns: > > 1) How delegate or nest processors so that they do the right thing. >
In contrib/struts-chain you'll see one approach for doing that. I separated the chain to pick which module to run from the chain to run the standard processing pipeline. In commons-chain there's a generic lookup command so that you can easily call nested chains by literal names or indirectly (by computing the name of the chain you want and then looking it up in the Catalog). There's also an option on the lookup command to ignore lookup failures. The example config uses this to let you optionally plug a preprocess command into either of the above two chains, simply by registering your own command under a particular name. > 2) Deciding which methods of the current processor should be decomposed. > If we're trying to emulate the 1.1 RequestProcessor, wouldn't it need to be all of them? That's what I started down the path of doing. > 3) Configuring the chain of processor from XML. > commons-chain has some utilities to easily construct a Digester instance that can parse them, and contrib/struts-chain uses that. See the following file in the Struts sources: contrib/struts-chain/src/conf/chain-config.xml There are, of course, no restrictions on how you actually register things in the Catalog, so you can load chain definitions from a database (or whatever) as well. > > Delegation: I believe would be like Servlet Filters as they are implemented > now. If we have servlet filters A and B , then we know that if filter A > chained to filter B. The final effect is not necessarily equal to B > followed A. > Order is definitely important in the standard chain, just like it is today. > Methods: In the current request processor there is one method > `process()' which has a default implementation: > > public void process(HttpServletRequest request, > HttpServletResponse response) > throws IOException, ServletException > > This method calls other ``process*'' methods. > > processLocale(request, response); > > ... > > processPreprocess(request, response); > > ActionMapping mapping = processMapping(request, response, path); > > ... > > ActionForm form = processActionForm(request, response, mapping); > processPopulate(request, response, form, mapping); > > ... > > Action action = processActionCreate(request, response, mapping); > > ... > ActionForward forward = > processActionPerform(request, response, > action, form, mapping); > > My question is if we make `RequestProcessor' a common-chain `Command' > then do then in turn make it call other `Command' in order to emulate > all the `process*()' calls. For example > > // RequestProcessor implemented as complex `Command' > // Assuming we get a web context from somewhere, > StrutWebContext sc = ... ; > > processPreprocessCommand.execute( sc ); > > ... > > ActionForm form = (Action) > processActionCreate.getAttributes().get("ActionForm"); > > ... > > processActionCreate.execute( sc ); > Action action = (Action) > processActionCreate.getAttributes().get("Action"); > > ... > > processActionCreate.execute( sc ); > ActionForward forward = (Action) > processActionCreate.getAttributes().get("ActionForward"); > > > Is this anything like what you had in mind, Craig? Because it > looks to me a bit untidy, but the request processor has effectively > been decomposed into commands. > Not only "had in mind" but "already partly done". There would no longer be any direct calls to each "process" method -- instead, they would all be commands in a chain that is preconfigured by Struts (and then optionally specialized by the app developer). See the sources in contrib/struts-chain. > The problem for me is building the new request processor, complex > command. what would the API look like? > > DefaultComplexProcessor dcp = ... ; // Our new request processor > > Suppose I want to intercept the process of creating a new ``Action'' > instance. If we write accessor method to expose the ``Chain'' that > is responsibe for creating an action, such as this: > > Chain oneChain =dcp.getProcessActionCreateChain(); > > then I could add my custom interceptor > > oneChain.addCommand( new ExpressoProcessActionCreateCommand() ); > > Is this speculation or truth? Am I on the right track or do you > have something else in mind. > At the API level, Chain.addCommand() is absolutely the way that chains are actually constructed. It's easier to build them from XML or some other data source, though. If we were to build everything on such a structure, configuring a Struts app would be mostly done by letting Struts load its standard definitions of all the chains (from some internal-to-Struts XML resource), then letting the application load its own config files -- possibly overriding the standard chain definitions -- then specifying the name of the chain that initially gets control (and is therefore responsible for processing the entire request). There wouldn't really be a RequestProcessor any more (although for 1.1 we'd probably implement all this inside a new one that simply replaces the process() method with the appropriate chain lookup and execution.) > Thoughts > > -- > Peter Pilgrim, > Struts/J2EE Consultant, RBoS FM, Risk IT > Tel: +44 (0)207-375-4923 > Craig --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]