Virtual Pipeline Components ---------------------------

Currently, people abuse the map:resource part of the sitemap to create pipeline fragments to call. This was introduced by the TreeProcessor implementation of the sitemap but map:resources were *not* designed to be pipeline fragments but entire pipelines.

It has been identified in several circumstances (but mostly dealing with blocks) that the need to use pipeline fragments is required.

I propose the creation of "virtual pipeline components" by aggregating two or more components into a virtual one. An example is

<map:components>

  <map:generators>
   <map:generator name="filteredFile">
    <map:generator type="file"/>
    <map:transformer type="xslt" src="namespaceFilter.xsl"/>
   </map:generator>

   <map:transformers>
    <map:transformer type="skin">
     <map:transformer type="xslt" src="fancy-doc2html.xslt"/>
    </map:transformer>
   </map:transformers>

   <map:serializers>
    <map:serializer type="html">
     <map:transformer type="linkTranslator"/>
     <map:serializer type="html"/>
    </map:serializer>
   </map:serializers>

</map:components>

As you can see from the example, with virtual components, we can:

1) reuse pipeline fragments as they were one component.
2) overload existing components with additional functionality
3) specify the src of a general purpose component (for example, xslt) and reuse that particular instance as a component. [useful for precompilation of general purpose transformations or for reusing pipeline services implemented by blocks]


The virtual compoments can include any other sitemap component but:

 1) for generators, all but serializers
 2) for transformers, all but generators and serializers
 3) for serializers, all but generators

and, obviously, the order is important.

- o -

 Moving Sitemap components into cocoon.xconf
 -------------------------------------------

the default sitemap is too verbose and this scares people away. I would like to move the default sitemap component definitions into the cocoon.xconf.

Note that with blocks, the definitions of those components will be in the block.xconf as well and this will be aggregated by the block manager.

- o -

 Pluggable Request Factories
 ---------------------------

Cocoon needs a simple way to deal with complex HTTP usages, such as binary uploading, XML-RPC, WebDAV or SOAP.

After a lot of discussion with Sylvain and input from many other people, I propose the introduction of a new sitemap element named "map:adaptRequest" that works by adapting the Request object into a more specific object that will parse the request and provide API-level access to the request.

For example, in case of file upload,

 <map:match src="/whatever/upload">
  <map:adaptRequest type="upload">
   <map:call function="upload()"/>
  </map:adaptRequest>
 </map:match>

the upload() function will be passed a UploadRequest object which extends Request and will be 'upcasted' by the script that uses it.

The same thing can happen for WebDAV or SOAP, where specific protocol-specific Request handlers will be passed and will be used by the script.

Note that upcasting requires a contract between the request object user and the sitemap writer. We believe this to be reasonable.

NOTE: the above removes the need for the pipeline extractor *and* removes the need for pipe-aware selectors. In fact, pipe-aware selection is not required if the proper information is extracted from the pipeline and made available to the environment. Instead of using extraction, the request is adapted by a specific request factory.

The factories are made part of the sitemap components

<map:components>
 ...
 <map:request-factories>
  <map:request-factory name="upload" src="...">
   <save-on-disk>true</save-on-disk>
   <map-upload>1000000</max-upload>
   ...
  </map:request-factory>
 </map:request-factories>
 ...
</map:components>

this also solves the issue with

1) uploading granularity
2) mailet request handling (that can be made a special request factory and evolve independently from our environment)


- o -

  Interception in Flowscript
 ----------------------------

While writing flowscripts, you realize how many things can be applied to many of the various flowscript functions that are called by the sitemap. In Linotype, I ended up using the ability that javascript gives you of using functions as native objects and then invoquing them by passing a modified argument vector.

It came to me that what I did with linotype was a really-poor-man interception mechanism. Interception is the ability to "intercept" a method call and execute some code before or after the execution of the intercepted method.

Interception is the simplest form of the aspect orientation.

Adding interception mechanism to the flowscript requires three changes, two in the FOM, one (more important!) in the javascript syntax:

1) the addition of a function call to the "cocoon" object, which indicates that intercepting function calls should be imported.

cocoon.apply("blah.js");

where "blah.js" contains the intercepting functions.

2) the addition of a function call to context that continues the intercepted invocation:

  ...
  continueExecution(arguments);
  ...

3) the introduction of wildcars for function names.

 function get*() {
   ...
 }

the above seems rather accademic, so allow me to write an example where the use of aspect-oriented flowscript would shine.

Something that can be modelled very well as an aspect is authentication/authorization (aka login) because it's not something that is part of the webapp (at least, it shouldn't be!) but it's something that is "wrapped" around it to allow people to access it without the proper authorization.

With interception, it can be implemented as such

login.js

    var user;
    var password;
    var role;

    function *() {
      var userManager = cocoon.getComponent("UserManager");
      while (true) {
        sendPageAndWait("login", { user : user, password : password });
        user = cocoon.request.user;
        password = cocoon.request.password;
        if (userManager.isValid(user, password)) {
           role = userManager.getRole(user);
           continueExecution(arguments);
           break;
        }
      }

then, in your flowscript, you simply have to call the "apply" function to apply the aspects to your flowscript

yourstuff.js

cocoon.apply("login.js");

     function whatever(blah) {
       doSomething(blah);
     }

- o -

Ok, that's it for now.

Ciao

--
Stefano.



Reply via email to