cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Sylvain Wallez <sylvain.wal...@anyware-tech.com>
Subject Re: [RT] FOM
Date Tue, 27 May 2003 09:06:07 GMT
Stefano Mazzocchi wrote:

>Please, consider that even if I'm writing this, the ideas presented on
>this RT were distilled over several evenings spent with Ricardo on the
>whiteboard. As so, we are presenting them to you, hoping to sparkle
>further discussion.
>
>                                  - o -
>
>The FOM is the Flow Object Model. In my vision, it's the server-side
>equivalent of the DOM.
>
>Pier and I already stated a while back that our current implementation
>of the FOM is weak and its design poor. I had those feelings but I
>couldn't really come up with a real design reason for that, but now I
>have it: the current object model tries to wrap around everything
>without considering if it's good or bad to have access to the
>environment hooks.
>
>I believe that the number of methods/properties/objects should be
>reduced to the minimum necessary. Why so? several reasons:
>
> 1) incremental evolution: adding a method because something we thought
>it wastn't needed becomes needed doesn't create back-incompatibilities,
>removing a method because we find out how much it can be abused, it does.
>
>[NOTE: the sitemap has been designed with 'less is more' and every
>addition has been challenged deeply. Today, everybody sees the sitemap
>as an elegant and coherent contract]
>
> 2) design for safety: the flow will be a center of abuse because people
>will find it easier to write longer flows than to restructure their
>business logic into components. We must make all possible efforts to
>reduce this from happening.
>
>                             - o -
>
>First of all, as a general rule and in order to keep a sort of object
>orientation, no global methods or properties are kept. The only global
>contract is the "cocoon" object which is used as an entry point between
>the flow and cocoon. [this is equivalent of the "window" object for DOM]
>
>---------------------------------------------------------------------------
>The Cocoon Object
>---------------------------------------------------------------------------
>
>The Cocoon object is the only possible way the flow can communicate with
>Cocoon. In a sense, it's a gateway between the two realms. This protects
>the flow from abusing the Cocoon internals (for example, there is no way
>the flow can compose a sitemap pipeline since the cocoon object doesn't
>give it that power)
>
>--------- methods ------------
>
> void sendPage(uri,map) -> returns control to the sitemap, invoking the
>pipeline that will match the given URI and passing the given map as model.
>
> void sendPageAndWait(uri,map) -> same as above, but creates one (or
>more) continuation objects and makes their IDs available as part of the
>model passed.
>
> void processPipelineTo(uri,map,outputStream) -> invoques the pipeline
>that will match the given URI, passing the map as the model but
>connecting the output of the pipeline to the given output stream.
>

An important need in the CMS world will be to write to a 
ModifiableSource. We can use the above for this by getting the resolver 
using getComponent() and then asking the resolver for the Source object, 
but what about providing the following shortcut :
  void processPipelineTo(uri, map, targetURI) ?

> void redirectTo(uri) -> triggers a client-side redirect to the given URI
>
> void addEventListener(eventName,eventHandler) -> adds an event listener
>to the given event name (for example, session expiration)
>
> void removeEventListener(eventName,eventHandler) -> removes the given
>handler from listening the tiven event name.
>
> Object getComponent(id) -> obtains the component indicated by the given ID
>

Why don't you use the traditional lookup() name ? Also, release() is 
missing. So what about lookupComponent(id) and releaseComponent(id) ?

An important question, also : how does component management fit with 
continuations ? Can a component be frozen by a continuation and unfrozen 
in a different environment ? We could have some hooks that automatically 
relase components when a continuation is frozen, but then what about 
stateful components ?

> void callAction(name,map) -> invoques the action indicated by the given
>name and pass the given map as model
>
>NOTE: I personally believe that the getComponent() method removes all
>needs for the callAction() method. I foresee a future where the
>callAction() method will be deprecated. I would personally go the extra
>mile and avoid having it there altogether, but since there is no easy
>way to plugin new avalon components at runtime (at least, not as easier
>as plugging in different actions into the sitemap), I'm in favor of
>leaving it for now, until 'real blocks' will make it unnecessary.
>  
>

Same feeling. So what about removing it now ? We can also consider that 
the current state of things is that components are "semi-pluggable" : we 
cannot add new classes to the classpath dynamically, but we can declare 
new components, and particularily actions, dynamically just by changing 
the sitemap. So I don't see the real need for callAction().

> Session getSession()
>
>NOTE: both Ricardo and I believe that the flow should always be
>associated with a Session. Thus the use of the semantics "getSession"
>instead of "createSession". We are, in fact, against the concept of
>having the flow behave differently we the session has been created or
>it's has not been. This implicit behavior is potentially very dangerous
>from a user perspective and should be avoided.
>
>Moreover, it has been pointed out how continuations can be see as a way
>to "extend" sessions rather than replacing them. This would allow us to
>reuse the session-handling machinery already in place for things like
>load-balancing and fault-tollerance.
>  
>

