cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stefano Mazzocchi <stef...@apache.org>
Subject [RT] Improving Sitemap and Flowscript
Date Fri, 15 Aug 2003 22:11:59 GMT

  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.


Mime
View raw message