cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ricardo Rocha <rica...@apache.org>
Subject Re: XSP and Cocoon2 Generators
Date Mon, 03 Apr 2000 21:49:27 GMT
On Mon, 03 Apr 2000, Giacomo Pati wrote:
> I still have problems with the concept of the hole process. As I
> remember a request is processed as follows:
> request -> generator -+--------------+-> serializer -> response
>                       !-<- filter -<-!
> So, there is always ONE generator and ONE serializer. There are 0-N
> filters. If I look with one eye at the "pyramid model of web contracts"
> and with the other on the pipeline above, I would say that XSP has to be
> implemented as (a) filter(s), not as a generator.
> This because if I am a german shop, I will have my XML-writers use
> german tags, transform them to XSP taglibs and then go thru the hole XSP
> machinery. 

On Mon, 03 Apr 2000, Stefano Mazzocchi wrote:
> Well, to be quite honest, the XSP Engine is both a filter and a
> generator: it's a filter when compiles the XSP page, it's a generator
> after the page is compiled.

Yes: during page generation, the XSP engine acts as a filter in that it
applies one or more transformations (stylesheet-based code generation)
to the input source document. Once the resulting source program has
been compiled and loaded, though, the engine acts as a generator in
that it doesn't use any preceding input from the pipeline and, instead,
generates events directly from the compiled program.

On Mon, 03 Apr 2000, Ben Laurie wrote:
> Then a generator is just a degenerate filter. You feed it <go/> and it
> spits its events.

This seems to imply that XML _files_ are the _only_ legitimate source of
SAX events... just kidding :-)

I'd say that only DynamicGenerators (not generators at large) are subject to
this interpretation, but I disagree it's a degenerate case: XSP pages, for
instance, are first-class generators where some or all of the event sources
are logic-based.

(Btw, the scenario presented by Giacomo, where XML writers use German
tags that must be transformed into XSP taglibs, can be satisfied by XSP as
a generator and even with the current Cocoon1 XSP implementation: it
would suffice to append a final  "German-to-XSP" logicsheet that takes
care of this particular transformation...)

Let's provide some context to our discussion:

Like any other server pages language, XSP processing has 2 phases:
code generation and request delegation. During the "code generation"
stage, XSP transforms the input xml document into an equivalent source
program that is subsequently stored, compiled and loaded. During the
"request delegation" stage, XSP simply passes the request to the
generated program which will then produce the actual xml content.

So far, XSP code generation has been achieved by means of a sequence
of xslt transformations yielding a text-only root node containing a suitable
source program.

Of course, this is not the only possible mechanism for code generation. In
my proposal for Cocoon2 dynamic generators, I define a "SourceCodeGenerator"
abstraction that is not tied to this or any other plausible implementation strategy.