Fault-tolerance, AFAIK, require session attributes to be serializable. 
So by attaching continuations to a session we allow load-balancing, but 
we still have a problem with fault tolerance.

>NOTE: methods that were left out where
>
> - input/output module support
> - script load support
>
>the reason for the first goes together with callAction(). Input/output
>modules were designed to overcome limitations in the scriptability of
>the sitemap.
>
>The reason for removing load() is because we want to avoid people from
>loading scripting dynamically. This goes in parallel with the
>anti-pattern of dynamic pipeline construction.
>
>WARNING: removing load() does *NOT* imply that you have to force all
>your flow in one big file. The way to fragment your flow into different
>files is to use several <map:script> elements in the <map:flow> section
>of the sitemap.
>

Load support is IMO required because JS lacks an import statement. Not 
having it means we'll have to write a <map:script> for the script we 
want to use, but also for *all the scripts it depends on*, recursively. 
This will be very difficult to manage.

>-------- properties ---------
>
> cocoon.request -> the request object
> cocoon.response -> the response object
> cocoon.log -> the log object
>
>NOTE: the absence of the context object is intentional! we couldn't come
>up with a reasonable need for such an object at the flow level. So, for
>the principle of 'less is more', we don't consider it. Be aware that if
>you want to propose its addition, you have to come up with a reason for it.
>

A simple reason : the context object (the environment one) gives access 
to context parameters defined in web.xml. In many situations, this is 
where parameters depending on the deployment environment are located, as 
it allows the sysadmin to use it's favorite app server GUI to set them 
and avoids editing cocoon.xconf. (yes, I've seen some installs being 
totally screwed up because the sysadmin didn't knew what a well-formed 
XML file was).

>---------------------------------------------------------------------------
>The Session Object
>---------------------------------------------------------------------------
>
>The session object is simply a wrapper around the Session object
>provided by the Cocoon environment. No methods were left out since they
>don't provide problems to the flow environment or suggest abuse.
>  
>

<snip/>

>---------------------------------------------------------------------------
>The Response Object
>---------------------------------------------------------------------------
>
>The response object contains hooks only to the cookies and to the
>response headers. Everything else will be controlled by the rest of the
>cocoon pipeline machinery (like output encoding, for example, which
>should *NOT* be determined by the flow)
>  
>

<snip/>

>---------------------------------------------------------------------------
>The Cookie Object
>---------------------------------------------------------------------------
>
>This object is a wrapper around the Cookie object provided by the
>Environment.
>  
>
<snip/>

>---------------------------------------------------------------------------
>The Request Object
>---------------------------------------------------------------------------
>
>The Request object is the one who has been pruned the most from the
>Cocoon Environment. The sections that were pruned were:
>
> - URI handling
> - Session handling
>
>Session handling has been removed in favor of the cocoon object and URI
>handling has been removed because unnecessary. I'm aware this is a big
>statement, please see below of why this is so.
>  
>

I don't have a good use case for URI handling just now, but I find this 
a strong limitation and I'm pretty sure we'll add it in the future...

<snip/>

>---------------------------------------------------------------------------
>The Log Object
>---------------------------------------------------------------------------
>
>This is a convenience method to access the cocoon logger. It could be
>the same of doing
>
> cocoon.getComponent(...)
>
Huh ? A logger is not a component.

>                                --- o ---
>
>That's it.
>
>This is, IMO, what the FOM requires. Nothing less, nothing more. But let
>me explain why I consider flow-driven URI handling harmful.
>
>Today, once you mount your web application, you don't know where it
>resides. In order to keep your webapp relocatable on your URI space,
>either you keep everything relative (including the many horrible
>../../../ which is easy to get wrong) or you re-invert the control by
>finding out yourself where you have been mounted and tweak URI accordingly.
>
>I strongly dislike both approaches because they are error prone.
>
>IMO, it should be cocoon to transparently adapt the URI right before
>serializing the output to the client.
>
>How?
>
>Using a link-translating protocol.
>
>Example:
>
> <html>
>  <head>
>   ...
>   <link src="link:/styles/main.css" ...>
>
>is then transformed accordingly (and transparently) by the sitemap right
>before the serializer.
>

This is a good idea, but IMO such a link transformation should be stated 
explicitely in the sitemap. Too much magic kills the confidence, and 
unecessary transformations kill the performance ;-)

>Ok, I think I wrote enough for now.
>
>Fire at will.
>

What about the Avalon context ? Is it omitted on purpose ?

Sylvain

-- 
Sylvain Wallez                                  Anyware Technologies
http://www.apache.org/~sylvain           http://www.anyware-tech.com
{ XML, Java, Cocoon, OpenSource }*{ Training, Consulting, Projects }



Mime
View raw message