cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Daniel Fagerstrom <>
Subject Re: Blocks, Flow and Dependencies [was RE: Splitting xconf files step 2: the sitemap]
Date Tue, 11 Jan 2005 17:38:37 GMT
Stefano Mazzocchi wrote:

> Reinhard Poetz wrote:
>>>> Answer: It depends on the order of declaring your scripts in 
>>>> <map:flow/>. The first helper() method declared will be found.
>>> But there is only one helper() method per block!?
>> Yes. Therefore we need something more sohpisticated than imports.
> I'm having a hard time following this conversation, as it seems to me 
> that this is another instance of something that is becoming an 
> anti-pattern: "stating the solution before stating the problem".

The problem that we discuss was stated by Reinhard in, 
and then discussed in the rest of that thread 
( Glen changed 
name of the thread to something more relevant for the topic and we 
continued to discuss it I tried to 
explain the issues and point to the use case in again, as a 
service to newcommers to the discussion, and make a new trial explaining 
the issues below.

> The problem is that you want to use some functionality defined in 
> another block.
> Fair enough, since that's what blocks are: isolated service providers.
> One of the design decisions with blocks is that *NO FILE* will ever be 
> exposed by the blocks directly.
> There is practically no way in the world you are going to change my 
> mind on that, so consider it a permanent -1 for a block to expose 
> direct file access.

I agree completely with that, and have discussed how to achieve 
shielding of block internals earlier in the thread.


Now the use case that Reinhard and I have discussed is:

The idea is that I in a number of my webapps want to use the same 
handling of new customers. And therefore I have written a block 
"Customer" containing among other things  a flowscript function:

function newCustomer() {
  var customer = new Customer(defaultCustomer.xml);
  return customer;

That handles a dialog with a new customer and returns an object that 
contains the result of the interaction.

Then we might want to use this functionality in another block for 
e-business that among other things uses the newCustomer function. That 
could e.g. look like:

function buy() {
  var customer = newCustomer();

IMO this is a relevant use case for blocks and flow.

Several Contexts

After having seen the use case the question is what to do about it. 
First it is important to note that Customer:newCustomer() contain a 
number of references to resources within the Customer block: the file 
defaultCustomer.xml and the possibly internal pipelines nameAndAdress, 
preferences, spamPreferenses. A consequence of this is that even if the 
function is executed in the context of another block, like the 
e-business block above, all its relative URIs must be resolved in the 
context of the Customer block.

So using flowscripts from other blocks is more complicated that using 
flowscripts from the same block (the current situation). When using a 
flowscript from the same block you just call it in the current context 
that is descripbed by the FOM. When you use a flowscript from another 
block it must be exectuted in the context of the "FOM" from the other 
block. So the situation is like in object oriented programing the block 
is an object and the flowscript function is a method on it.

Sylvain have recoginzed that the handling of block (and sitemap) 
specific contexts is necessary for implementing VPCs and blocks, and 
discussed the concepts and its implementation in I have sugested 
that this can be interpreted in terms of static and dynamic binding, a 
refinement of the parameter passing strategy and polymorphic sitemaps in 
that thread.

Implementation Approaches

Returning to implementation of the usecase above. We have discussed some 
solutions, it can be solved by calling the flowscript function in a VPC 
pipeline defined in block. This VPC pipeline can then be used in other 
places following Sylvains design. We need some slightly modificated 
cocoon.sendPageAndWait function that handles foreign VPCs. This is the 
solution that I initially and Glen more persistently proposed.

The problem with that solution is how to pass the return value. It could 
be done by seting a session variable from the flowscript variable, but 
neither I nor Reinhard liked that solution. Communication between 
components by using global variables is not my favorite way of building 
systems. It scales badly, the communication between components becomes 
rather implicit and we have a risk that different blocks gets session 
variable name collisions.

Another solution would be to introduce some kind of return value for VPC 
pipelines and a third would be package the exported flowscript function 
as some function like thing that is easy to use from flowscripts. 
Reinhard and I have discussed the third option.

Here there are a number of questions:

* How to export functions from blocks. My opinion is that they should be 
explicitly enumerated in the VPC section is the block

* How to use them from another block, provided that they are exported. 
Reihnard proposed: cocoon.block.Customer.newCustomer();, which I find a 
good solution as it solves the problem that the function must be called 
in the context of its block. It solves the problem with lack of name 
spaces in JS and it also showes the object oriented nature of the situation.

* How to implement it.

* Other shielding issues. E.g. what about the web continuations that are 
created during the execution of a block flowscript:

                                                          --- o0o ---

> Blocks *may* expose their sitemap pipelines but nobody said that they 
> couldn't expose flow functions too (which are the flow equivalent of 
> sitemap pipelines)
> Now, blocks have different composition patterns:
>  - dependency
>  - extension
> the two will, IMO, result in different ways of composing flow functions.
> Dependency can make available, either implicity or explicitly thru a 
> cocoon.importDependencies() the block's dependencies.
> Since javascript has no notion of "private/public" for functions, we 
> could specify that functions that start with _ are "private", while 
> the other ones are "public". Or something like that.
> For extension, we could have automatic overload, so that if block A 
> has flow with function blah() and block B extends block A with 
> function blah() you can do
>  block b:
>   blah() {
>    cocoon.super()
>    print "blah b"
>   }
>  block a:
>   blah() {
>    print "blah a"
>   }
> if block b extends block a, calling blah() on b will result in
>  blah a
>  blah b

These are certainly also important use cases.

> There is *NO* need for direct file access and there is


> *NO* need for namespaces in javascript.

Combining blocks from several manufacturers will be more complicated if 
there are name collsions. But by using the exported functions as a 
method on the "block object", that problem disapears.

> I understand the above might not be easy to implement, but 
> implementation difficulty should *never* drive design decisions.

I tend to live after that policy, but my employers have not always been 
happy with that approach ;)

                                                          --- o0o ---



View raw message