Castor (http://castor.exolab.org), for instance, uses a purely object-oriented
approach in which the target Java class is explicitly represented as an object,
with properties representing superclasses, methods, fields and the like. This
approach shines when used for a specific target language and a "stable"
object type. It can be a bit expensive, though, when you intend to support
multiple programming languages as well as multiple target object types.

XSP, on the other hand, has followed a pattern rooted in the old Unix tradition
of using preprocessors for source code generation (e.g. m4).  This approach
is also fully consistent with xml's own layered transformation philosophy as
embodied in xslt...

Here, dynamic tags are expanded to equivalent source codelets by using xslt's
regular template matching mechanism. While some perceive this sort of
transformation as a degenerate case yielding a big text node enclosed in a
single root element, I think it's a valid general approach for markup-to-text
transformations (e.g. generating RTF from xml).

Returning to our subject, it's this in area (namely, xslt-based code generation)
and in this area alone where we could see XSP implemented as a filter: a
sequence of zero or more xslt stylesheets are applied to a source xml  document
(in a well-defined order) to yield a source program that is to be subsequently
instantiated.

Right after this stage, the filter similitude vanishes: once the program is ready
for execution, it becomes a first-class generator "spitting events" (as Stefano
puts it) to be consumed by the remaining pipeline and without depending on
any preceding xml input.

Granted, one might rephrase the logicsheet-applying process as a sequence
of pipeline xslt filters preceding "true" XSP processing. This is, afaiu, what
Giacomo proposes.

However, this necessarily calls for a more granular pipeline-step caching
mechanism where the result of each step is cached and made dependent on the
underlying resources (xml source document, xslt logicsheet) so that whenever
any of them changes, the pipeline is restarted from that point on:

On Mon, 03 Apr 2000, Giacomo Pati wrote:
> If we can tell the cocoon system which resource (i.e. file) a part
> (generator/filter/serializer) of a pipeline uses, we can cache every
> intermediate result of the pipeline and restart the pipelining at the
> first step where a resource has changed. 

On Mon, 03 Apr 2000, Stefano Mazzocchi wrote:
> Yes, but maybe _very_ expensive in terms of memory usage. The use of
> thedouble pipeline is to store _only_ the result of each pipeline and forget
> about the rest (of course, stylesheets are different and _will_ be cached).

[Hmmm... Let's keep in mind that logicsheets _are_ stylesheets...]

I agree with Stefano that the cost of keeping intermediate results can be way
higher than that of rebuilding the XSP program when needed.

Besides, the XSP engine must be able to reload generated programs _across
Cocoon invocations_, a scenario in which we don't care so much about
intermediate results as we care about the end product (e.g. a compiled Java
class) being current.

So far, our question has been: "should the XSP engine be implemented as a
generator or as a filter?".

Let's extend this question to include: "what component type does a generated
XSP page implement?"

Is a generated XSP page a filter? Clearly not: it does not process any incoming
input. On the contrary, it's meant to be the source of a pipeline because it's
directly derived from the source xml document and is guaranteed to encode all
of such document's content (as augmented by its embedded logic-based tags)

Clearly, a generated XSP page is a generator. More specifically, it's a
_dynamic_ generator, meaning that it's not statically defined in Cocoon's
sitemap, but rather dynamically located and instantiated at request time.

Independently of their dynamic nature, XSP pages are generators and, as
such, must come first in the processing pipeline.

Which leads us to the second stage: request delegation.

During request delegation, the XSP engine necessarily acts as a generator:
a generator capable of locating/generating and subsequently transferring
control to another (dynamic) generator which actually feeds the pipeline with
XML data. This is what in my proposal I call a DynamicGeneratorLoader.

Now, all this does not invalidate what I believe to be Giacomo's main (and
valid) point: xslt-based code generation is clearly a case of filtering...

Here's where sub-pipelining comes into play: we can (and should) reuse
Cocoon's machinery to perform an otherwise regular xslt transformation of
the input XSP document in order to yield a source program implementing
DynamicGenerator.

[A bit of self-criticism is in order here: something I dislike about the current
XSP implementation is that  instead of reusing Cocoon's machinery for its
code generation purposes, it applies logicsheets using its own pipelining
caching and reloading. This sucks!]

A better approach is the proposed sub-pipeline mechanism where a dynamic
generator loader (among other possible candidate users) can recursively
invoke Cocoon's request handling machinery to delegate the task of
generating source code.

This isn't the only case in which such a mechanism is called for; we also
have what Stefano has dubbed "the old tune" of Cocoon sub-requests:
the ability to embed the result of another Cocoon request into the current
pipeline.

The current XSP implementation provides [very] limited support for this: you
can embed any well-formed XML fragment coming from any url. This
mechanism, though, incurrs in  the potentially unacceptable overhead of
generating another Http request...

XSP in Cocoon2 should provide a "native" mechanism to perform such
recursive inclusion without incurring in additional Http request overhead.
This inclusion mechanism should come in 2 flavors: compile-time (to aid
in the compilation process) and request-time (to provide for "normal"
runtime inclusion). Of course, both variants should relay on xinclude...

Likewise, Donald's XInclude filter may well provide an optimization to
determine whether a given inclusion can be satisfied by the current
Cocoon instance.

Given this optimization, sub-pipelining could always be seen simply as
a case of XInclusion.

A desirable side-effect of this approach is that Cocoon would cache
the intervening logicsheets thus resulting in something similar to what
Giacomo would like to see: restarting the code generation [sub]pipeline
only at the proper changeable point...


Regards,

Ricardo

Mime
View raw message