I've set myself to hacking up some of my alternative flow ideas so it could feed the 'generalized flow' discussion (and guide us through understanding possibly required refactoring)
I dubbed the thing 'apples' for now:
It basically sprung off from the short 'app' for application and 'applet' was already taken :-p (I also like the implied wit that we shouldn't compare any of his to pears)
For those that find emails longer then 20 words ;-) difficult to grasp, here is the TOC:
[1] explanation of current apples
[2] proposed refactoring to the current flow-codebase
[3] reflections on code sharing
[4] future directions
I think section [2] holds the most info related to the rest of the community (at least on short notice)
I hope (expect) for some discussion to come round those section [2] topics for sure... all comments on the rest is highly appreciated of course
-o0o-
[1][explanation of current apples]
The goal
(appart from 'doing research' which is a goal an sich ;-))
- explore the creation of a Java API to disclose the flow concepts
- such that people could reuse their OO thinking and their Java-class and Avalon-component coding skills to write 'Apples'
- which would be Avalon components hosting your business logic and making flow and publication decissions (i.e. selecting the uri and preparing the bizdata)
Here is what goes on to date:
The core is called the ApplesProcessor which is currently hooked up as a subclass of the existing Interpreter class
1/config: - it gets declared inside cocoon.xconf with some <component-instance name="apples" logger="apples" class="org.apache.cocoon.components.flow.apples.ApplesProcessor" > among the <flow-interpreters>
- and gets selected as the flow-impl to use in any sitemap by adding the:
<map:flow language="apples"/>
2/usage:
calling the logic inside your java-'apple' is based on the existing flow-directives in the sitemap:
<map:match pattern="**/*.kont">
<map:call continuation="{2}"/>
</map:match> <map:match pattern="start/use-case_X/*">
<map:call function="package.names.MyXApple">
<map:parameter name="param_A" value="val_A"/>
</map:call>
</map:match>3/processing:
These sitemap directives directly map onto the following methods of the Interpreter interface:
void callFunction(String fqcn, List args, Environment env) void handleContinuation(String id, List args, Environment env)
the AppleProcessor will do the following:
in the event of callFunction(fqcn, args, env)
- make an instance of the class specified in fqcn
- cast it to its interface of interest: AppleController
- pull it through the avalon lifecycles (lifecycehelper)
- wrap it up in a WebContinuation object (full reuse of the existing ContinuationsManagerImpl)
- let this fresh Apple process the 'request'
- get uri and bizdata from the 'response'
- use those in the forwardTo(uri, bizdata, wk, env) of the Intrepreter interface
and in the event of handleContinuation(id, args, env)
- find the nested continuation in the WebContinuation pointed to by id
- cast that to its interface of interest: AppleController
- let this re-found (stateful) Apple process the 'request'
- get uri and bizdata from the 'response'
- use those in the forwardTo(uri, bizdata, wk, env) of the Intrepreter interface
4/coding:
Your arbitrary business logic can be a sample Java class that
- can exploit the following avalon lifecycle-interfaces (Serviceable, (not yet Composable) and LogEnabled) -- (not yet Disposable)
- needs to implement void processRequest(AppleRequest, AppleResponse)
these new Request-Response objects are just convenient ways to control the access these Apples have to anything that is available to the AppleProcessor at the time of the call.
Basically:
- AppleRequest gives access to the CocoonRequest and the map of parameters (args) passed over...
- AppleResponse allows to set uri and bizdata
-o0o-
[2] proposed refactoring to the current flow-codebase
If above seemed like not that big a thing then you are absolutely correct: the layers to hook up any FlowImplementation you like are already present inside Cocoon, and it's a real pleasure to work with them.
There is only a slight tendency in naming and argument-passing that directs implementations towards using a scripting-language-interpreter to do the job.
Also, getting in some closer to the flow from a slightly different angle then the current js makes me suggest a number of additional modifications...
Here goes my set of proposed refactorings
(There is a fair chance that continued investigation will bring up some more of these...)
1/ modified forwardTo() in the AbstractInterpreter
All flow implementations just need to implement Interpreter but are likely to subclass AbstractInterpreter to do so. In that event they inherit already the implementation of the forwardTo() method.
Changing that implementation to this:
public void forwardTo(String uri, Object bizData,
WebContinuation continuation,
Environment environment) throws Exception
{
if (SourceUtil.indexOfSchemeColon(uri) == -1) {
uri = "cocoon:/" + uri;
} Map objectModel = environment.getObjectModel();
FlowHelper.setContextObject(objectModel, bizData);
FlowHelper.setWebContinuation(objectModel, continuation);
PipelinesNode.getRedirector(environment)
.redirect(false, uri);
}will proclaime the same forwarding behaviour accross all implementations:
forward-uri --> results in actual forward to no-leading-slash/whatever --> cocoon:/no-leading-slash/whatever which maps onto a pipe in the current sitemap
/with-leading-slash/more --> cocoon://with-leading-slash/more which maps to a pipe in the top-sitemap
scheme://full-uri --> unchanged
which assumes that the flowscript writer knows what he is doing himself. this could even be a http:// uri which results in a client-side redirect.
(see also http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=105888316704512&w=2)
2/ renaming interfaces, classes and methods (and sitemap nodes)
Interpreter --> FlowProcessor AbstractIntrepreter --> AbstractFlowProcessor
this probably ties up to the <flow-interpreters> becoming <flow-processors> in the xconf
Interpreter.callFunction() --> FlowProcessor.initiateFlow() Interpreter.handleContinuation() --> FlowProcessor.continueFlow()
which brings us back to the non-closed vote on changing sitemap semantics that could be mirrored by one of the proposals:
map:call/@function --> map:initiate/@flow map:call/@continuation --> map:continue/@flow
3/ signature change of callFunction and handleContinuation
In both methods the 2nd argument is a java.util.List of Interpreter.Argument objects.
I understand that the scripting implementations require the thus implied order on the <parameters>/arguments, however it would make sense to maybe redesign this passed 2nd argument to allow for both named or indexed lookup of the arguments...
(Currently just filling an additional hashmap from the List, actuall it's no big hastle, just 'additional', and giving some cosmetical unease)
4/ dispose() the wrapped continuation object upon invalidation
I'ld like the ContinuationsManager to check if the wrapped continuation is implementing Disposable upon invalidation of it's wrapper WebContinuation.
While at it it might preform the same service on the wrapped 'userObject' (although I have no direct need for this, it seems a logical extension of the reasoning)
5/ multiple flow declarations inside one sitemap
Well, to be fair I haven't seen the need here and now, but the discussion was also still open.
It still makes sense IMHO but I haven't got into proposing here something myself.
-o0o-
[3][reflections on code-sharing]
For those that need to read the code to think about all of this I am in the process of bundling up a first cut (rough stuff) as a src-zip/jar file that could (eventually) be added as some sort of a premature block....
I'm wide open to any suggestions about getting it to each or all of you (bugzilla being my natural choice unless someone makes me see differently)
-o0o-
[4][future directions]
First of all I'ld like to welcome any thought and code participation on this, so this can really go into any direction...
here is some directions/aspects where I'ld like to get some future investigation into:
(all of these should probably start off with checking up on the current js implementation -- if someone knows by heart please speak up)
- access control on live continuations (what if someone else uses your kont-id?)
- synchronization/locking on live continuations (what if two requests hit the same kont-id simultaneously)
- allow to programmically control the 'end-of-use-case' from the Apple itself
- make time-to-live somewhat more configurable and maybe even use-case controlled?
- get into the class-loader horror for dynamic reloading of these Apples (possibly through some -hopefully existing- Avalon component)
thx for reading up to here...
regards, -marc= -- Marc Portier http://outerthought.org/ Outerthought - Open Source, Java & XML Competence Support Center Read my weblog at http://radio.weblogs.com/0116284/ [EMAIL PROTECTED] [EMAIL PROTECTED]
