You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Stefano Mazzocchi <st...@apache.org> on 2005/03/29 18:22:35 UTC
[RT] composition vs. inheritance in blocks
Daniel Fagerstrom wrote:
> But if we step up from the technical details, the main reason that I
> want multiple inheritance is that I want to make it easy to build
> webapps by extending and partly overiding a couple of orthogonal blocks.
> When you build your webapp block it might extend e.g. a Forrest block
> for documentation structure and skinning, a Lenya block for CMS
> functionality a user handling block for user adminstration etc. If you
> use extension you get a default behaviour from the beginning and then
> you can a step at the time overide the resources you want to modify.
>
> If you use a block instead of extending it, it is much more complicated
> to modify its behaviour. Take a look at Forrest, e.g. To make it
> extendible you have to use all kinds of global variables to simulate
> polymorphism. You must explicitly tell where it should search for
> different resources in your Forrest conf. As I have said before, I have
> practical experience of building webapps based on sitemap polymorphism
> and multiple inheritance, and it is much more convenient than having
> Forrest like conigurations for every block you want to extend.
>
> <snip/>
>
>>>> ------------------------------------------------------------------------------
>>>>
>>>> Improvement #3: block inheritance
>>>>
>>>> The third step is to allow blocks to extends other blocks.
>>>>
>>>> The idea is to be able to wrap a block with another one, creating an
>>>> 'overloading' mechanism similar to the one used by OOP inheritance
>>>> where methods are 'fall back' to the extended class if the extending
>>>> class doesn't implement them.
>>>>
>>>> Let us supposed we have the following block (very simple):
>>>>
>>>> block "A" implements "skin"
>>>>
>>>> /stylesheets/changes2document.xslt
>>>> /stylesheets/faq2document.xslt
>>>> /stylesheets/document2html.xslt
>>>> /resources/logo.gif
>>>>
>>>> and let us suppose that we want to change the look and feel of that
>>>> block. The first two stylesheets provide simply a way to adapt from
>>>> more specific markup to the Document DTD. So, my block would need to
>>>> change only the last two resources 'document2html.xslt' and 'logo.gif'.
>>>>
>>>> The best solution is to allow my block to explicitly "extend" that
>>>> block and inherits the resources that it doesn't contain.
>>>>
>>>> block "B" extends block "A"
>>>>
>>>> /stylesheets/document2html.xslt
>>>> /resources/logo.gif
>>>>
>>>> but then block B still is considered implementing behavior "skin"
>>>> because the rest is inherited.
>>>>
>>>> This mainly:
>>>>
>>>> * reduces block development and maintanance costs because
>>>> changes and bugfixes are directly inherited by all the extending
>>>> blocks, thus allowing better SoC between the two groups mainaining
>>>> the different blocks
>>>>
>>>> * easy customization: blocks can be adapted for personal
>>>> specific needs simply with a wrapper around and without the need to
>>>> repackaging.
>>>
>>>
>>>
>>>
>>> Ok, allready discussed that above. I think we need to be more
>>> explicit about what behaviour we want. If we just write:
>>>
>>> <map:transform src="stylesheets/document2html.xslt"/>
>>>
>>> that means normally the same as:
>>>
>>> <map:transform src="context:/stylesheets/document2html.xslt"/>
>>>
>>> and I don't think it is a good idea for isolation between block to be
>>> able to overide what is in the current context, only things that are
>>> exposed through the sitemap should IMO be overidable:
>>>
>>> <map:transform src="block:polymorph:/stylesheets/document2html.xslt"/>.
>>
>>
>>
>> I'm not sure if Stefano and you mean the same here. IIUC in Stefano's
>> example
>> you have e.g. blockA and blockB. blockA implements the behaviour skin and
>> extends blockB:
>>
>>
>> <block id="http://cocoon.apache.org/blocks/A/1.0.0">
>> <extends>
>> <block id="http://cocoon.apache.org/interface/B/1.0.0"/>
>> </extends>
>> <implements>
>> <interface id="http://cocoon.apache.org/interface/skin/1.0"/>
>> </implements>
>> </block>
>>
>> A sitemap snippet of blockA:
>>
>> <map:match pattern="stylesheets/document2html.xslt">
>> <map:read src="{0}"/>
>> </map:match>
>>
>> A sitemap snippet of blockB:
>>
>> <map:match pattern="stylesheets/changes2.html.xslt">
>> <map:read src="{0}"/>
>> </map:match>
>> <map:match pattern="stylesheets/document2html.xslt">
>> <map:read src="{0}"/>
>> </map:match>
>>
>>
>> Another block, e.g. blockC now uses blockA for its styling:
>>
>> <block id="http://cocoon.apache.org/blocks/C/1.0.0">
>> <requirements>
>> <requires block="http://cocoon.apache.org/interface/skin/1.0"
>> default="http://cocoon.apache.org/blocks/A/1.0.0"
>> name="skin"/>
>> </requirements>
>> </block>
>>
>> Here a sitemap snippet of blockC:
>>
>> <map:match pattern="myPipeline1">
>> <map:generate src="bla"/>
>> <map:transform src="blocks:skin:/stylesheets/document2html.xslt"/>
>> <map:serialize/>
>> </map:match>
>> <map:match pattern="myPipeline2">
>> <map:generate src="bla"/>
>> <map:transform src="blocks:skin:/stylesheets/changes2html.xslt"/>
>> <map:serialize/>
>> </map:match>
>>
>> myPipeline1 gets the stylesheet from blockA and myPipeline2 from
>> blockB (no
>> stylesheet available in blockA --> fallback to super block blockB)
>>
>> Does this make sense for you?
>
>
> It does.
>
>> How does block:polymorph apply in this usecase?
>
>
> In your example block A extends block B, then in block B we can have a
> sitemap rule like:
>
> <map:match pattern="**.html">
> <map:generate src="{1}.xml"/>
> <map:transform src="block:polymorph:/stylesheets/document2html.xslt"/>
> <map:serialize/>
> </map:match>
>
> The block:polymorphism makes that stylesheets/document2html.xslt is
> taken from A rather than B. Say that you use that stylesheet in several
> rules, then you change multiple behaviours by overriding it.
>
>
>>>> ---------------------------------------------------------------------------------
>>>>
>>>>
>>>> I'm not sure about multiple-block inheritance. For me it's some kind
>>>> of an anti-pattern but maybe I'm too Java-minded.
>>>
>>>
>>> Multiple inheritance is not an antipattern in itself. The idea that
>>> it should be is IMO mainly marketing BS from Sun to make the stupid
>>> idea of single implementation inheritance seem like a feature.
>>>
>>> But there are a number of antipattern that was popular in OO maybe
>>> 10-20 years ago that was based on multiple inheritance. But that is a
>>> different thing. People tended to model the world with classes
>>> instead of interfaces, and used deep an multiple inheritance that got
>>> a lot of garbage from all the to full featured base classes. Also as
>>> the extension relation in Java (and many other OO languages) is much
>>> "harder" than using through interface, extension was considered less
>>> flexible.
>>>
>>> But as discussed above we don't need extension to be as hardcoded as
>>> in OO languages. And also implementation inheritance is a rather
>>> natural and efficient way to put things together.
>>
>>
>> I think that modelling applications using interfaces and implementing
>> them using
>> delegation is better than extension ...
>
>
> If you want to convince me I'm afraid that you have to tell why you
> think it as well ;)
>
> Using extension as it happen to be implemented in C++ and Java can be an
> anti pattern under certain circumstances. But saying that something is
> an antipattern without giving a context is close to meaningsless. For
> blocks extension give us polymorphism and if we want to extend and
> override several different concern areas in our webapp, we need multiple
> inheritance.
>
> If we instead using interfaces they are for the moment just an URI an
> maybe some documentation. And for the delegation, it means that you have
> to explicitly code the usage pattern for every block service.
>
>> The question for blocks now is what
>> multi-block inheritance really buys us.
>
>
> Extend and override from multiple blocks based on polymorphism.
>
>> As I said above I think we should go
>> through all 3 block services (pipelines, components, flows) and describe
>> scenarios and compare pros and cons of multi-block inheritance
>> compared to single-block inheritance.
>
>
> The pros with multi-block inheritance is that your block can be vertical
> frameworks with default behaviour that you can modify by overiding
> certain pipeline rules, components and flow functions. The cons is that
> we have to spend some thinking to get the design right and to get the
> behaviour intuitive enough.
>
> Single block inheritance is possibly good in the way that it is easy to
> see where you get things from and it is bad in that you have to do a lot
> of coding if you want to use several vertical frameworks that takes care
> of different concern areas in your webapp.
>
> Frankly I can't see much advantages in single implementation inheritance
> at all. If delegation always is better we should only have interface
> inheritance and not even single implementation inheritance. And if
> implementation inheritance is good, and for webapps I'm quite certain
> that it is, it seem like a very arbitrary limitation to just allow for
> inheriting implementation for one concern area.
I don't like multiple inheritance and this is not just because I learned
OOP thru java, but because every single time I wish I had multiple
implementation inheritance in java I found a way to go around the
problem with single implementation inheritance that was more elegant.
I would go a little further and say that I believe inheritance is useful
only when used as a 'cascading' mechanism, in any other sense is
harmful: composition should be used instead.
Why so?
It's extremely hard to design for inheritance, a lot easier to design
for composition.
And performing composition thru multiple-inheritance is a really
terrible way to do it. Why? because you need to go very deep in
describing what behaviors get exposed and what are protected, otherwise
things get messy very fast.
Also, multiple-inheritance stops further composition: you seem to
suggest that a block that inherit multiply is a 'leaf block', one that
is your own application and that will not be used by others.
Well, one of the reasons for block design was to sparkle the creation of
reusable application components without people to think much about them:
multiple-inheritance yields horizontal behavior changes to the inherited
components, which means that if I have block A inherit block B and then
block C that wants to use A but was already using B, but A modified B's
behavior a little with the inheritance, you have a problem!
I am strongly against multiple implementation inheritance for blocks,
because what you want to do, if you care about reusability, is really
multiple composition and that is achieved with being allowed to
implement multiple behavioral interfaces.
If you *don't* care for reusability, then it's true that multiple
implementation inheritnace can serve as a cheaper form of composition.
But if I had to pick between improving block reusability or ease of
composition, I would go with the first, hoping that tools/syntax-sugar
would help the second (as it happened with Java).
--
Stefano.
Re: [RT] composition vs. inheritance in blocks
Posted by Peter Hunsberger <pe...@gmail.com>.
On Tue, 29 Mar 2005 19:36:33 -0500, Stefano Mazzocchi
<st...@apache.org> wrote:
> Peter Hunsberger wrote:
>
> >>I would go a little further and say that I believe inheritance is useful
> >>only when used as a 'cascading' mechanism, in any other sense is
> >>harmful: composition should be used instead.
> >>
> >>Why so?
> >>
> >>It's extremely hard to design for inheritance, a lot easier to design
> >>for composition.
> >
> >
> > That's FUD: a graph is a graph is a graph.
>
> BS. All graphs are graphs, but the 'properties' of graphs very a lot
> between them and there is a pretty good literature about how different
> 'local properties' in graph growth yield global properties.
Most of the significant differences are best described as the result
of default node exposure vs. default node hiding. Composition can
only default to hiding, inheritance can do either. As such, simply
saying that composition is better than inheritance is FUD, it's how
you traverse the graph that matters and what matters for Cocoon blocks
is that a graph is a graph is a graph.
A good traversal mechanism is going to solve the issues at hand much
better than trying to figure out whether that traversal mechanism
shares more properties with the concepts of inheritance or
composition.
xPath comes to mind...
> > The only question is how to expose or hide child nodes.
>
> Yep, this is *exactly* the local property I'm talking about above, that
> yields very different dependencies graphs.
>
> > With composition there are no child
> > nodes until you add them.
>
> Yep.
>
> > With inheritance the visibility depends on
> > the language and the implementor.
>
> Absolutely. And look at what happens with our classes: we call something
> public, just because we want another package to have access to it, and
> this is automatically exposed to somebody that later on wants to extend
> it, even if we did not meant it to be public for that use!!
>
> Sure, we could keep adding 'visibility' stati to sitemap URLs (we
> already have two: internal and external) but what is the gain?
Composition doesn't solve this problem. If you need public access to a
composed method the problem starts all over again. The problem with
Java is how you traverse the nodes (using public/private/etc.), not
inheritance.
>
> >>And performing composition thru multiple-inheritance is a really
> >>terrible way to do it. Why? because you need to go very deep in
> >>describing what behaviors get exposed and what are protected, otherwise
> >>things get messy very fast.
> >
> > Also FUD, again it depends on the language and the implementor.
>
> Again, BS. MI would force us to deal with visibility metadata and back
> compatibility would force us to default to 'external', meaning that only
> those 'aware' of what they are doing will keep things internal unless
> really required to open it up, and the 'public' java identifier problem
> will happen all over again.
No that's not BS: properly used MI doesn't _force_ you to do anything
more than composition. It allows it, but doesn't force it. MI provides
a superset of capabilities WRT composition. One can construct exactly
the same graphs using a constrained MI as with composition, the
inverse is not true (for normalized structures).
> >>Also, multiple-inheritance stops further composition: you seem to
> >>suggest that a block that inherit multiply is a 'leaf block', one that
> >>is your own application and that will not be used by others.
> >>
> >>Well, one of the reasons for block design was to sparkle the creation of
> >>reusable application components without people to think much about them:
> >>multiple-inheritance yields horizontal behavior changes to the inherited
> >>components, which means that if I have block A inherit block B and then
> >>block C that wants to use A but was already using B, but A modified B's
> >>behavior a little with the inheritance, you have a problem!
> >
> >
> > Only if you design things to allow the problem in the first place. If
> > I'm using both blocks to start with I can specify A.foo() or B.foo()
> > and pick or choose which version I want. If I start out using only B
> > and later add in A and find out I have a name space collision on foo()
> > then I have an issue.
> >
> > That's where the real problem lies with Cocoon blocks: unless the
> > references are resolved at startup then you have the _potential_ for
> > obscure run time problems as blocks get resolved dynamically. Since
> > you may not want to do startup resolution on the entire graph, I think
> > the way for Cocoon to support multiple inheritance is for the default
> > behaviour to be to hide all inherited capabilities and require
> > explicit exposure or to always require complete paths to the function.
>
> Exactly, and this behavior is back incompatible.
There's nothing to be back incompatible with.... Given that the
resultant property exposure can be exactly the same as with
composition you're not making any sense.
> > IOW, in this example , the only way to see the A version of foo()
> > would be an explicit reference to A.foo(), otherwise the reference
> > would fall back to B.
> >
> >
> >>I am strongly against multiple implementation inheritance for blocks,
> >>because what you want to do, if you care about reusability, is really
> >>multiple composition and that is achieved with being allowed to
> >>implement multiple behavioral interfaces.
> >
> >
> > Given that this is more-or-less completely new territory, the terms
> > inheritance and composition seem to be getting in the way. The real
> > issue is how does the block language expose features from each block.
> > You're describing the language as implementing "multiple behavioral
> > interfaces"; from my backgrounds POV the easiest way to do that is
> > multiple inheritance.
>
> I completely agree that it's the easiest way. My avalon experience shows
> me that composition yields more separate and much easier reusable
> components.
That suggests to me that avalon didn't have good ways of working with
MI, nothing more...
> It's very true this is unexplored terryrory, but my gut feeling tells me
> this is the case for webapp components as well. And, as I said, I will
> stick to this until proven wrong.
Here's the issue, properly done:
- composition yields a bunch of disjoint graphs and relies on a
grammar to move from one graph to another, and another grammar to move
from one node to another.
- MI builds a single normalized graph and uses a single grammar to
move from one node to another. A separate grammar is required to
build the normalized graph from disjoint components.
IOW; where do you want to pay the price for the second grammar? At the
time you smash the blocks together, or at the time you want to use the
functions in a block? Do you smash the blocks together more often
than you use functions across the blocks or vice versa?
Frankly, I don't know the answer to that one.
We do know that Cocoon has mechanisms for aggregation already
existing: smashing a bunch of block descriptors together in a pipeline
is trivial. Using XSLT to extract the results is likely somewhat
tricky work. However, once you've got the results, an in memory DOM
like structure traversed via xpath for feature extraction is straight
forward programming.
>
> >>If you *don't* care for reusability, then it's true that multiple
> >>implementation inheritnace can serve as a cheaper form of composition.
> >>
> >>But if I had to pick between improving block reusability or ease of
> >>composition, I would go with the first, hoping that tools/syntax-sugar
> >>would help the second (as it happened with Java).
> >
> > Well, that's almost all that it is about in this case: pure syntax.
> > If you think about what's going to have to happen under the covers the
> > end result is the same either way: you need a language to describe
> > which features are visible from one block to another. If there's a
> > term that is an abstraction for both inheritance and composition then
> > that's what you reallly want...
>
> that's hiding the problem under the carpet.
>
> Polymorphic Composition is not the same as multiple inheritance even if
> they might be used to achieve the same results.
>
> The real issue is another one and you both seem to be missing it
> entirely: multiple inheritance is easier to use, because doesn't force
> the block providers to define (and think about!) the contract between
> you and the services you require to achieve your task.
Only if you let it (default feature exposure)...
>
> This is both its advantage and its ultimate weakness: the system is way
> more fragile because the contracts between the two block sare 'implitic'.
>
> So, when you do
>
> +-(inherits from)-> block B
> /
> block A
> \
> +-(inherits from)-> block C
>
> what you are really stating is
>
> +-(requires)-> service 1 <-(implements)- block B
> /
> block A
> \
> +-(requires)-> service 2 <-(implements)- block C
>
> in java interfaces at least have method signatures that can be checked
> at compile time, Cocoon blocks won't have anything like that (the first
> that mentions BPEL will be shot!) because it's simply too hard (and
> cumbersome and useless in a local environment) to describe the behavior
> of a (potentially stateful!) service.
Unless you're going to write the language (BPEL or otherwise), how are
you going to get any better contracts with composition? You might have
jumped straight to your second diagram, but so what? Unless you've
written the "requires" and "implements" contracts you haven't achieved
anything. If you have written those contracts then they are the nodes
of your graphs and you're back to the issues I give above: how do you
want to smash the nodes of the graph together and how do you want to
traverse them?
> In such a 'weakly typed' environment, allowing people to get away with
> even "defining" what is the service (interface) that a block implements
> in order to allow service composition is suicidal.
>
> I don't want it to be easy to 'reporpuse' existing blocks (not designed
> to be extended or used as services!!), I want it to be *HARD*.
What about blocks designed to be used as services? Do you want _two_
different mechanisms for dealing with blocks? Surely not?
> I want it to be dead easy to write 'leaf blocks', those that you mount
> to the public and you expose as your own stuff, but as for writing
> blocks that are meant to be reused, this is another story and this
> requires you to go to the process of managing that contract between what
> you implement and what you exhibit.
>
> And you get polymorphism for free if you do that, but polymorphism is
> not the main advantage of this: interfaces, just like in java, make
> programs more reusable and solid because they create 'awareness' of what
> is the contract between your code and the user's.
>
> If we lose that, we are doomed to have a million blocks, and people that
> keep cutting and pasting between them to achieve what they want and
> avoid depending on somebody elses because the contracts change too fast.
>
> Sure, unlike java, our dependencies are versioned, so some of that
> problem goes away, but the awareness of contract management is what I
> want and MI kills all that.
Oh, good grief, that's simply not true (and I'm pretty sure you know
it). Sure you can screw up contract management with MI. You can also
screw up contracts with composition. You can also make contract
management easier with MI than with composition.
Instead of arguing MI vs. composition figure out what it really means
to do contract discovery and validation: if it's something you need to
do multiple times then you want a normalized graph. If it's something
you rarely need to do then save the resources required to do
normalization and use disjoint graphs instead.
--
Peter Hunsberger
Re: [RT] composition vs. inheritance in blocks
Posted by Stefano Mazzocchi <st...@apache.org>.
Peter Hunsberger wrote:
>>I would go a little further and say that I believe inheritance is useful
>>only when used as a 'cascading' mechanism, in any other sense is
>>harmful: composition should be used instead.
>>
>>Why so?
>>
>>It's extremely hard to design for inheritance, a lot easier to design
>>for composition.
>
>
> That's FUD: a graph is a graph is a graph.
BS. All graphs are graphs, but the 'properties' of graphs very a lot
between them and there is a pretty good literature about how different
'local properties' in graph growth yield global properties.
> The only question is how to expose or hide child nodes.
Yep, this is *exactly* the local property I'm talking about above, that
yields very different dependencies graphs.
> With composition there are no child
> nodes until you add them.
Yep.
> With inheritance the visibility depends on
> the language and the implementor.
Absolutely. And look at what happens with our classes: we call something
public, just because we want another package to have access to it, and
this is automatically exposed to somebody that later on wants to extend
it, even if we did not meant it to be public for that use!!
Sure, we could keep adding 'visibility' stati to sitemap URLs (we
already have two: internal and external) but what is the gain?
>>And performing composition thru multiple-inheritance is a really
>>terrible way to do it. Why? because you need to go very deep in
>>describing what behaviors get exposed and what are protected, otherwise
>>things get messy very fast.
>
> Also FUD, again it depends on the language and the implementor.
Again, BS. MI would force us to deal with visibility metadata and back
compatibility would force us to default to 'external', meaning that only
those 'aware' of what they are doing will keep things internal unless
really required to open it up, and the 'public' java identifier problem
will happen all over again.
>>Also, multiple-inheritance stops further composition: you seem to
>>suggest that a block that inherit multiply is a 'leaf block', one that
>>is your own application and that will not be used by others.
>>
>>Well, one of the reasons for block design was to sparkle the creation of
>>reusable application components without people to think much about them:
>>multiple-inheritance yields horizontal behavior changes to the inherited
>>components, which means that if I have block A inherit block B and then
>>block C that wants to use A but was already using B, but A modified B's
>>behavior a little with the inheritance, you have a problem!
>
>
> Only if you design things to allow the problem in the first place. If
> I'm using both blocks to start with I can specify A.foo() or B.foo()
> and pick or choose which version I want. If I start out using only B
> and later add in A and find out I have a name space collision on foo()
> then I have an issue.
>
> That's where the real problem lies with Cocoon blocks: unless the
> references are resolved at startup then you have the _potential_ for
> obscure run time problems as blocks get resolved dynamically. Since
> you may not want to do startup resolution on the entire graph, I think
> the way for Cocoon to support multiple inheritance is for the default
> behaviour to be to hide all inherited capabilities and require
> explicit exposure or to always require complete paths to the function.
Exactly, and this behavior is back incompatible.
> IOW, in this example , the only way to see the A version of foo()
> would be an explicit reference to A.foo(), otherwise the reference
> would fall back to B.
>
>
>>I am strongly against multiple implementation inheritance for blocks,
>>because what you want to do, if you care about reusability, is really
>>multiple composition and that is achieved with being allowed to
>>implement multiple behavioral interfaces.
>
>
> Given that this is more-or-less completely new territory, the terms
> inheritance and composition seem to be getting in the way. The real
> issue is how does the block language expose features from each block.
> You're describing the language as implementing "multiple behavioral
> interfaces"; from my backgrounds POV the easiest way to do that is
> multiple inheritance.
I completely agree that it's the easiest way. My avalon experience shows
me that composition yields more separate and much easier reusable
components.
It's very true this is unexplored terryrory, but my gut feeling tells me
this is the case for webapp components as well. And, as I said, I will
stick to this until proven wrong.
>>If you *don't* care for reusability, then it's true that multiple
>>implementation inheritnace can serve as a cheaper form of composition.
>>
>>But if I had to pick between improving block reusability or ease of
>>composition, I would go with the first, hoping that tools/syntax-sugar
>>would help the second (as it happened with Java).
>
> Well, that's almost all that it is about in this case: pure syntax.
> If you think about what's going to have to happen under the covers the
> end result is the same either way: you need a language to describe
> which features are visible from one block to another. If there's a
> term that is an abstraction for both inheritance and composition then
> that's what you reallly want...
that's hiding the problem under the carpet.
Polymorphic Composition is not the same as multiple inheritance even if
they might be used to achieve the same results.
The real issue is another one and you both seem to be missing it
entirely: multiple inheritance is easier to use, because doesn't force
the block providers to define (and think about!) the contract between
you and the services you require to achieve your task.
This is both its advantage and its ultimate weakness: the system is way
more fragile because the contracts between the two block sare 'implitic'.
So, when you do
+-(inherits from)-> block B
/
block A
\
+-(inherits from)-> block C
what you are really stating is
+-(requires)-> service 1 <-(implements)- block B
/
block A
\
+-(requires)-> service 2 <-(implements)- block C
in java interfaces at least have method signatures that can be checked
at compile time, Cocoon blocks won't have anything like that (the first
that mentions BPEL will be shot!) because it's simply too hard (and
cumbersome and useless in a local environment) to describe the behavior
of a (potentially stateful!) service.
In such a 'weakly typed' environment, allowing people to get away with
even "defining" what is the service (interface) that a block implements
in order to allow service composition is suicidal.
I don't want it to be easy to 'reporpuse' existing blocks (not designed
to be extended or used as services!!), I want it to be *HARD*.
I want it to be dead easy to write 'leaf blocks', those that you mount
to the public and you expose as your own stuff, but as for writing
blocks that are meant to be reused, this is another story and this
requires you to go to the process of managing that contract between what
you implement and what you exhibit.
And you get polymorphism for free if you do that, but polymorphism is
not the main advantage of this: interfaces, just like in java, make
programs more reusable and solid because they create 'awareness' of what
is the contract between your code and the user's.
If we lose that, we are doomed to have a million blocks, and people that
keep cutting and pasting between them to achieve what they want and
avoid depending on somebody elses because the contracts change too fast.
Sure, unlike java, our dependencies are versioned, so some of that
problem goes away, but the awareness of contract management is what I
want and MI kills all that.
--
Stefano.
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Peter Hunsberger wrote:
> On Tue, 29 Mar 2005 11:22:35 -0500, Stefano Mazzocchi
> <st...@apache.org> wrote:
<snip/>
> That's where the real problem lies with Cocoon blocks: unless the
> references are resolved at startup then you have the _potential_ for
> obscure run time problems as blocks get resolved dynamically. Since
> you may not want to do startup resolution on the entire graph, I think
> the way for Cocoon to support multiple inheritance is for the default
> behaviour to be to hide all inherited capabilities and require
> explicit exposure or to always require complete paths to the function.
Exactly, we could have internal and external sections of the component
declaration in sitemap in the same way as we allready has internal and
external pipelines. For pipelines I suggested earlier that inhertiance
is done through a special map:mount, in that way one is explicit about
search order and where in the uri space the blocks sitemap is mounted.
Also I proposed that we have a special protocol for polymorphic access
for avoiding supprises.
We could have similar constructions for component inheritance. I.e. all
or individual components from an extended block can be added to the
component section in an extending block, if there are several components
with the same name in the components section, the order is significant.
One have to explicitly ask for poymorphic behaviour for component lookup.
<snip/>
>>I am strongly against multiple implementation inheritance for blocks,
>>because what you want to do, if you care about reusability, is really
>>multiple composition and that is achieved with being allowed to
>>implement multiple behavioral interfaces.
>
> Given that this is more-or-less completely new territory, the terms
> inheritance and composition seem to be getting in the way.
Agree, what we need to discuss is what access patterns we want to
support between two blocks for different service types (pipelines,
components, flow?). I guess we all agree about that a "use" access
pattern with possibility for having internal services is needed. IMO we
also need a polymorpic "extend" access pattern for supporting the
"extend and overide default behaviour" style of webapp composition.
> The real
> issue is how does the block language expose features from each block.
As described above IMO this could be done on a more detailed level with
mounts in the sitemap for exposing pipeline services and though the
component section for exposing components.
Thinking further about it I'm quite sceptic about declaring "implements"
and "extends" at the block level, it should be enough to declare what
blocks it is dependent on. The exact nature of the dependence can better
be described in the sitemap.
Of course I think that it would be cool to be able to say that a block
depends on a number of interafaces and to be able to supply it with any
other set of blocks that implements the interfaces. But as long as no
one have made any concrete proposals about how to declare the behaviours
that a certain interface contains, I wonder if it not is asking for
trouble and all kinds of runtime errors by having "interfaces" without
any possibillities to check the contracts.
<snip/>
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Peter Hunsberger <pe...@gmail.com>.
On Tue, 29 Mar 2005 11:22:35 -0500, Stefano Mazzocchi
<st...@apache.org> wrote:
<snip/>
>
> I don't like multiple inheritance and this is not just because I learned
> OOP thru java, but because every single time I wish I had multiple
> implementation inheritance in java I found a way to go around the
> problem with single implementation inheritance that was more elegant.
I learned most of my OO with Smalltalk, Java has always seemed like a
big step backwards by comparison...
> I would go a little further and say that I believe inheritance is useful
> only when used as a 'cascading' mechanism, in any other sense is
> harmful: composition should be used instead.
>
> Why so?
>
> It's extremely hard to design for inheritance, a lot easier to design
> for composition.
That's FUD: a graph is a graph is a graph. The only question is how
to expose or hide child nodes. With composition there are no child
nodes until you add them. With inheritance the visibility depends on
the language and the implementor.
> And performing composition thru multiple-inheritance is a really
> terrible way to do it. Why? because you need to go very deep in
> describing what behaviors get exposed and what are protected, otherwise
> things get messy very fast.
Also FUD, again it depends on the language and the implementor.
> Also, multiple-inheritance stops further composition: you seem to
> suggest that a block that inherit multiply is a 'leaf block', one that
> is your own application and that will not be used by others.
>
> Well, one of the reasons for block design was to sparkle the creation of
> reusable application components without people to think much about them:
> multiple-inheritance yields horizontal behavior changes to the inherited
> components, which means that if I have block A inherit block B and then
> block C that wants to use A but was already using B, but A modified B's
> behavior a little with the inheritance, you have a problem!
Only if you design things to allow the problem in the first place. If
I'm using both blocks to start with I can specify A.foo() or B.foo()
and pick or choose which version I want. If I start out using only B
and later add in A and find out I have a name space collision on foo()
then I have an issue.
That's where the real problem lies with Cocoon blocks: unless the
references are resolved at startup then you have the _potential_ for
obscure run time problems as blocks get resolved dynamically. Since
you may not want to do startup resolution on the entire graph, I think
the way for Cocoon to support multiple inheritance is for the default
behaviour to be to hide all inherited capabilities and require
explicit exposure or to always require complete paths to the function.
IOW, in this example , the only way to see the A version of foo()
would be an explicit reference to A.foo(), otherwise the reference
would fall back to B.
> I am strongly against multiple implementation inheritance for blocks,
> because what you want to do, if you care about reusability, is really
> multiple composition and that is achieved with being allowed to
> implement multiple behavioral interfaces.
Given that this is more-or-less completely new territory, the terms
inheritance and composition seem to be getting in the way. The real
issue is how does the block language expose features from each block.
You're describing the language as implementing "multiple behavioral
interfaces"; from my backgrounds POV the easiest way to do that is
multiple inheritance.
> If you *don't* care for reusability, then it's true that multiple
> implementation inheritnace can serve as a cheaper form of composition.
>
> But if I had to pick between improving block reusability or ease of
> composition, I would go with the first, hoping that tools/syntax-sugar
> would help the second (as it happened with Java).
Well, that's almost all that it is about in this case: pure syntax.
If you think about what's going to have to happen under the covers the
end result is the same either way: you need a language to describe
which features are visible from one block to another. If there's a
term that is an abstraction for both inheritance and composition then
that's what you reallly want...
--
Peter Hunsberger
Re: [RT] composition vs. inheritance in blocks
Posted by Stefano Mazzocchi <st...@apache.org>.
Daniel Fagerstrom wrote:
damn, hit sent too early.
>> If you *don't* care for reusability, then it's true that multiple
>> implementation inheritnace can serve as a cheaper form of composition.
>
> For the majority of Cocoon users I would assume that blocks that are
> possible to extend and override is easier to reuse (considered that they
> have a good design of course), than just a lump of components and
> stylesheets.
what the hell are you talking about? the problem on the table is
multiple inheritance, not how granular the services the blocks offer are.
There is *NOTHING* that indicates that if you had MI or not the blocks
will be more or less granular.
>> But if I had to pick between improving block reusability or ease of
>> composition, I would go with the first, hoping that tools/syntax-sugar
>> would help the second (as it happened with Java).
>
> It's not either or. It's not exactly rocket science to build a mechanism
> for mutiple inheritance so we can have booth.
> We just need to discuss what we want to achieve and how to achive it to
> get it right.
I consider multiple inheritance for blocks FS: YAGNI!
Show me *one* example where single inheritance and multiple interface
composition can't echieve what you want to achieve and I'll change my
mind, but until then I'm stongly -1 on MI for blocks.
--
Stefano.
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Peter Hunsberger <pe...@gmail.com>.
On Apr 4, 2005 11:16 AM, Daniel Fagerstrom <da...@nada.kth.se> wrote:
> Peter Hunsberger wrote:
>
> >On Apr 4, 2005 10:26 AM, Daniel Fagerstrom <da...@nada.kth.se> wrote:
> >
> >
> >>Pier Fumagalli wrote:
> >>
> >>
> >>
> >>>On 31 Mar 2005, at 01:26, Stefano Mazzocchi wrote:
> >>>
> >>>
> >
> ><snip/>
> >
> >
> >
> >>As all URI discussions tend to provoke strong feelings for Stefano, it's
> >>best to say directly that this question is not important enough for me
> >>to fight about ;)
> >>
> >>But anyway, whether we go for an opaque custom protocol or base the
> >>block protocol on hierachial URIs we need to get into the specifics for
> >>the block URI scheme to be able to implement it.
> >>
> >>WDYT?
> >>
> >>
> >
> >He, he... The more I look at this the more I wonder if maybe it
> >really isn't crazy to allow blocks to specify a resolver intercept
> >scheme. Just lift the code directly out of mod-rewrite/mod-redirect
> >and let a block tell Cocoon what URI's have special concerns:
> >
> ><resolver>match spec</resolver>
> >
> >then you can go either way...
> >
> >
> I'm not following you, we already has source factories, so we can make
> our resolver as special as we want to. The question was rather if we
> should make them less special by using java.net.URI. Or do you have
> something else in mind?
Basically, the idea is to have a way for a block to say to treat a
given set of URI's in a special manner by performing a remapping on
them. That way the incoming request can be generic and transformed
into something block specific _before_ it hits the source factory.
Eg, being able to say that
http://site.com/foo/bar.css
ends up as:
block:/foo/bar.css
where as:
../bar.css
gets passed through to Cocoon untouched, or vice versa, depending on
the needs of the block and the block user. Perhaps this might be
better expressed as a "remap" directive than a "resolve" directive...
--
Peter Hunsberger
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Peter Hunsberger wrote:
>On Apr 4, 2005 10:26 AM, Daniel Fagerstrom <da...@nada.kth.se> wrote:
>
>
>>Pier Fumagalli wrote:
>>
>>
>>
>>>On 31 Mar 2005, at 01:26, Stefano Mazzocchi wrote:
>>>
>>>
>
><snip/>
>
>
>
>>As all URI discussions tend to provoke strong feelings for Stefano, it's
>>best to say directly that this question is not important enough for me
>>to fight about ;)
>>
>>But anyway, whether we go for an opaque custom protocol or base the
>>block protocol on hierachial URIs we need to get into the specifics for
>>the block URI scheme to be able to implement it.
>>
>>WDYT?
>>
>>
>
>He, he... The more I look at this the more I wonder if maybe it
>really isn't crazy to allow blocks to specify a resolver intercept
>scheme. Just lift the code directly out of mod-rewrite/mod-redirect
>and let a block tell Cocoon what URI's have special concerns:
>
><resolver>match spec</resolver>
>
>then you can go either way...
>
>
I'm not following you, we already has source factories, so we can make
our resolver as special as we want to. The question was rather if we
should make them less special by using java.net.URI. Or do you have
something else in mind?
/Daniel
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Peter Hunsberger <pe...@gmail.com>.
On Apr 4, 2005 10:26 AM, Daniel Fagerstrom <da...@nada.kth.se> wrote:
> Pier Fumagalli wrote:
>
> > On 31 Mar 2005, at 01:26, Stefano Mazzocchi wrote:
<snip/>
>
> As all URI discussions tend to provoke strong feelings for Stefano, it's
> best to say directly that this question is not important enough for me
> to fight about ;)
>
> But anyway, whether we go for an opaque custom protocol or base the
> block protocol on hierachial URIs we need to get into the specifics for
> the block URI scheme to be able to implement it.
>
> WDYT?
He, he... The more I look at this the more I wonder if maybe it
really isn't crazy to allow blocks to specify a resolver intercept
scheme. Just lift the code directly out of mod-rewrite/mod-redirect
and let a block tell Cocoon what URI's have special concerns:
<resolver>match spec</resolver>
then you can go either way...
--
Peter Hunsberger
Re: Multiple block instances
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Reinhard Poetz wrote:
> Daniel Fagerstrom wrote:
>
>>>> Another case is if we follow the method of handling the profile
>>>> info for a portal block that Reinhard proposed. If we want to use
>>>> two portals under the same Cocoon the portal block will be deployed
>>>> in two instances with different implementations of the profile
>>>> contract. Also here is the question is how we differ between the
>>>> two instances.
>>>
>>>
>>>
>>> Let's assume that you want to deploy two custom blocks that are
>>> based on the portal block. Doing so leds to two different blocks
>>> (--> different block IDs) which both extend the same block. Both
>>> blocks can use the same profile block to be customized or each gets
>>> its own - depends on your requirements.
>>
>>
>>
>> If we compare the situation with concepts from Java, my view was:
>>
>> Java: You download a class with unique combination of name and
>> namespace.
>> Blocks: You download a block with a unique URI.
>>
>> Java: You call the constuctor of the class possibly with parameters
>> and get an object with an unique object id.
>> Blocks: You deploy the block and get a block instance with a unique
>> (in your Cocoon) block instance id. During deployment you give it
>> parameter values and connect it to other block instances.
>>
>> --- o0o ---
>>
>> I guess that in your view there is no istantiation, you subclass and
>> have everything "static" instead.
>>
>> Both views will solve the same problem but in different ways. With
>> your view we might want to have tool support for automatic
>> subclassing ;)
>
>
> It should be as simple as writing a new block.xml and make a .cob out
> of it. btw, I heard of some project called Lepido .... ;-)
>
> After reading your mail I thought a bit about block instances but IMO
> they make things more difficult: where to put the 'constructor
> parameters', URI resolving and maybe more stuff.
In my view there is nearly no extra difficulty. The BlockManager
represents an instance and the deployment parameters and connections are
the constructor parameters. The only differnce is that a identifier is
generated at deploy time so that several BlockManagers can represent the
same Block but with different parameter and connection values.
> Maybe we really need them but this will be clearified after we set up
> some usecases using a working prototype.
Sure, it will only affect the identifier in the wiring and some
fuctionality in the deployer. For the communication between the
BlockManager and the BlocksManager it shouldn't matter. So its no big
deal to change it when we see that we need it ;)
/Daniel
Re: Multiple block instances
Posted by Reinhard Poetz <re...@apache.org>.
Daniel Fagerstrom wrote:
>>> Another case is if we follow the method of handling the profile info
>>> for a portal block that Reinhard proposed. If we want to use two
>>> portals under the same Cocoon the portal block will be deployed in
>>> two instances with different implementations of the profile contract.
>>> Also here is the question is how we differ between the two instances.
>>
>>
>> Let's assume that you want to deploy two custom blocks that are based
>> on the portal block. Doing so leds to two different blocks (-->
>> different block IDs) which both extend the same block. Both blocks can
>> use the same profile block to be customized or each gets its own -
>> depends on your requirements.
>
>
> If we compare the situation with concepts from Java, my view was:
>
> Java: You download a class with unique combination of name and namespace.
> Blocks: You download a block with a unique URI.
>
> Java: You call the constuctor of the class possibly with parameters and
> get an object with an unique object id.
> Blocks: You deploy the block and get a block instance with a unique (in
> your Cocoon) block instance id. During deployment you give it parameter
> values and connect it to other block instances.
>
> --- o0o ---
>
> I guess that in your view there is no istantiation, you subclass and
> have everything "static" instead.
>
> Both views will solve the same problem but in different ways. With your
> view we might want to have tool support for automatic subclassing ;)
It should be as simple as writing a new block.xml and make a .cob out of it.
btw, I heard of some project called Lepido .... ;-)
After reading your mail I thought a bit about block instances but IMO they make
things more difficult: where to put the 'constructor parameters', URI resolving
and maybe more stuff. Maybe we really need them but this will be clearified
after we set up some usecases using a working prototype.
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: Multiple block instances
Posted by Ralph Goers <Ra...@dslextreme.com>.
Daniel Fagerstrom wrote:
> If we compare the situation with concepts from Java, my view was:
>
> Java: You download a class with unique combination of name and namespace.
> Blocks: You download a block with a unique URI.
>
> Java: You call the constuctor of the class possibly with parameters
> and get an object with an unique object id.
> Blocks: You deploy the block and get a block instance with a unique
> (in your Cocoon) block instance id. During deployment you give it
> parameter values and connect it to other block instances.
This depends on whether the Java class is a singleton, in which case the
constructor is called only when the class is instantiated the first
time. The same could be true for blocks as well, if that is desirable.
It probably would be more manaageable if the first release required that
blocks be singletons and then expand that later if needed. Isn't that
basically the way servlets work?
>
>
> --- o0o ---
>
> I guess that in your view there is no istantiation, you subclass and
> have everything "static" instead.
Being a singleton doesn't mean that you can't have some initialization.
>
> Both views will solve the same problem but in different ways. With
> your view we might want to have tool support for automatic subclassing ;)
>
> /Daniel
>
Re: Multiple block instances
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Reinhard Poetz wrote:
> Daniel Fagerstrom wrote:
>
>> Consider the following case: One of my applications use a repository
>> block, and this repository block has a db connection with name and
>> password as deplyment parameters. If another application need to use
>> the same repository block, but connected to another db it will have
>> other deployment parameters. In this case we will have two deployed
>> instances of the same block with different deployment parameters. How
>> do we differ between them.
>
>
> If you need different behaviour of one block you will have to extend
> it (so it gets another unique ID) and only change the properties in
> block.xml.
ok.
> (Although I think that this isn't a good example because it's not a
> consuming block's concern to set the database connection IMO).
Didn't suggest that. What I described above was supposed to happen at
deploy time. The two applications only know that they talk with a block
that fullfills the repository contract.
>> Another case is if we follow the method of handling the profile info
>> for a portal block that Reinhard proposed. If we want to use two
>> portals under the same Cocoon the portal block will be deployed in
>> two instances with different implementations of the profile contract.
>> Also here is the question is how we differ between the two instances.
>
> Let's assume that you want to deploy two custom blocks that are based
> on the portal block. Doing so leds to two different blocks (-->
> different block IDs) which both extend the same block. Both blocks can
> use the same profile block to be customized or each gets its own -
> depends on your requirements.
If we compare the situation with concepts from Java, my view was:
Java: You download a class with unique combination of name and namespace.
Blocks: You download a block with a unique URI.
Java: You call the constuctor of the class possibly with parameters and
get an object with an unique object id.
Blocks: You deploy the block and get a block instance with a unique (in
your Cocoon) block instance id. During deployment you give it parameter
values and connect it to other block instances.
--- o0o ---
I guess that in your view there is no istantiation, you subclass and
have everything "static" instead.
Both views will solve the same problem but in different ways. With your
view we might want to have tool support for automatic subclassing ;)
/Daniel
Multiple block instances
Posted by Reinhard Poetz <re...@apache.org>.
Daniel Fagerstrom wrote:
> Consider the following case: One of my applications use a repository
> block, and this repository block has a db connection with name and
> password as deplyment parameters. If another application need to use the
> same repository block, but connected to another db it will have other
> deployment parameters. In this case we will have two deployed instances
> of the same block with different deployment parameters. How do we differ
> between them.
If you need different behaviour of one block you will have to extend it (so it
gets another unique ID) and only change the properties in block.xml.
(Although I think that this isn't a good example because it's not a consuming
block's concern to set the database connection IMO).
>
> Another case is if we follow the method of handling the profile info for
> a portal block that Reinhard proposed. If we want to use two portals
> under the same Cocoon the portal block will be deployed in two instances
> with different implementations of the profile contract. Also here is the
> question is how we differ between the two instances.
Let's assume that you want to deploy two custom blocks that are based on the
portal block. Doing so leds to two different blocks (--> different block IDs)
which both extend the same block. Both blocks can use the same profile block to
be customized or each gets its own - depends on your requirements.
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] The block protocol
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Stefano Mazzocchi wrote:
> Daniel Fagerstrom wrote:
>
>> Stefano Mazzocchi wrote:
>>
>>> I disagree. You have a world-wide unique identifier (the URI) and a
>>> local name in a well isolated context, and a wiring table to glue
>>> these together (using the URIs) that's all you need.
>>
>>
>> Consider the following case: One of my applications use a repository
>> block, and this repository block has a db connection with name and
>> password as deplyment parameters. If another application need to use
>> the same repository block, but connected to another db it will have
>> other deployment parameters. In this case we will have two deployed
>> instances of the same block with different deployment parameters. How
>> do we differ between them.
>
>
> Context.
>
> Here is your problem:
>
> [ Block A -(requires)-> Block C ] -(named)-> 'database'
> [ Block B -(requires)-> Block C ] -(named)-> 'database'
>
> this is the 'structure' of the dependency, not your actual instance.
>
> When you install Block A, the block deployer (thanks Reinhard for
> correcting me) will look for Block C (let's not dicuss the 'how' of
> this now).
>
> The block will be fetched, unpacked, configured and wired. At this
> point, Block C will become known (to A!) as "database" and from the
> block A, you can call "block:database:/" and that *instance* of block
> C will respond.
>
> Note that since java classloading is already namespaced, you *DO NOT*
> need to provide a block hint for the classloading: if Block C provides
> a class called
>
> org.myhost.myapp.myblock.Database
>
> you flowscript in block A can call
>
> cocoon.getComponent("org.myhost.myapp.myblock.Database")
>
> and obtain that *instance*, configured as you wanted at installation
> time (here, you will be asked for username/password/jdbc-url etc.).
>
> Now, later on, you install Block B, which requires an instance of
> Block C. You already have one installed, so the block deployer will
> ask you if you want to reuse that instance or another one.
>
> at this point, if you want to use another instance (keep the code, but
> change the behavior thru different configurations!), the block manager
> (and its internal classloader and sitemap mounter) will make sure that
> if you call block:database:/ from block B, you end up in *another*
> instance, with different configurations and different parameters.
>
Yes, sounds good.
/Daniel
Re: [RT] The block protocol
Posted by Stefano Mazzocchi <st...@apache.org>.
Daniel Fagerstrom wrote:
> Stefano Mazzocchi wrote:
>
>> I disagree. You have a world-wide unique identifier (the URI) and a
>> local name in a well isolated context, and a wiring table to glue
>> these together (using the URIs) that's all you need.
>
> Consider the following case: One of my applications use a repository
> block, and this repository block has a db connection with name and
> password as deplyment parameters. If another application need to use the
> same repository block, but connected to another db it will have other
> deployment parameters. In this case we will have two deployed instances
> of the same block with different deployment parameters. How do we differ
> between them.
Context.
Here is your problem:
[ Block A -(requires)-> Block C ] -(named)-> 'database'
[ Block B -(requires)-> Block C ] -(named)-> 'database'
this is the 'structure' of the dependency, not your actual instance.
When you install Block A, the block deployer (thanks Reinhard for
correcting me) will look for Block C (let's not dicuss the 'how' of this
now).
The block will be fetched, unpacked, configured and wired. At this
point, Block C will become known (to A!) as "database" and from the
block A, you can call "block:database:/" and that *instance* of block C
will respond.
Note that since java classloading is already namespaced, you *DO NOT*
need to provide a block hint for the classloading: if Block C provides a
class called
org.myhost.myapp.myblock.Database
you flowscript in block A can call
cocoon.getComponent("org.myhost.myapp.myblock.Database")
and obtain that *instance*, configured as you wanted at installation
time (here, you will be asked for username/password/jdbc-url etc.).
Now, later on, you install Block B, which requires an instance of Block
C. You already have one installed, so the block deployer will ask you if
you want to reuse that instance or another one.
at this point, if you want to use another instance (keep the code, but
change the behavior thru different configurations!), the block manager
(and its internal classloader and sitemap mounter) will make sure that
if you call block:database:/ from block B, you end up in *another*
instance, with different configurations and different parameters.
--
Stefano.
Re: [RT] The block protocol
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Stefano Mazzocchi wrote:
> Daniel Fagerstrom wrote:
<snip/>
>>>> in the connection section, where
>>>> "http://mycompany.com/skins/corporate/34.3.345" uniquely identifies
>>>> the specific skin implementation that has been choosen at deploy time.
>>>>
>>>> <comment>
>>>> Is the URI unique enough? What if I want several variants of the
>>>> skin that has different deployment parameters and implementations
>>>> of theire connections.
>>>
>>> IIRC, URI is generated, at that time uniqueness is guaranteed by
>>> BlocksManager (who created the URI).
>>
>> From http://wiki.apache.org/cocoon/BlockIdentification, I get the
>> impression that URI is "universal" rather than locally generated at
>> deploy time. I agree that a unique identifier created at deploy time
>> by the BlocksManager is needed.
>
> I disagree. You have a world-wide unique identifier (the URI) and a
> local name in a well isolated context, and a wiring table to glue
> these together (using the URIs) that's all you need.
Consider the following case: One of my applications use a repository
block, and this repository block has a db connection with name and
password as deplyment parameters. If another application need to use the
same repository block, but connected to another db it will have other
deployment parameters. In this case we will have two deployed instances
of the same block with different deployment parameters. How do we differ
between them.
Another case is if we follow the method of handling the profile info for
a portal block that Reinhard proposed. If we want to use two portals
under the same Cocoon the portal block will be deployed in two instances
with different implementations of the profile contract. Also here is the
question is how we differ between the two instances.
>>>> </comment>
>>>>
>>>> Interesting enough, IIUC, blocks are only accessible through the
>>>> block protocol from other blocks,
>>>
>>> No; IMHO they are all available through BlocksManager.
>>
> Well, no. The BlockManager has block 'scopes' and should allow a block
> to resolve only the blocks that it explicitly depended upon and for
> which it has a name for. The rest is just like it wasn't there... and
> this is required to avoid polymorphism without unwanted collisions.
>
>> They are, but AFAICS they have no common short name that could be
>> used outside blocks, and it is the short name that is used by the
>> block protocol.
>
> Exactly.
>
>> This could be solved by considering the main sitemap being part of a
>> block as well and have a (possibly optional) block descriptor for it.
>> Then the blocks would have a short name from the main sitemap as well.
>
> YAGNI: if you need a block, declare that you need it and associate a
> name with it. Otherwise, you don't need it, you don't have access to it.
>
With declaring it, do you mean that we have a block deployment
descriptor that is connected to the main sitemap?
/Daniel
Re: [RT] The block protocol
Posted by Stefano Mazzocchi <st...@apache.org>.
Daniel Fagerstrom wrote:
>> You probably meant here "BlocksManager"
>
>
> No I meant BlockManager. In my discussion I assumed that a BlockManager
> is responsible for the information within a block element in the wiring
> (http://wiki.apache.org/cocoon/BlocksWiring) and that the BlocksManager
> "correspond" to the blocks element. So from this the BlocksManager only
> know the URI that identifies the block. The mapping from a short name to
> the URI
>
> skin -> http://mycompany.com/skins/corporate/34.3.345
>
> is only known localy whithin a BlockManager. The situation is AFAIU
> analoguos with the relation between a namespace URI and a namespace
> prefix. Where the URI is a universal identifier and the prefix works as
> a identifier within the document. In the same way the blocks URI is a
> universal identifier of the block while the short name only identifies
> it whithin a certain block and the wiring for the block is like a
> namespace declaration. Different blocks can access the same block with
> different short names.
This is correct.
> I think this design is necessary for achieving scalability. If the short
> name was assumed to be unique, we would get name clashes between
> external blocks developers.
Absolutely: URI gets prefixed and are used only in the local wiring
context, they lose meaning if detached from the block that uses them.
Also because the "using" block is responsible for this mapping:
[ http://host/myBlock/3.4.34 -(requires)-> http://blah/skin/2.3 ]
--(calls it)--> "skin"
so, block:skin: used inside http://host/myBlock/3.4.34 will point to
whatever http://blah/skin/2.3 implementation you decided to wire it to,
but block:skin: used somewhere might route somewhere else.
So, "skin" has no absolute meaning, just local and it's still a solid
contract because it's defined by the requiring block, which is the only
one using and in-control-of that name.
>>> resolves it by looking up "skin" in the wiring info for the block
>>> (http://wiki.apache.org/cocoon/BlocksWiring) and find the mapping:
>>>
>>> skin -> http://mycompany.com/skins/corporate/34.3.345
>>
>>
>>
>> Beside mapping, BlocksManager can fetch an instance of the referenced
>> Block, i.e. its BlockManager. Not sure if URI by itself is needed at all.
>
>
> The BlockManagers could be wired to get direct access to each other
> during start up. In that case we don't need a global identifier during
> execution. I prefered to make all communication between the blocks
> proxied by the BlocksManager in the interest of isolation. But it is
> more of an implementation detail. Isolation can be achieved in other ways.
You don't need global block identifiers other than their URIs (which are
meant to be 'globally' unique, not just locally).
>>> in the connection section, where
>>> "http://mycompany.com/skins/corporate/34.3.345" uniquely identifies
>>> the specific skin implementation that has been choosen at deploy time.
>>>
>>> <comment>
>>> Is the URI unique enough? What if I want several variants of the skin
>>> that has different deployment parameters and implementations of
>>> theire connections.
>>
>>
>>
>> IIRC, URI is generated, at that time uniqueness is guaranteed by
>> BlocksManager (who created the URI).
>
>
> From http://wiki.apache.org/cocoon/BlockIdentification, I get the
> impression that URI is "universal" rather than locally generated at
> deploy time. I agree that a unique identifier created at deploy time by
> the BlocksManager is needed.
I disagree. You have a world-wide unique identifier (the URI) and a
local name in a well isolated context, and a wiring table to glue these
together (using the URIs) that's all you need.
>>> </comment>
>>>
>>> Interesting enough, IIUC, blocks are only accessible through the
>>> block protocol from other blocks,
>>
>>
>> No; IMHO they are all available through BlocksManager.
Well, no. The BlockManager has block 'scopes' and should allow a block
to resolve only the blocks that it explicitly depended upon and for
which it has a name for. The rest is just like it wasn't there... and
this is required to avoid polymorphism without unwanted collisions.
> They are, but AFAICS they have no common short name that could be used
> outside blocks, and it is the short name that is used by the block
> protocol.
Exactly.
> This could be solved by considering the main sitemap being part of a
> block as well and have a (possibly optional) block descriptor for it.
> Then the blocks would have a short name from the main sitemap as well.
YAGNI: if you need a block, declare that you need it and associate a
name with it. Otherwise, you don't need it, you don't have access to it.
--
Stefano.
Re: [RT] The block protocol
Posted by Vadim Gritsenko <va...@reverycodes.com>.
Daniel Fagerstrom wrote:
> Vadim Gritsenko wrote:
>
>> Daniel Fagerstrom wrote:
>>
>>> Inter block access
>>> ------------------
>>>
>>> An URI to another block "skin" e.g. looks like:
>>>
>>> block:skin:/foo/bar
>>>
>>> the BlockManager
>>
>>
>> You probably meant here "BlocksManager"
>
>
> No I meant BlockManager. In my discussion I assumed that a BlockManager
> is responsible for the information within a block element in the wiring
> (http://wiki.apache.org/cocoon/BlocksWiring) and that the BlocksManager
> "correspond" to the blocks element. So from this the BlocksManager only
> know the URI that identifies the block. The mapping from a short name to
> the URI
>
> skin -> http://mycompany.com/skins/corporate/34.3.345
>
> is only known localy whithin a BlockManager.
Yes, you are right. See my prev email about portal / profile block: portal knows
which profile it wants (URI), and BlocksManager can resolve block instance using
URI.
> The situation is AFAIU
> analoguos with the relation between a namespace URI and a namespace
> prefix. Where the URI is a universal identifier and the prefix works as
> a identifier within the document. In the same way the blocks URI is a
> universal identifier of the block while the short name only identifies
> it whithin a certain block and the wiring for the block is like a
> namespace declaration. Different blocks can access the same block with
> different short names.
Yep
>>> resolves it by looking up "skin" in the wiring info for the block
>>> (http://wiki.apache.org/cocoon/BlocksWiring) and find the mapping:
>>>
>>> skin -> http://mycompany.com/skins/corporate/34.3.345
Now we are on the same page. So BlockManager (or something else on its behalf -
like Wiring) looks up URI by the short name.
> The BlockManagers could be wired to get direct access to each other
> during start up. In that case we don't need a global identifier during
> execution. I prefered to make all communication between the blocks
> proxied by the BlocksManager in the interest of isolation.
Yes, once URI known, BlockManager should ask for other block instance from
BlocksManager (which might be as simple as this.manager.lookup()).
>>> in the connection section, where
>>> "http://mycompany.com/skins/corporate/34.3.345" uniquely identifies
>>> the specific skin implementation that has been choosen at deploy time.
>>>
>>> <comment>
>>> Is the URI unique enough? What if I want several variants of the skin
>>> that has different deployment parameters and implementations of
>>> theire connections.
>>
>>
>> IIRC, URI is generated, at that time uniqueness is guaranteed by
>> BlocksManager (who created the URI).
>
>
> From http://wiki.apache.org/cocoon/BlockIdentification, I get the
> impression that URI is "universal" rather than locally generated at
> deploy time.
Yes, my recall was wrong :-)
>>> </comment>
>>>
>>> Interesting enough, IIUC, blocks are only accessible through the
>>> block protocol from other blocks,
>>
>>
>> No; IMHO they are all available through BlocksManager.
>
>
> They are, but AFAICS they have no common short name that could be used
> outside blocks, and it is the short name that is used by the block
> protocol.
Which is resolved to URI which can be used to get a block from BlocksManager as
described above.
> This could be solved by considering the main sitemap being part of a
> block as well and have a (possibly optional) block descriptor for it.
> Then the blocks would have a short name from the main sitemap as well.
I thought about it... If there is a root block, then there will be *no* root
sitemap. As I see it, either you deploy root block (new behaviour), or you have
root sitemap (old one) which then can mount blocks as needed.
Vadim
Re: [RT] The block protocol
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Vadim Gritsenko wrote:
> Daniel Fagerstrom wrote:
>
>> --- o0o ---
>
>
> </lurk>
> Just some sidenotes...
>
>> The main involved components are the BlocksManager that in turn has
>> access to one BlockManager for each block.
>
>
> (From [1] BlockManager is the ServiceManager of the block)
Yes it is. We need to discuss the details about component managment in
blocks also. My mail was only about the block protocol aspect of the
architecture.
>> Block local access
>> ------------------
>>
>> Each BlockManager has its own SourceResolver and especially it can
>> have its own implementation of the block protocol which is registred
>> with the scheme "block:".
>>
>> An absolute URI relative to the root sitemap of the block looks like:
>>
>> block:/foo/bar
>>
>> and is a hierarchical URI. It is invoked by first trying "foo/bar" in
>> the current block's root sitemap and if that fails
>> "block:super:/foo/bar" is invoked.
>
>
> You don't need that. As mentioned in [1], local BlockManager has
> access to the parent BlockManager, so local BlockSource instance will
> lookup parent BlockSource and delegate to it. (Or may be this is just
> another way of saying the same? Hm.)
I think we mean the same.
>> More about "block:super:" later. To make this work I would assume
>> that error handling must work a little bit different in blocks so
>> that a sitemap can fail without emmiting any error messages immediatly.
>
> That's the only behaviour available in 2.1.6 and below.
Ok.
>> In the case when a block A has invoked an URI in its super block B,
>> to achieve polymorphism, all block protocoll resolution in B must be
>> done by first asking A's block resolver before trying its own.
>
>
> So it means local SourceResolver (or it's settings) should be
> preserved for the duration of polymorphic source processing.
Yes.
>> A relative URI in a sub sitemap "/foo" from the block's root sitemap,
>>
>> block:./bar
>>
>> (an opaque URI) is resolved to
>>
>> block:/foo/bar
>>
>> using the same method as Pier used for the cocoon protocol in his Wiki.
>>
>> Inter block access
>> ------------------
>>
>> An URI to another block "skin" e.g. looks like:
>>
>> block:skin:/foo/bar
>>
>> the BlockManager
>
> You probably meant here "BlocksManager"
No I meant BlockManager. In my discussion I assumed that a BlockManager
is responsible for the information within a block element in the wiring
(http://wiki.apache.org/cocoon/BlocksWiring) and that the BlocksManager
"correspond" to the blocks element. So from this the BlocksManager only
know the URI that identifies the block. The mapping from a short name to
the URI
skin -> http://mycompany.com/skins/corporate/34.3.345
is only known localy whithin a BlockManager. The situation is AFAIU
analoguos with the relation between a namespace URI and a namespace
prefix. Where the URI is a universal identifier and the prefix works as
a identifier within the document. In the same way the blocks URI is a
universal identifier of the block while the short name only identifies
it whithin a certain block and the wiring for the block is like a
namespace declaration. Different blocks can access the same block with
different short names.
I think this design is necessary for achieving scalability. If the short
name was assumed to be unique, we would get name clashes between
external blocks developers.
>> resolves it by looking up "skin" in the wiring info for the block
>> (http://wiki.apache.org/cocoon/BlocksWiring) and find the mapping:
>>
>> skin -> http://mycompany.com/skins/corporate/34.3.345
>
>
> Beside mapping, BlocksManager can fetch an instance of the referenced
> Block, i.e. its BlockManager. Not sure if URI by itself is needed at all.
The BlockManagers could be wired to get direct access to each other
during start up. In that case we don't need a global identifier during
execution. I prefered to make all communication between the blocks
proxied by the BlocksManager in the interest of isolation. But it is
more of an implementation detail. Isolation can be achieved in other ways.
>> in the connection section, where
>> "http://mycompany.com/skins/corporate/34.3.345" uniquely identifies
>> the specific skin implementation that has been choosen at deploy time.
>>
>> <comment>
>> Is the URI unique enough? What if I want several variants of the skin
>> that has different deployment parameters and implementations of
>> theire connections.
>
>
> IIRC, URI is generated, at that time uniqueness is guaranteed by
> BlocksManager (who created the URI).
From http://wiki.apache.org/cocoon/BlockIdentification, I get the
impression that URI is "universal" rather than locally generated at
deploy time. I agree that a unique identifier created at deploy time by
the BlocksManager is needed.
>> </comment>
>>
>> Interesting enough, IIUC, blocks are only accessible through the
>> block protocol from other blocks,
>
> No; IMHO they are all available through BlocksManager.
They are, but AFAICS they have no common short name that could be used
outside blocks, and it is the short name that is used by the block protocol.
This could be solved by considering the main sitemap being part of a
block as well and have a (possibly optional) block descriptor for it.
Then the blocks would have a short name from the main sitemap as well.
>> as the short name, "skin" e.g., only exists in the block wiring info.
>> Are we going to consider the main sitemap part of a block as well to
>> be able to access blocks from it?
>
> (I did not get this question).
Is it clearer from my explanations above.
>> Next the block manager asks the blocks manager for the URI,
>
> Nope. No need - it can simply ask for BlockManager.
>
>> this could be done through a "blocks:" protocol that is connected to
>> the blocks manager. The uri "block:skin:/foo/bar" could be resolved
>> to e.g.:
>>
>> blocks:{http://mycompany.com/skins/corporate/34.3.345}:/foo/bar
>>
>> Besides that it looks awfull I would doubt that it even is synatactic
>> correct as an opaque URI. I only wrote it down to provoke you to find
>> something better ;)
>
> IMHO, it (BlockManager) does not need URI of another block, at all. So
> no need for writing awful URIs :-P
See above.
>> Next the blocks manager looks up the block manager identified by
>> "http://mycompany.com/skins/corporate/34.3.345" and send the URI:
>>
>> block:/foo/bar
>>
>> to it, which will be resolved by the skin blocks internal
>> implementation of the block protocol.
>
> Yep.
>
>> block:super:/foo/bar
>>
>> is resolved in the same way as an ordinary external block URI. To
>> make this possible the role of being a super block must be
>> identifiable among the connections in the wiring info. Maybe by
>> reserving the name "super" for this case.
>>
>> WDYT?
>>
>> /Daniel
>
> Vadim
> <lurk>
>
> [1] http://wiki.apache.org/cocoon/22BlockImplementation
/Daniel
Re: [RT] The block protocol
Posted by Vadim Gritsenko <va...@reverycodes.com>.
Daniel Fagerstrom wrote:
> --- o0o ---
</lurk>
Just some sidenotes...
> The main involved components are the BlocksManager that in turn has
> access to one BlockManager for each block.
(From [1] BlockManager is the ServiceManager of the block)
> Block local access
> ------------------
>
> Each BlockManager has its own SourceResolver and especially it can have
> its own implementation of the block protocol which is registred with the
> scheme "block:".
>
> An absolute URI relative to the root sitemap of the block looks like:
>
> block:/foo/bar
>
> and is a hierarchical URI. It is invoked by first trying "foo/bar" in
> the current block's root sitemap and if that fails
> "block:super:/foo/bar" is invoked.
You don't need that. As mentioned in [1], local BlockManager has access to the
parent BlockManager, so local BlockSource instance will lookup parent
BlockSource and delegate to it. (Or may be this is just another way of saying
the same? Hm.)
> More about "block:super:" later. To
> make this work I would assume that error handling must work a little bit
> different in blocks so that a sitemap can fail without emmiting any
> error messages immediatly.
That's the only behaviour available in 2.1.6 and below.
> In the case when a block A has invoked an URI in its super block B, to
> achieve polymorphism, all block protocoll resolution in B must be done
> by first asking A's block resolver before trying its own.
So it means local SourceResolver (or it's settings) should be preserved for the
duration of polymorphic source processing.
> A relative URI in a sub sitemap "/foo" from the block's root sitemap,
>
> block:./bar
>
> (an opaque URI) is resolved to
>
> block:/foo/bar
>
> using the same method as Pier used for the cocoon protocol in his Wiki.
>
> Inter block access
> ------------------
>
> An URI to another block "skin" e.g. looks like:
>
> block:skin:/foo/bar
>
> the BlockManager
You probably meant here "BlocksManager"
> resolves it by looking up "skin" in the wiring info for
> the block (http://wiki.apache.org/cocoon/BlocksWiring) and find the
> mapping:
>
> skin -> http://mycompany.com/skins/corporate/34.3.345
Beside mapping, BlocksManager can fetch an instance of the referenced Block,
i.e. its BlockManager. Not sure if URI by itself is needed at all.
> in the connection section, where
> "http://mycompany.com/skins/corporate/34.3.345" uniquely identifies the
> specific skin implementation that has been choosen at deploy time.
>
> <comment>
> Is the URI unique enough? What if I want several variants of the skin
> that has different deployment parameters and implementations of theire
> connections.
IIRC, URI is generated, at that time uniqueness is guaranteed by BlocksManager
(who created the URI).
> </comment>
>
> Interesting enough, IIUC, blocks are only accessible through the block
> protocol from other blocks,
No; IMHO they are all available through BlocksManager.
> as the short name, "skin" e.g., only exists
> in the block wiring info. Are we going to consider the main sitemap part
> of a block as well to be able to access blocks from it?
(I did not get this question).
> Next the block manager asks the blocks manager for the URI,
Nope. No need - it can simply ask for BlockManager.
> this could
> be done through a "blocks:" protocol that is connected to the blocks
> manager. The uri "block:skin:/foo/bar" could be resolved to e.g.:
>
> blocks:{http://mycompany.com/skins/corporate/34.3.345}:/foo/bar
>
> Besides that it looks awfull I would doubt that it even is synatactic
> correct as an opaque URI. I only wrote it down to provoke you to find
> something better ;)
IMHO, it (BlockManager) does not need URI of another block, at all. So no need
for writing awful URIs :-P
> Next the blocks manager looks up the block manager identified by
> "http://mycompany.com/skins/corporate/34.3.345" and send the URI:
>
> block:/foo/bar
>
> to it, which will be resolved by the skin blocks internal implementation
> of the block protocol.
Yep.
> block:super:/foo/bar
>
> is resolved in the same way as an ordinary external block URI. To make
> this possible the role of being a super block must be identifiable among
> the connections in the wiring info. Maybe by reserving the name "super"
> for this case.
>
> WDYT?
>
> /Daniel
Vadim
<lurk>
[1] http://wiki.apache.org/cocoon/22BlockImplementation
Re: [RT] The block protocol
Posted by Stefano Mazzocchi <st...@apache.org>.
Reinhard Poetz wrote:
> Vadim Gritsenko wrote:
>
>> Reinhard Poetz wrote:
>>
>>> Ralph Goers wrote:
>>>
>>>> Daniel Fagerstrom wrote:
>>>>
>>>> Portal block
>>>> ------------
>>>> - requires "MyProfile" that implements "profile"
>>
>>
>>
>> Correction:
>>
>> - Requires implementation of "profile" interface.
>> "profile" is implemented by "MyProfile1",
>> "MyProfile2", ..., "MyProfileN".
>>
>>
>>>> <profiles>
>>>> <copletbasedata-load
>>>> uri="blocks:profile:/load-global-profile?profile=copletbasedata"/>
>>>> <copletdata-global-load
>>>> uri="blocks:profile:/load-global-profile?profile=copletdata"/>
>>>> ..
>>>> </profiles>
>>>>
>>>> The problem with this example is that is not how the portal works,
>>>> nor would I ever want the portal to require that a block with a
>>>> specific name be present as this prohibits two portal
>>>> implementations from being present in the same webapp.
>>>
>>>
>>>
>>>
>>> That's not true. You can deploy as many portal applications as real
>>> blocks as you want.
>>
>>
>>
>> Yes
>>
>>
>>> And, if you don't like dependencies (references, extensions) just
>>> don't use them.
>>
>>
>>
>> And No. If portal block requires implementation of profile block,
>> during its deployment time you will pick up an implementation you like
>> for each instance of portal block.
>
>
> ... stand corrected
>
> and you have always the chance that you can do it the same way as it is
> done now: simply copy everything that you need into your own application.
>
> If people really want this, the portal block could have a "base" version
> that only contains the components (e.g. the PortalGenerator) and a
> "default" version that extends the base version and requires a "profile"
> block.
>
> Then people who like blocks and that functionality is spreat over
> several blocks extend the "default" version and people who don't want to
> change the way how they work with Cocoon, use the "base" block that only
> contains components.
There are two concerns here, not totally unrelated, but enough so:
1) what features should the block system have
2) what is the best way to use those features in order to achieve what
I need
We have a pretty good understanding of 1) (and meets *all* the
requirements that I came across so far!) but have no idea on best
practices for 2)
I would strongly suggest we avoid discussing #2 before we even implement
#1 to test it out.
Obviously, the two cannot be completely isolated, because #1 influences
#2 and problems in #2 should influence back #1, so the cycle will be
iterative, but for now, let's focus on what we understand of #1 and move
on until we have a better understanding of the problems on #2.
--
Stefano.
Re: [RT] The block protocol
Posted by Reinhard Poetz <re...@apache.org>.
Vadim Gritsenko wrote:
> Reinhard Poetz wrote:
>
>> Ralph Goers wrote:
>>
>>> Daniel Fagerstrom wrote:
>>>
>>> Portal block
>>> ------------
>>> - requires "MyProfile" that implements "profile"
>
>
> Correction:
>
> - Requires implementation of "profile" interface.
> "profile" is implemented by "MyProfile1",
> "MyProfile2", ..., "MyProfileN".
>
>
>>> <profiles>
>>> <copletbasedata-load
>>> uri="blocks:profile:/load-global-profile?profile=copletbasedata"/>
>>> <copletdata-global-load
>>> uri="blocks:profile:/load-global-profile?profile=copletdata"/>
>>> ..
>>> </profiles>
>>>
>>> The problem with this example is that is not how the portal works,
>>> nor would I ever want the portal to require that a block with a
>>> specific name be present as this prohibits two portal implementations
>>> from being present in the same webapp.
>>
>>
>>
>> That's not true. You can deploy as many portal applications as real
>> blocks as you want.
>
>
> Yes
>
>
>> And, if you don't like dependencies (references, extensions) just
>> don't use them.
>
>
> And No. If portal block requires implementation of profile block, during
> its deployment time you will pick up an implementation you like for each
> instance of portal block.
... stand corrected
and you have always the chance that you can do it the same way as it is done
now: simply copy everything that you need into your own application.
If people really want this, the portal block could have a "base" version that
only contains the components (e.g. the PortalGenerator) and a "default" version
that extends the base version and requires a "profile" block.
Then people who like blocks and that functionality is spreat over several blocks
extend the "default" version and people who don't want to change the way how
they work with Cocoon, use the "base" block that only contains components.
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] The block protocol
Posted by Vadim Gritsenko <va...@reverycodes.com>.
Reinhard Poetz wrote:
> Ralph Goers wrote:
>
>> Daniel Fagerstrom wrote:
>>
>> Portal block
>> ------------
>> - requires "MyProfile" that implements "profile"
Correction:
- Requires implementation of "profile" interface.
"profile" is implemented by "MyProfile1",
"MyProfile2", ..., "MyProfileN".
>> <profiles>
>> <copletbasedata-load
>> uri="blocks:profile:/load-global-profile?profile=copletbasedata"/>
>> <copletdata-global-load
>> uri="blocks:profile:/load-global-profile?profile=copletdata"/>
>> ..
>> </profiles>
>>
>> The problem with this example is that is not how the portal works, nor
>> would I ever want the portal to require that a block with a specific
>> name be present as this prohibits two portal implementations from
>> being present in the same webapp.
>
>
> That's not true. You can deploy as many portal applications as real
> blocks as you want.
Yes
> And, if you don't like dependencies (references,
> extensions) just don't use them.
And No. If portal block requires implementation of profile block, during its
deployment time you will pick up an implementation you like for each instance of
portal block.
Vadim
Re: [RT] The block protocol
Posted by Reinhard Poetz <re...@apache.org>.
Ralph Goers wrote:
> Daniel Fagerstrom wrote:
>
>> is resolved in the same way as an ordinary external block URI. To make
>> this possible the role of being a super block must be identifiable
>> among the connections in the wiring info. Maybe by reserving the name
>> "super" for this case.
>>
>> WDYT?
>>
>> /Daniel
>
>
> A few thoughts here (that aren't necessarily directed at you):
> 1. I may have missed some points in this discussion. When the email gets
> to be long or quotes previous nested emails in their entirety I tend to
> just move on and ignore the post. So, as a rule I would recommend
> keeping posts as short and sweet as possible. If you'll notice, there
> have only been a few participants in these discussions. Maybe its just
> me, but I wonder if others aren't jumping in with their thoughts for the
> same reason.
I have the same feeling - but discussing based on examples is difficult,
especially if the examples are very long ...
> 2. I've noticed a few discussions that are mainly between you and
> Reinhard with other folks posting occaisionally. Although you two may
> come to agreement on some ideas, given item 1 I wonder if it actually is
> the concensus of the community.
No, I don't think that everybody who hasn't contributed to the discussion is in
agreement with Daniel, Stefano and me. It will be much easier when the first
prototype is available.
> Maybe I'm wrong though, and maybe most
> of the commtters just aren't interested.
I don't understand this. If somebody isn't interested, he shouldn't have a
problem with the discussion. It's a bigger problem that if people *were*
interested and don't like the long mails that they would have to say important
things but they don't want to invest that much time in following the discussions.
As said in my reply to Betrand's mail, I will try to revise the original design
proposal by Stefano (as far as I can see there are only some minor things that
have changed or were extended + I will also add relevant links to mails)
> 3. I've had a real problem with the previous "blocks" discussion and how
> it used the Portal as an example. I'm not sure that it is actually
> understood what needs to happen with the portal to make it into a "real
> block". The issue with the portal is that the framework (what would be
> the portal block) requires quite a few definitions, both in components
> and in the sitemap. These definitions must be provided by the portal
> implementation. If the portal implementation must provide the
> definitions then there really is no need for a block protocol as there
> is nothing in the portal block to invoke, other than the sitemap
> components provided by it. In message
> http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=111245388030013&w=2,
> Reinhard said "The block "portal" only contains pipelines calls which
> the block "profile" provides in its sitemap
>
> Portal block
> ------------
> - requires "MyProfile" that implements "profile"
>
> <profiles>
> <copletbasedata-load
> uri="blocks:profile:/load-global-profile?profile=copletbasedata"/>
> <copletdata-global-load
> uri="blocks:profile:/load-global-profile?profile=copletdata"/>
> ..
> </profiles>
>
> The problem with this example is that is not how the portal works, nor
> would I ever want the portal to require that a block with a specific
> name be present as this prohibits two portal implementations from being
> present in the same webapp.
That's not true. You can deploy as many portal applications as real blocks as
you want. And, if you don't like dependencies (references, extensions) just
don't use them. The example above was for the sake of showing that things *can*
be separated if people like it. E.g. you could deploy 5 portal applications all
using the same skin block.
In fact, these definitions must be in the
> application, not the portal block.
as said above, it's your choice. If you want to do things in the future as you
have always done, put your application into a single block and only minor things
will change for you (you have to provide a block.xml file, that's it).
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] The block protocol
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Ralph Goers wrote:
> Daniel Fagerstrom wrote:
>
>> is resolved in the same way as an ordinary external block URI. To
>> make this possible the role of being a super block must be
>> identifiable among the connections in the wiring info. Maybe by
>> reserving the name "super" for this case.
>>
>> WDYT?
>>
>> /Daniel
>
>
> A few thoughts here (that aren't necessarily directed at you):
> 1. I may have missed some points in this discussion. When the email
> gets to be long or quotes previous nested emails in their entirety I
> tend to just move on and ignore the post. So, as a rule I would
> recommend keeping posts as short and sweet as possible.
While I agree in general, It is quite hard to achieve. At some point we
need to get from discussing about the general requirements and the broad
vision about things, and get into designing the gory details. And at
that point we need to use examples (which takes place) to assure that
our proposed solutions actually work and that we talking about the same
things. It is also necessary to discuss some edge cases that most users
hopefully don't need to understand, but which would bite them if we
didin't take care about them in the design.
> If you'll notice, there have only been a few participants in these
> discussions. Maybe its just me, but I wonder if others aren't jumping
> in with their thoughts for the same reason.
I have certainly noticed that there are few participant in the
discussion. I think an important reason is that the discussed subject
(blocks) is rather difficult and takes quite some while to learn enough
about to be able to participate in detailed design discussions.
For my own part I found blocks attractive and important from the very
beginning, when Stefano presented them maybe three years ago. But it
took me long time before I started to participate in the discussions as
the focus on the blocks work in the beginning was about things that I
didn't know much about. People believed that it was necessary to switch
component manager before we could start to actually implement blocks.
And I didn't know much about componment managers back then.
Anyway, if you (or others) think that we are dicussing something that
you would like to participate in but is lost in all the details, just
ask us about some background or for a summary of the issues. As long as
you don't comment it is hard to know if anyone reads. And the allready
long mails would be endless if we by default started with a summary of
the whole thread.
> 2. I've noticed a few discussions that are mainly between you and
> Reinhard with other folks posting occaisionally. Although you two may
> come to agreement on some ideas, given item 1 I wonder if it actually
> is the concensus of the community.
I'm certain that people will start to have opinions when we start to
have an implementation. Until then lazy concensus is enough.
<snip>stuff that Reinhard commented</snip>
/Daniel
Re: [RT] The block protocol
Posted by Bertrand Delacretaz <bd...@apache.org>.
Le 5 avr. 05, à 09:10, Reinhard Poetz a écrit :
> ...I will revise http://wiki.apache.org/cocoon/Blocks (this weekend or
> next week)
Thanks - wiki pages also make good "discussion checkpoints", and might
allow more people to give feedback on the design.
-Bertrand
--
Bertrand Delacretaz
independent consultant, Lausanne, Switzerland
http://www.codeconsult.ch
Re: [RT] The block protocol
Posted by Reinhard Poetz <re...@apache.org>.
Bertrand Delacretaz wrote:
> Le 5 avr. 05, à 04:42, Ralph Goers a écrit :
>
>> ...When the email gets to be long or quotes previous nested emails in
>> their entirety I tend to just move on and ignore the post...
>
>
> FWIW, it is exactly my case: not enough time to follow these loooong
> emails. The mailing-list discussion mode makes it very hard to work on
> such (important I'm afraid) design issues collectively.
>
> Not that I have a solution, just wanted to reinforce what Ralph is
> saying. Or maybe one suggestion: if the people involved in these
> discussions could post [SUMMARY] messages as a kind of checkpoint along
> the way from time to time, it might help more people get involved based
> on what's been agreed in the discussion so far.
as said the discussions were very long and maybe Daniel, Stefano and I were the
only ones who were able to follow it.
I will revise http://wiki.apache.org/cocoon/Blocks (this weekend or next week)
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] The block protocol
Posted by Bertrand Delacretaz <bd...@apache.org>.
Le 5 avr. 05, à 04:42, Ralph Goers a écrit :
> ...When the email gets to be long or quotes previous nested emails in
> their entirety I tend to just move on and ignore the post...
FWIW, it is exactly my case: not enough time to follow these loooong
emails. The mailing-list discussion mode makes it very hard to work on
such (important I'm afraid) design issues collectively.
Not that I have a solution, just wanted to reinforce what Ralph is
saying. Or maybe one suggestion: if the people involved in these
discussions could post [SUMMARY] messages as a kind of checkpoint along
the way from time to time, it might help more people get involved based
on what's been agreed in the discussion so far.
-Bertrand
Re: [RT] The block protocol
Posted by Ralph Goers <Ra...@dslextreme.com>.
Daniel Fagerstrom wrote:
> is resolved in the same way as an ordinary external block URI. To make
> this possible the role of being a super block must be identifiable
> among the connections in the wiring info. Maybe by reserving the name
> "super" for this case.
>
> WDYT?
>
> /Daniel
A few thoughts here (that aren't necessarily directed at you):
1. I may have missed some points in this discussion. When the email gets
to be long or quotes previous nested emails in their entirety I tend to
just move on and ignore the post. So, as a rule I would recommend
keeping posts as short and sweet as possible. If you'll notice, there
have only been a few participants in these discussions. Maybe its just
me, but I wonder if others aren't jumping in with their thoughts for the
same reason.
2. I've noticed a few discussions that are mainly between you and
Reinhard with other folks posting occaisionally. Although you two may
come to agreement on some ideas, given item 1 I wonder if it actually is
the concensus of the community. Maybe I'm wrong though, and maybe most
of the commtters just aren't interested.
3. I've had a real problem with the previous "blocks" discussion and how
it used the Portal as an example. I'm not sure that it is actually
understood what needs to happen with the portal to make it into a "real
block". The issue with the portal is that the framework (what would be
the portal block) requires quite a few definitions, both in components
and in the sitemap. These definitions must be provided by the portal
implementation. If the portal implementation must provide the
definitions then there really is no need for a block protocol as there
is nothing in the portal block to invoke, other than the sitemap
components provided by it. In message
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=111245388030013&w=2,
Reinhard said "The block "portal" only contains pipelines calls which
the block "profile" provides in its sitemap
Portal block
------------
- requires "MyProfile" that implements "profile"
<profiles>
<copletbasedata-load
uri="blocks:profile:/load-global-profile?profile=copletbasedata"/>
<copletdata-global-load
uri="blocks:profile:/load-global-profile?profile=copletdata"/>
..
</profiles>
The problem with this example is that is not how the portal works, nor
would I ever want the portal to require that a block with a specific
name be present as this prohibits two portal implementations from being
present in the same webapp. In fact, these definitions must be in the
application, not the portal block.
Ralph
[RT] The block protocol (was: RFC-2396)
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Daniel Fagerstrom wrote:
> Pier Fumagalli wrote:
>> On 4 Apr 2005, at 16:26, Daniel Fagerstrom wrote:
>>> Pier Fumagalli wrote:
>>>> On 31 Mar 2005, at 01:26, Stefano Mazzocchi wrote:
>>>>>
>>>>> block:super://blah.xml
>>>>
>>>> A very simple remark, I don't want to criticise...
>>>>
>>>> I'm already slightly "upset" about the "cocoon://" protocol, as it
>>>> does not follow the URI RFC properly, I'd like to address the
>>>> problem as early as possible...
>>>>
>>>> http://www.ietf.org/rfc/rfc2396.txt
>>>>
>>>> I wrote a small "rant" while on the plane, just to explain my
>>>> reasoning, with a couple of code examples, as it's (I don't think)
>>>> mailing-list material, I've stored it on my WIKI...
>>>>
>>>> http://www.betaversion.org/~pier/wiki/display/pier/Cocoon+and+URIs
<snip/>
>> Exactly... That's why I'm thinking that the URI should be this:
>>
>> block:portal:/foo
>>
>> block is an opaque URI, whose scheme specific part _is_ a valid URI by
>> itself.
>>
>> portal:/foo is a valid URI, but if (for example) you think about other
>> cases, this URI could be
>>
>> block:xmlrpc://www.myrpcserver.dom/entry/point
>>
>> block: opaque URI
>> xmlrpc: valid URI whose scheme specific part (whether it's opaque,
>> absolute, relative, blah) is only known by the "xmlrpc" handler...
>>
>> block:portal:/foo
>>
>> What's "/foo"? Only the portal block knows it...
<snip/>
I have thougth a litle bit more about the block URI and the architecture
around it so I do a new trial.
--- o0o ---
The main involved components are the BlocksManager that in turn has
access to one BlockManager for each block.
Block local access
------------------
Each BlockManager has its own SourceResolver and especially it can have
its own implementation of the block protocol which is registred with the
scheme "block:".
An absolute URI relative to the root sitemap of the block looks like:
block:/foo/bar
and is a hierarchical URI. It is invoked by first trying "foo/bar" in
the current block's root sitemap and if that fails
"block:super:/foo/bar" is invoked. More about "block:super:" later. To
make this work I would assume that error handling must work a little bit
different in blocks so that a sitemap can fail without emmiting any
error messages immediatly.
In the case when a block A has invoked an URI in its super block B, to
achieve polymorphism, all block protocoll resolution in B must be done
by first asking A's block resolver before trying its own.
A relative URI in a sub sitemap "/foo" from the block's root sitemap,
block:./bar
(an opaque URI) is resolved to
block:/foo/bar
using the same method as Pier used for the cocoon protocol in his Wiki.
Inter block access
------------------
An URI to another block "skin" e.g. looks like:
block:skin:/foo/bar
the BlockManager resolves it by looking up "skin" in the wiring info for
the block (http://wiki.apache.org/cocoon/BlocksWiring) and find the mapping:
skin -> http://mycompany.com/skins/corporate/34.3.345
in the connection section, where
"http://mycompany.com/skins/corporate/34.3.345" uniquely identifies the
specific skin implementation that has been choosen at deploy time.
<comment>
Is the URI unique enough? What if I want several variants of the skin
that has different deployment parameters and implementations of theire
connections.
</comment>
Interesting enough, IIUC, blocks are only accessible through the block
protocol from other blocks, as the short name, "skin" e.g., only exists
in the block wiring info. Are we going to consider the main sitemap part
of a block as well to be able to access blocks from it?
Next the block manager asks the blocks manager for the URI, this could
be done through a "blocks:" protocol that is connected to the blocks
manager. The uri "block:skin:/foo/bar" could be resolved to e.g.:
blocks:{http://mycompany.com/skins/corporate/34.3.345}:/foo/bar
Besides that it looks awfull I would doubt that it even is synatactic
correct as an opaque URI. I only wrote it down to provoke you to find
something better ;)
Next the blocks manager looks up the block manager identified by
"http://mycompany.com/skins/corporate/34.3.345" and send the URI:
block:/foo/bar
to it, which will be resolved by the skin blocks internal implementation
of the block protocol.
block:super:/foo/bar
is resolved in the same way as an ordinary external block URI. To make
this possible the role of being a super block must be identifiable among
the connections in the wiring info. Maybe by reserving the name "super"
for this case.
WDYT?
/Daniel
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Pier Fumagalli wrote:
>
> On 4 Apr 2005, at 16:26, Daniel Fagerstrom wrote:
>
>> Pier Fumagalli wrote:
>>
>>> On 31 Mar 2005, at 01:26, Stefano Mazzocchi wrote:
>>>
>>>>
>>>> block:super://blah.xml
>>>
>>>
>>>
>>> A very simple remark, I don't want to criticise...
>>>
>>> I'm already slightly "upset" about the "cocoon://" protocol, as it
>>> does not follow the URI RFC properly, I'd like to address the
>>> problem as early as possible...
>>>
>>> http://www.ietf.org/rfc/rfc2396.txt
>>
>>
>>>
>>> I wrote a small "rant" while on the plane, just to explain my
>>> reasoning, with a couple of code examples, as it's (I don't think)
>>> mailing-list material, I've stored it on my WIKI...
>>>
>>> http://www.betaversion.org/~pier/wiki/display/pier/Cocoon+and+URIs
>>>
>>> Anyhow, feel free to discuss it here...
>>
>>
>> I read your rant and agree with it, it seem benefical to take
>> advantage of java.net.URI. I'm not completely happy with letting
>> relative sitemap paths be opaque and absolute be hierarchical, but I
>> don't see any better alternatives.
>
>
> The thing is that the scheme specific part of the opaque URI, is
> actually a relative URI which can be resolved against an absolute one...
>
> URI relative_uri =
> absolute_uri.resolve(opaque_uri.getSchemeSpecificPart());
>
> As simple as that...
>
>>
>> Concerning:
>>
>> block:super://blah.xml
>>
>> it is AFAICS a correct opaque URI. But we could make better use of
>> java.net.URI if we considered a hierarchial URI scheme for blocks
>> instead. From this perspective the scheme that Reinhard suggested
>> makes sense
>>
>> block://portal/foo
>>
>> for refering to the absoute path "/foo" within the portal block,
>>
>> block:/foo
>>
>> for refering to the absolute path "/foo" within the current block and
>>
>> block:./bar
>>
>> for refering to the relative path "bar" relative to the current
>> (sub)sitemap within the current block and
>>
>> block:super:/foo
>>
>> for refering to the absolute path "foo" whithin the super block of
>> the current and possibly
>>
>> block:super:./bar
>>
>> for refering to the relative path "bar" relative to the current
>> (sub)sitemap within the super block of the current.
>>
>> The last three URIs are opaque and could be resolved to absolute
>> hierarchical URIs with a similar algorithm as you proposed for
>> "cocoon:./" resolution.
>>
>> Maybe using "//portal" as an authority is stretching the
>> intepretation to far.
>
>
> Exactly... That's why I'm thinking that the URI should be this:
>
> block:portal:/foo
>
> block is an opaque URI, whose scheme specific part _is_ a valid URI by
> itself.
>
> portal:/foo is a valid URI, but if (for example) you think about other
> cases, this URI could be
>
> block:xmlrpc://www.myrpcserver.dom/entry/point
>
> block: opaque URI
> xmlrpc: valid URI whose scheme specific part (whether it's opaque,
> absolute, relative, blah) is only known by the "xmlrpc" handler...
>
> block:portal:/foo
>
> What's "/foo"? Only the portal block knows it...
Ok, that makes sense. The specific blocks handler resolve the scheme
specific part. If we follow this path the blocks descriptor
(http://wiki.apache.org/cocoon/BlocksCob) must be extended with a
declaration about what source resolver to use.
It would still be good to have a default resolver for all blocks that
doesn't have specific needs, so that we get some coherence for our
blocks. And there we could use hierarchical URIs like those you propsed
in your wiki for the cocoon: protocol.
Question is how i.e. the portal block refers to its own pipes. If you
take a look at http://wiki.apache.org/cocoon/BlocksCob a block doesn't
have a short name for it self that can be used as scheme, it only
declares such names for the blocks it requires, so portal: doesn't make
any sense within the portal block. So within the specific block we could
maybe use:
block:/foo, block:./bar, block:super:/foo, block:super:./bar
whith the same intepretation as I suggested above (for the default
resolver).
This could be done in the way that each block define its own resolver
and bind it to the scheme block:, then when a block, portal e.g. use an
URI to another block, the block manager (for portal) will get an URI like:
block:skin:/foo
it will then find the block manager for the skin block and ask it to resolve
block:/foo
Which will use the resolver from the skin block.
/Daniel
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Stefano Mazzocchi <st...@apache.org>.
Pier Fumagalli wrote:
> The only problem I have with "block:super://blah.xml" is that "//" in an
> URI indicates the start of the authority part, and this is defined as
> "user@host:port", and no matter how you see it, "block:...anything..."
> _is_ a URI, and thus should follow its spec...
>
> Pier
>
>>
>> --- o0o ---
>>
>> As all URI discussions tend to provoke strong feelings for Stefano,
>> it's best to say directly that this question is not important enough
>> for me to fight about ;)
Despite dry humor, I have no problems deprecating the use of // in the
cocoon: and block: URI scheme.
--
Stefano.
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Pier Fumagalli <pi...@betaversion.org>.
On 4 Apr 2005, at 16:26, Daniel Fagerstrom wrote:
> Pier Fumagalli wrote:
>
>> On 31 Mar 2005, at 01:26, Stefano Mazzocchi wrote:
>>
>>>
>>> block:super://blah.xml
>>
>>
>> A very simple remark, I don't want to criticise...
>>
>> I'm already slightly "upset" about the "cocoon://" protocol, as it
>> does not follow the URI RFC properly, I'd like to address the problem
>> as early as possible...
>>
>> http://www.ietf.org/rfc/rfc2396.txt
>
>>
>> I wrote a small "rant" while on the plane, just to explain my
>> reasoning, with a couple of code examples, as it's (I don't think)
>> mailing-list material, I've stored it on my WIKI...
>>
>> http://www.betaversion.org/~pier/wiki/display/pier/Cocoon+and+URIs
>>
>> Anyhow, feel free to discuss it here...
>
> I read your rant and agree with it, it seem benefical to take
> advantage of java.net.URI. I'm not completely happy with letting
> relative sitemap paths be opaque and absolute be hierarchical, but I
> don't see any better alternatives.
The thing is that the scheme specific part of the opaque URI, is
actually a relative URI which can be resolved against an absolute
one...
URI relative_uri =
absolute_uri.resolve(opaque_uri.getSchemeSpecificPart());
As simple as that...
>
> Concerning:
>
> block:super://blah.xml
>
> it is AFAICS a correct opaque URI. But we could make better use of
> java.net.URI if we considered a hierarchial URI scheme for blocks
> instead. From this perspective the scheme that Reinhard suggested
> makes sense
>
> block://portal/foo
>
> for refering to the absoute path "/foo" within the portal block,
>
> block:/foo
>
> for refering to the absolute path "/foo" within the current block and
>
> block:./bar
>
> for refering to the relative path "bar" relative to the current
> (sub)sitemap within the current block and
>
> block:super:/foo
>
> for refering to the absolute path "foo" whithin the super block of the
> current and possibly
>
> block:super:./bar
>
> for refering to the relative path "bar" relative to the current
> (sub)sitemap within the super block of the current.
>
> The last three URIs are opaque and could be resolved to absolute
> hierarchical URIs with a similar algorithm as you proposed for
> "cocoon:./" resolution.
>
> Maybe using "//portal" as an authority is stretching the intepretation
> to far.
Exactly... That's why I'm thinking that the URI should be this:
block:portal:/foo
block is an opaque URI, whose scheme specific part _is_ a valid URI by
itself.
portal:/foo is a valid URI, but if (for example) you think about other
cases, this URI could be
block:xmlrpc://www.myrpcserver.dom/entry/point
block: opaque URI
xmlrpc: valid URI whose scheme specific part (whether it's opaque,
absolute, relative, blah) is only known by the "xmlrpc" handler...
block:portal:/foo
What's "/foo"? Only the portal block knows it...
> Using an URIs like the ones above has the advantage that we can reuse
> most of the definition of hierarchial URIs and the functionality in
> java.net.URI, if we instead go for the opaque style exemplified by
> "block:super://blah.xml" we have to define the URI parsing ourselves
> instead.
The only problem I have with "block:super://blah.xml" is that "//" in
an URI indicates the start of the authority part, and this is defined
as "user@host:port", and no matter how you see it,
"block:...anything..." _is_ a URI, and thus should follow its spec...
Pier
>
> --- o0o ---
>
> As all URI discussions tend to provoke strong feelings for Stefano,
> it's best to say directly that this question is not important enough
> for me to fight about ;)
>
> But anyway, whether we go for an opaque custom protocol or base the
> block protocol on hierachial URIs we need to get into the specifics
> for the block URI scheme to be able to implement it.
>
> WDYT?
>
> /Daniel
>
>
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Pier Fumagalli wrote:
> On 31 Mar 2005, at 01:26, Stefano Mazzocchi wrote:
>
>>
>> block:super://blah.xml
>
>
> A very simple remark, I don't want to criticise...
>
> I'm already slightly "upset" about the "cocoon://" protocol, as it
> does not follow the URI RFC properly, I'd like to address the problem
> as early as possible...
>
> http://www.ietf.org/rfc/rfc2396.txt
>
> I wrote a small "rant" while on the plane, just to explain my
> reasoning, with a couple of code examples, as it's (I don't think)
> mailing-list material, I've stored it on my WIKI...
>
> http://www.betaversion.org/~pier/wiki/display/pier/Cocoon+and+URIs
>
> Anyhow, feel free to discuss it here...
I read your rant and agree with it, it seem benefical to take advantage
of java.net.URI. I'm not completely happy with letting relative sitemap
paths be opaque and absolute be hierarchical, but I don't see any better
alternatives.
Concerning:
block:super://blah.xml
it is AFAICS a correct opaque URI. But we could make better use of
java.net.URI if we considered a hierarchial URI scheme for blocks
instead. From this perspective the scheme that Reinhard suggested makes
sense
block://portal/foo
for refering to the absoute path "/foo" within the portal block,
block:/foo
for refering to the absolute path "/foo" within the current block and
block:./bar
for refering to the relative path "bar" relative to the current
(sub)sitemap within the current block and
block:super:/foo
for refering to the absolute path "foo" whithin the super block of the
current and possibly
block:super:./bar
for refering to the relative path "bar" relative to the current
(sub)sitemap within the super block of the current.
The last three URIs are opaque and could be resolved to absolute
hierarchical URIs with a similar algorithm as you proposed for
"cocoon:./" resolution.
Maybe using "//portal" as an authority is stretching the intepretation
to far.
Using an URIs like the ones above has the advantage that we can reuse
most of the definition of hierarchial URIs and the functionality in
java.net.URI, if we instead go for the opaque style exemplified by
"block:super://blah.xml" we have to define the URI parsing ourselves
instead.
--- o0o ---
As all URI discussions tend to provoke strong feelings for Stefano, it's
best to say directly that this question is not important enough for me
to fight about ;)
But anyway, whether we go for an opaque custom protocol or base the
block protocol on hierachial URIs we need to get into the specifics for
the block URI scheme to be able to implement it.
WDYT?
/Daniel
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Stefano Mazzocchi <st...@apache.org>.
Daniel Fagerstrom wrote:
> Colin Paul Adams wrote:
>
>>>>>>> "Pier" == Pier Fumagalli <pi...@betaversion.org> writes:
>>>>>>>
>>
>>
>> Pier> I'm already slightly "upset" about the "cocoon://" protocol,
>> Pier> as it does not follow the URI RFC properly, I'd like to
>> Pier> address the problem as early as possible...
>>
>> Pier> http://www.ietf.org/rfc/rfc2396.txt
>>
>> I don't know if this is relevant to the discussion, but are you aware
>> that this RFC has been obsoleted by RFC 3986?
>>
>>
> It has some relevance to the discussion as it seem (chap 3.) to allow a
> hierarchical URI at the form:
>
> cocoon:foo/bar
>
> where "foo/bar" is called a root less path. But I don't find any
> explanation about what it is supposed to mean.
that's the point of a general URI syntax: the meaning is not defined.
It's just XML for strings really. The semantics are not defined there.
--
Stefano.
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Colin Paul Adams wrote:
>>>>>>"Daniel" == Daniel Fagerstrom <da...@nada.kth.se> writes:
>
>
> Daniel> cocoon:foo/bar
>
> Daniel> where "foo/bar" is called a root less path. But I don't
> Daniel> find any explanation about what it is supposed to mean.
>
> Well, it could mean anything the protocol inventor intended.
> Not all URI schemes are hierarchical in nature. This does not mean
> they cannot use the / character.
Thing is that foo/bar in the example above actually is supposed to be a
hierarchy consisting of the segments foo and bar according to rfc3986.
But after having checked it closer, the comment in the end of chapter 5
seem to mean that is shouldn't be used and only is part of the spec to
cover a loophole in rfc1630 the predecessor of rfc2396. So we shouldn't
use it anyway.
/Daniel
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Colin Paul Adams <co...@colina.demon.co.uk>.
>>>>> "Daniel" == Daniel Fagerstrom <da...@nada.kth.se> writes:
Daniel> cocoon:foo/bar
Daniel> where "foo/bar" is called a root less path. But I don't
Daniel> find any explanation about what it is supposed to mean.
Well, it could mean anything the protocol inventor intended.
Not all URI schemes are hierarchical in nature. This does not mean
they cannot use the / character.
--
Colin Paul Adams
Preston Lancashire
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Colin Paul Adams wrote:
>>>>>>"Pier" == Pier Fumagalli <pi...@betaversion.org> writes:
>>>>>>
>>>>>>
>
> Pier> I'm already slightly "upset" about the "cocoon://" protocol,
> Pier> as it does not follow the URI RFC properly, I'd like to
> Pier> address the problem as early as possible...
>
> Pier> http://www.ietf.org/rfc/rfc2396.txt
>
>I don't know if this is relevant to the discussion, but are you aware
>that this RFC has been obsoleted by RFC 3986?
>
>
It has some relevance to the discussion as it seem (chap 3.) to allow a
hierarchical URI at the form:
cocoon:foo/bar
where "foo/bar" is called a root less path. But I don't find any
explanation about what it is supposed to mean.
/Daniel
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Pier Fumagalli <pi...@betaversion.org>.
On 4 Apr 2005, at 18:09, Colin Paul Adams wrote:
>>>>>> "Pier" == Pier Fumagalli <pi...@betaversion.org> writes:
>
> Pier> I'm already slightly "upset" about the "cocoon://" protocol,
> Pier> as it does not follow the URI RFC properly, I'd like to
> Pier> address the problem as early as possible...
>
> Pier> http://www.ietf.org/rfc/rfc2396.txt
>
> I don't know if this is relevant to the discussion, but are you aware
> that this RFC has been obsoleted by RFC 3986?
Ups, didn't pick up that one... Thanks... AFAICS the main changes
concern IPv6, anyhow... The overall concept remains the same.
Pier
Re: RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Colin Paul Adams <co...@colina.demon.co.uk>.
>>>>> "Pier" == Pier Fumagalli <pi...@betaversion.org> writes:
Pier> I'm already slightly "upset" about the "cocoon://" protocol,
Pier> as it does not follow the URI RFC properly, I'd like to
Pier> address the problem as early as possible...
Pier> http://www.ietf.org/rfc/rfc2396.txt
I don't know if this is relevant to the discussion, but are you aware
that this RFC has been obsoleted by RFC 3986?
--
Colin Paul Adams
Preston Lancashire
RFC-2396 (Was: Re: [RT] composition vs. inheritance in blocks)
Posted by Pier Fumagalli <pi...@betaversion.org>.
On 31 Mar 2005, at 01:26, Stefano Mazzocchi wrote:
>
> block:super://blah.xml
A very simple remark, I don't want to criticise...
I'm already slightly "upset" about the "cocoon://" protocol, as it does
not follow the URI RFC properly, I'd like to address the problem as
early as possible...
http://www.ietf.org/rfc/rfc2396.txt
I wrote a small "rant" while on the plane, just to explain my
reasoning, with a couple of code examples, as it's (I don't think)
mailing-list material, I've stored it on my WIKI...
http://www.betaversion.org/~pier/wiki/display/pier/Cocoon+and+URIs
Anyhow, feel free to discuss it here...
Pier
Re: [RT] composition vs. inheritance in blocks
Posted by Peter Hunsberger <pe...@gmail.com>.
On Apr 4, 2005 8:49 AM, Daniel Fagerstrom <da...@nada.kth.se> wrote:
<snip/>
> This means IMO that we have to spend time discussing things even if it
> in the short time horizont and for ones own goals whould have seemed
> more productive to just commit some code.
Ultimately, with an Open Source community it is going to be the code
that counts. However, that shouldn't stop any discussion before or
after the fact. There's a thousand different view points out there
and just bringing them to light may trigger ideas that no one would
have considered otherwise...
--
Peter Hunsberger
Re: [RT] composition vs. inheritance in blocks
Posted by Peter Hunsberger <pe...@gmail.com>.
On Thu, 31 Mar 2005 18:03:40 +0200, Reinhard Poetz <re...@apache.org> wrote:
> Peter Hunsberger wrote:
> > On Thu, 31 Mar 2005 17:42:38 +0200, Reinhard Poetz <re...@apache.org> wrote:
> >
> >>Peter Hunsberger wrote:
> >>
> >>
> >>>One comment: I'd hope that you don't literally copy the
> >>>"portal-page.xsl" and modify it? Instead you should be creating a new
> >>>XSL, including "portal-page.xsl" in it and just modifying the
> >>>templates that you wish to override...
> >>
> >>yes, <xsl:import href="blocks://portal-skin/portal-page.xsl"/> should do it.
> >
> >
> > Personally, I'd use <xsl:include href="..."/> most of the time, but
> > either way, it's interesting to note that the Cocoon resolver has to
> > get involved in resolving the reference, which means the resultant XSL
> > isn't portable....
>
> true, but what's the alternative?
You need to allow the referencing block to add an indication that the
the block resolver is to be used to resolve certain URL's. Eg:
<block ...
<extends>http://cocoon.apache.org/blocks/portal-skin/1.0.0
<resolve>//portal-skin</resolve>
</extends>
then any reference starting with the given path would use the block
resolver to resolve to the given block. That could probably work with
relative URL's also, but the whole idea makes me a little nervous:
you'd get cases where people want to use regex or something to do the
matches or add filters to make exceptions and you'd end up reinventing
mod-redirect or some such thing.
--
Peter Hunsberger
Re: [RT] composition vs. inheritance in blocks
Posted by Reinhard Poetz <re...@apache.org>.
Peter Hunsberger wrote:
> On Thu, 31 Mar 2005 17:42:38 +0200, Reinhard Poetz <re...@apache.org> wrote:
>
>>Peter Hunsberger wrote:
>>
>>
>>>One comment: I'd hope that you don't literally copy the
>>>"portal-page.xsl" and modify it? Instead you should be creating a new
>>>XSL, including "portal-page.xsl" in it and just modifying the
>>>templates that you wish to override...
>>
>>yes, <xsl:import href="blocks://portal-skin/portal-page.xsl"/> should do it.
>
>
> Personally, I'd use <xsl:include href="..."/> most of the time, but
> either way, it's interesting to note that the Cocoon resolver has to
> get involved in resolving the reference, which means the resultant XSL
> isn't portable....
true, but what's the alternative?
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] composition vs. inheritance in blocks
Posted by Peter Hunsberger <pe...@gmail.com>.
On Thu, 31 Mar 2005 17:42:38 +0200, Reinhard Poetz <re...@apache.org> wrote:
> Peter Hunsberger wrote:
>
> > One comment: I'd hope that you don't literally copy the
> > "portal-page.xsl" and modify it? Instead you should be creating a new
> > XSL, including "portal-page.xsl" in it and just modifying the
> > templates that you wish to override...
>
> yes, <xsl:import href="blocks://portal-skin/portal-page.xsl"/> should do it.
Personally, I'd use <xsl:include href="..."/> most of the time, but
either way, it's interesting to note that the Cocoon resolver has to
get involved in resolving the reference, which means the resultant XSL
isn't portable....
--
Peter Hunsberger
Re: [RT] composition vs. inheritance in blocks
Posted by Reinhard Poetz <re...@apache.org>.
Peter Hunsberger wrote:
> One comment: I'd hope that you don't literally copy the
> "portal-page.xsl" and modify it? Instead you should be creating a new
> XSL, including "portal-page.xsl" in it and just modifying the
> templates that you wish to override...
yes, <xsl:import href="blocks://portal-skin/portal-page.xsl"/> should do it.
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] composition vs. inheritance in blocks
Posted by Peter Hunsberger <pe...@gmail.com>.
On Thu, 31 Mar 2005 11:51:53 +0200, Daniel Fagerstrom
<da...@nada.kth.se> wrote:
<snip/>
> Now I'm aware that the portal samples use the construction you show
> above, but it doesn't achieve exactly the same thing as the construction
> I propose. If you want to use a slightly modified skin, I would assume
> that you start by copying the +30 files from skins/commons and then
> point "global-variables/skin" to the new location and start to modify
> whatever you wanted to modify.
>
> With my solution you just copy the file, in this case "portal-page.xsl"
> that you actually want to modify and write an overriding sitemap rule to
> use it. After having used thing like the global variable trick for a
> number of years in various applications, we had a tremendous amonount of
> different generations of esentially the same files and numerous copies
> of slightly modified sitemap snippets. Hardly supprising it was a
> maintainance nightmare. After having start to use the pattern that I
> propose we have seen a drastic decrease in the number of files in our
> new applications.
One comment: I'd hope that you don't literally copy the
"portal-page.xsl" and modify it? Instead you should be creating a new
XSL, including "portal-page.xsl" in it and just modifying the
templates that you wish to override...
I point this out because XSLT implements an interesting version of MI
with include. It completely exposes the entire inheritance tree and
gives you very limited ways to navigate the tree. None-the-less
people use it all the time.
In the 70 plus XSLT we have in our app roughly half of them do an
include, sometimes using 4 levels inheritance. None of them use an
import and an "apply-imports" which would be the XSLT equivalent of
composition.
There are a couple of ways in which XSLT (1.0) could provide better
tools for manging the inheritance tree. In particular, on include you
should be able to specify the default priority of the included
templates and a base-priority that would be added to any existing
priorities. You still wouldn't get complete navigation through the
tree, I can see ways of doing that also, but that's another topic
(unless people want to use an XSLT like model for block inheritance.)
<snip/>
--
Peter Hunsberger
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Reinhard Poetz wrote:
> Daniel Fagerstrom wrote:
>
>> I have given some examples of how a user could use some adapted form
>> of MI to build applications based on a number of blocks, so I'm
>> interested in your view about how to build blocks based applications.
>
>
> I can't add much to what Stefano already has said:
>
> "You install "Linotype2", is a real block and it requires "Linotype
> Skin", "JCR Repository", "RDF TripleStore". The block manager goes to
> the block library on cocoon.apache.org and finds a list of possible
> blocks that implement those interfaces and that are known to be
> compatible with the version of the block you are now installing."
>
>
> Except that not the BlocksManager but the BlockDeployer will install
> blocks, that's the vision:
>
> - reusability
> --> skin can be used by more than one block)
> --> develop functionality *once* and reuse it in many applications
> - versioning
> - development will become much easier because you can wire locally
> available development blocks
> e.g. I want to use the latest cForms block in *my* project I simply
> point in the wiring.xml of *my* project to this block. There are
> no difficult deployment cycles!
>
>
> And quoting Stefano a second time: "what is the best way to use those
> features in order to achieve what I need". I don't know what will be
> the best way to use all those features. When we have a working
> prototype we will learn a lot and best practices will evolve.
>
Ok, so lets get to a working prototype. Still if we don't spend some
thought on relevant use cases that comes up, the working prototype might
be less relevant than it could be.
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Reinhard Poetz <re...@apache.org>.
Daniel Fagerstrom wrote:
> I have given some examples of how a user could use some adapted form of
> MI to build applications based on a number of blocks, so I'm interested
> in your view about how to build blocks based applications.
I can't add much to what Stefano already has said:
"You install "Linotype2", is a real block and it requires "Linotype Skin", "JCR
Repository", "RDF TripleStore". The block manager goes to the block library on
cocoon.apache.org and finds a list of possible blocks that implement those
interfaces and that are known to be compatible with the version of the block you
are now installing."
Except that not the BlocksManager but the BlockDeployer will install blocks,
that's the vision:
- reusability
--> skin can be used by more than one block)
--> develop functionality *once* and reuse it in many applications
- versioning
- development will become much easier because you can wire locally
available development blocks
e.g. I want to use the latest cForms block in *my* project I simply
point in the wiring.xml of *my* project to this block. There are
no difficult deployment cycles!
And quoting Stefano a second time: "what is the best way to use those features
in order to achieve what I need". I don't know what will be the best way to use
all those features. When we have a working prototype we will learn a lot and
best practices will evolve.
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Reinhard Poetz wrote:
> Daniel Fagerstrom wrote:
>> Reinhard Poetz wrote:
>>> I think I got the idea. Personally, I would solve this by
>>> composition; the profiling is just another reference of the block. Of
>>> course, as Stefano said, blocks have to be designed for this. If the
>>> application block hasn't factored out the profile aspect, then you
>>> can't replace implementation A by implementation B:
>>>
>>> ---------------------------------------------------------------------------
>>>
>>> "Application block" (to be reused in many projects)
>>> ---------------------------------------------------------------------------
>>>
>>> <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
>>> id="http://mycompany.com/blocks/application-block/1.0.0">
>>> <name>Application block</name>
>>> <requirements>
>>> <requires interface="http://mycompany.com/interfaces/skin/1.0"
>>> name="skin"
>>> default="http://mycompany.com/blocks/myskin/1.0.0"/>
>>> <requires
>>> interface="http://cocoon.apache.org/interfaces/profile/1.0"
>>> name="profile"
>>> default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
>>> <requires interface="http://cocoon.apache.org/interfaces/portal/1.0"
>>> name="portal"
>>> default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
>>> </requirements>
>>> </block>
>>
>>
>>
>> It would work, but to achieve what I did in a few sitemap lines
>> (above) you have to create and deploy a special MyProfile block, and
>> as I just wanted to override a few things in my customized profile I
>> have to extend the original profile from the Portal block in some way.
>> In the sitemap in MyProfile you have to write a copy of the profiles
>> section in the Portal block:
>>
>> MyProfile sitemap
>> -----------------
>>
>> ...
>> <profiles>
>> <copletbasedata-load
>> uri="blocks:/profile/load-global-profile?profile=copletbasedata"/>
>> <copletdata-global-load
>> uri="blocks:/profile/load-global-profile?profile=copletdata"/>
>> <copletdata-role-load
>> uri="blocks:/profile/load-role-profile?profile=copletdata"/>
>> <copletdata-user-load
>> uri="blocks:/profile/load-user-profile?profile=copletdata"/>
>> <copletinstancedata-global-load
>> uri="blocks:/profile/load-global-profile?profile=copletinstancedata"/>
>> <copletinstancedata-role-load
>> uri="blocks:/profile/load-role-profile?profile=copletinstancedata"/>
>> <copletinstancedata-user-load
>> uri="blocks:/profile/load-user-profile?profile=copletinstancedata"/>
>> <copletinstancedata-user-save
>> uri="blocks:/profile/save-user-profile?profile=copletinstancedata"/>
>> <layout-global-load
>> uri="blocks:/profile/load-global-profile?profile=layout"/>
>> <layout-role-load
>> uri="blocks:/profile/load-role-profile?profile=layout"/>
>> <layout-user-load
>> uri="blocks:/profile/load-user-profile?profile=layout"/>
>> <layout-user-save
>> uri="blocks:/profile/save-user-profile?profile=layout"/>
>> </profiles>
>> ...
>> <pipeline>
>> <match pattern="profile/load-user-profile">
>> ...
>> </match>
>>
>> Here the blocks protocol is supposed to first look in the own sitemap
>> (and find "load-user-profile") before it asks the super block. As you
>> can see you need a copy of the profiles section of the sitemap booth
>> in Portal and in MyProfile.
>
>
> No, you don't. The block "portal" only contains pipelines calls which
> the block "profile" provides in its sitemap:
>
> Portal block
> ------------
> - requires "MyProfile" that implements "profile"
>
> <profiles>
> <copletbasedata-load
> uri="blocks:profile:/load-global-profile?profile=copletbasedata"/>
> <copletdata-global-load
> uri="blocks:profile:/load-global-profile?profile=copletdata"/>
> ..
> </profiles>
>
> (After reading Stefano's mail I found a mistake in my examples: The
> block name is a sub-protocol and not part of the path.)
>
> You can have one block that provides default pipelines, let's call it
> "profile-default":
>
> "profile-default"
> -----------------
> - implements "profile"
>
> <map:match pattern="load-global-profile">
> ...
> </map:match>
>
>
> If you need special behaviour in your _custom_ profile block, you extend
> the "profile-default" block and override _only_ those parts that you
> want to see changed. In your custom portal block ("MyPortal") you change
> the requirement from "profile-default" to "MyProfile" and you're done.
>
> "MyProfile"
> -----------
> - extends "profile-default"
>
>
>> And you define and deploy small blocks for each aspect you want to
>> override in the original block. The behaviour of an actual application
>> will be spread out in all these small extended blocks. I found it
>> clumsy, complicated and burocratic compared to the simple sitemap
>> based extension mechanism I used in my example.
>
>
> IIUC your point is that how your application works is spread over to
> many blocks. Maybe you're right but I don't think so, at least the
> examples we talked about here are overly complex using
?
Ok, accepting that we get a number of small blocks, I still think that
you miss things in your example by not using polymorphism.
Whithout knowing much about the portal, it seem to me that it would more
natural to let the Profile interface be about an actual profile rather
than about a number of pipelines that you could use for building a
profile. A DefaultProfile implementation could (and probably should)
have a number of pipelines that makes default configuration content
avaliable and overidable and that are used for building the profile. But
if we want to actually build easy reusable components the interface
should not be that fat and specific.
If the DefaultProfile is built this way, really polymorphic (single)
inheritance will reduce the amount of copying, compared to pure composition.
>>> What I do like is <mount uri-prefix="" src="blocks://portal"/> which
>>> makes it explicit what a block exports. I'm not sure about why this
>>> has to be a "two way contract".
>>
>>
>>
>> It must be a two way contract, as "extend and overide" is a two way
>> contract. If you have it one way you end up having to copy everything
>> that is an agregate of functionality as in the profile example above.
>
>
> Yes, if something isn't designed for reusability, then you have to copy
> it. If you design for reusablity, you don't have to copy services.
Aggregated services requires real polymorphism, if you don't want to
copy the sitemap rule or code that does the actual composition.
<snip/>
> I think we should stop the discussion at this point for now (I don't
> think that anybody can follow it anymore). IIUC everything you proposed
> can be added in a backwards-compatible way to the existing proposal. But
> I'm confident we don't need it ;-)
Yes, we obviously not getting anywher, so lets move on and let us design
really polymorphic blocks with sigle inheritance.
>> Also, I'm intersted in your view about how to actually use the blocks
>> in an application.
> I can think of many scenarios where blocks make sense. We already talked
> abut them in this discussion (skinning, profiles, easy deployment, easy
> development, ...). Does this answer your question or is it too general.
I wouldn't have parcipated in this discussion if I didn't found blocks
usefull ;)
My question is a serious and IMO important one. If a user is going to
build an own portal for his/her company and is going to base this on the
portal block, how will he/she do this. What will the main sitemap look
like, the deployment configuration etc. In the same way that we needed
to write example block.xml and block sitemaps, to get better
understanding of blocks, I think we need to take a look on a "real"
usage of a block, to get the design as usable as possible.
I have given some examples of how a user could use some adapted form of
MI to build applications based on a number of blocks, so I'm interested
in your view about how to build blocks based applications.
Is the question clearer now?
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Reinhard Poetz <re...@apache.org>.
Daniel Fagerstrom wrote:
> Reinhard Poetz wrote:
>
>> I think I got the idea. Personally, I would solve this by composition;
>> the profiling is just another reference of the block. Of course, as
>> Stefano said, blocks have to be designed for this. If the application
>> block hasn't factored out the profile aspect, then you can't replace
>> implementation A by implementation B:
>>
>> ---------------------------------------------------------------------------
>>
>> "Application block" (to be reused in many projects)
>> ---------------------------------------------------------------------------
>>
>> <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
>> id="http://mycompany.com/blocks/application-block/1.0.0">
>> <name>Application block</name>
>> <requirements>
>> <requires interface="http://mycompany.com/interfaces/skin/1.0"
>> name="skin"
>> default="http://mycompany.com/blocks/myskin/1.0.0"/>
>> <requires interface="http://cocoon.apache.org/interfaces/profile/1.0"
>> name="profile"
>> default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
>> <requires interface="http://cocoon.apache.org/interfaces/portal/1.0"
>> name="portal"
>> default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
>> </requirements>
>> </block>
>
>
> It would work, but to achieve what I did in a few sitemap lines (above)
> you have to create and deploy a special MyProfile block, and as I just
> wanted to override a few things in my customized profile I have to
> extend the original profile from the Portal block in some way. In the
> sitemap in MyProfile you have to write a copy of the profiles section
> in the Portal block:
>
> MyProfile sitemap
> -----------------
>
> ...
> <profiles>
> <copletbasedata-load
> uri="blocks:/profile/load-global-profile?profile=copletbasedata"/>
> <copletdata-global-load
> uri="blocks:/profile/load-global-profile?profile=copletdata"/>
> <copletdata-role-load
> uri="blocks:/profile/load-role-profile?profile=copletdata"/>
> <copletdata-user-load
> uri="blocks:/profile/load-user-profile?profile=copletdata"/>
> <copletinstancedata-global-load
> uri="blocks:/profile/load-global-profile?profile=copletinstancedata"/>
> <copletinstancedata-role-load
> uri="blocks:/profile/load-role-profile?profile=copletinstancedata"/>
> <copletinstancedata-user-load
> uri="blocks:/profile/load-user-profile?profile=copletinstancedata"/>
> <copletinstancedata-user-save
> uri="blocks:/profile/save-user-profile?profile=copletinstancedata"/>
> <layout-global-load
> uri="blocks:/profile/load-global-profile?profile=layout"/>
> <layout-role-load uri="blocks:/profile/load-role-profile?profile=layout"/>
> <layout-user-load uri="blocks:/profile/load-user-profile?profile=layout"/>
> <layout-user-save uri="blocks:/profile/save-user-profile?profile=layout"/>
> </profiles>
> ...
> <pipeline>
> <match pattern="profile/load-user-profile">
> ...
> </match>
>
> Here the blocks protocol is supposed to first look in the own sitemap
> (and find "load-user-profile") before it asks the super block. As you
> can see you need a copy of the profiles section of the sitemap booth in
> Portal and in MyProfile.
No, you don't. The block "portal" only contains pipelines calls which the block
"profile" provides in its sitemap:
Portal block
------------
- requires "MyProfile" that implements "profile"
<profiles>
<copletbasedata-load
uri="blocks:profile:/load-global-profile?profile=copletbasedata"/>
<copletdata-global-load
uri="blocks:profile:/load-global-profile?profile=copletdata"/>
..
</profiles>
(After reading Stefano's mail I found a mistake in my examples: The block name
is a sub-protocol and not part of the path.)
You can have one block that provides default pipelines, let's call it
"profile-default":
"profile-default"
-----------------
- implements "profile"
<map:match pattern="load-global-profile">
...
</map:match>
If you need special behaviour in your _custom_ profile block, you extend the
"profile-default" block and override _only_ those parts that you want to see
changed. In your custom portal block ("MyPortal") you change the requirement
from "profile-default" to "MyProfile" and you're done.
"MyProfile"
-----------
- extends "profile-default"
> And you define and deploy small blocks for each
> aspect you want to override in the original block. The behaviour of an
> actual application will be spread out in all these small extended
> blocks. I found it clumsy, complicated and burocratic compared to the
> simple sitemap based extension mechanism I used in my example.
IIUC your point is that how your application works is spread over to many
blocks. Maybe you're right but I don't think so, at least the examples we talked
about here are overly complex using
>> What I do like is <mount uri-prefix="" src="blocks://portal"/> which
>> makes it explicit what a block exports. I'm not sure about why this
>> has to be a "two way contract".
>
>
> It must be a two way contract, as "extend and overide" is a two way
> contract. If you have it one way you end up having to copy everything
> that is an agregate of functionality as in the profile example above.
Yes, if something isn't designed for reusability, then you have to copy it. If
you design for reusablity, you don't have to copy services.
> For another example of two way communication beween a default sitemap
> and an extending one you can look at Forrest which make good use of
> allowing user extensions
> (http://forrest.apache.org/docs/dev/sitemap-ref.html,
> http://svn.apache.org/viewcvs.cgi/forrest/trunk/main/webapp/sitemap.xmap?view=markup
> e.g.).
>
> Here is an example:
>
> <map:resource name="skinit">
> <map:select type="exists">
> <map:when
> test="{project:skins-dir}{forrest:skin}/xslt/html/{type}.xsl">
> <map:transform
> src="{project:skins-dir}{forrest:skin}/xslt/html/{type}.xsl">
> <map:parameter name="notoc" value="{notoc}"/>
> <!-- For backwards-compat with 0.2 - 0.4 skins -->
> <map:parameter name="isfaq" value="{notoc}"/>
> <map:parameter name="nopdf" value="{nopdf}"/>
> <map:parameter name="path" value="{path}"/>
> <map:parameter name="config-file" value="{project:skinconf}"/>
> </map:transform>
> </map:when>
> <map:otherwise>
> <map:transform
> src="{forrest:context}/skins/{forrest:skin}/xslt/html/{type}.xsl">
> <map:parameter name="notoc" value="{notoc}"/>
> <!-- For backwards-compat with 0.2 - 0.4 skins -->
> <map:parameter name="isfaq" value="{notoc}"/>
> <map:parameter name="nopdf" value="{nopdf}"/>
> <map:parameter name="path" value="{path}"/>
> <map:parameter name="config-file" value="{project:skinconf}"/>
> </map:transform>
> </map:otherwise>
> </map:select>
> <map:serialize/>
> </map:resource>
>
> if the style sheet exists in the extending directory given by
> "project:skins-dir" it is used otherwise the default variant from
> "forrest:context" is used. As you see it is a two way communication
> there Forrest need explicit info about the loocation of the extending
> application at deploy time. With the mechanism I propose we would get:
>
> Forrest block sitemap
> ---------------------
>
> <map:resource name="skinit">
> <map:transform
> src="blocks:/skins/{forrest:skin}/xslt/html/{type}.xsl">
> <map:parameter name="notoc" value="{notoc}"/>
> <!-- For backwards-compat with 0.2 - 0.4 skins -->
> <map:parameter name="isfaq" value="{notoc}"/>
> <map:parameter name="nopdf" value="{nopdf}"/>
> <map:parameter name="path" value="{path}"/>
> <map:parameter name="config-file" value="{project:skinconf}"/>
> </map:transform>
> <map:serialize/>
> </map:resource>
>
> instead and could use Forrest from our own app with:
>
> Own documentation pipeline
> --------------------------
>
> <pipeline>
> <match pattern="skins/common/xslt/html/document2html.xsl">
> ...
> </match>
>
> <mount uri-prefix="" src="blocks://forrest"/>
> </pipeline>
>
> where mount:/ gives polymorphic lookup. The advantage, except for being
> terser, with this solution compared to the one Forrest use today for the
> block context is that the Forrest block doesn't need to know any
> explicit paths to the extending application wich is especially important
> if you want to use the same block in several contexts.
The same you reach if everything that should be extensible in Forrest, is moved
into a "default-block". This can be overridden by a project specific block.
>
>> If you write <copletdata-role-load
>> uri="blocks:/load-role-profile?profile=copletdata"/> then it means
>> that you make it explicit what can be overriden and what not.
>> I would use <copletdata-role-load
>> uri="blocks:/profile/load-role-profile?profile=copletdata"/> which
>> requires another reference. Using the proposed <mount>-mechanism, you
>> can reuse the "portal"-pipeline.
>
>
> I'm not certain that I follow you. I would (possibly) use:
>
> blocks://profile/load-profile
>
> for refering to another block, and:
>
> blocks:/load-profile
>
> for refering to the same block possibly with sub protocols:
>
> blocks:polymorph:
>
> if we want to be explicit about when something can be looked up from an
> extending sitemap
>
> blocks:super:
>
> for refereing to the extended block.
>
> A problem with blocks://profile, rather than blocks:profile// is if one
> want to access the "root" block sitemap from a sub sitemap, but that
> could maybe be done with blocks://this/.
Sorry, my usage of the blocks protocal was wrong in my former mails. I'm with
Stefano here that the block is a sub-protocol and additionally we have a "super"
sub-protocol referencing the parent block.
>
>> - o -
>>
>> I think for now we shoudn't support these two-way contracts but favour
>> composition by references (incl. <map:mount uri="[another-block]"/>).
>> If this gets too bureaucratic, we can still think about alternatives.
>>
>> WDYT?
>
>
> I think that it becomes to bureaucratic. But you maybe have some better
> solutions to the issues I adress above.
I think we should stop the discussion at this point for now (I don't think that
anybody can follow it anymore). IIUC everything you proposed can be added in a
backwards-compatible way to the existing proposal. But I'm confident we don't
need it ;-)
> Also, I'm intersted in your view
> about how to actually use the blocks in an application.
I can think of many scenarios where blocks make sense. We already talked abut
them in this discussion (skinning, profiles, easy deployment, easy development,
...). Does this answer your question or is it too general.
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Reinhard Poetz wrote:
> Daniel Fagerstrom wrote:
>
>> Reinhard Poetz wrote:
>
<snip/>
>> What does extends actually buy us here, couldn't we just use
>> "requrires" for the relation to portal-skin/1.0.0.
>
> IIUC using "extends" was the original idea here.
I know, but I don't see any reasons to take that as written in stone.
Extends is an implementation aspect in the otherwise declarative
block.xml and as we have discussed it is probably better to be more
explicit in the sitemap about what and how a block exposes things.
Thurthermore since Stefano gave his original design there have been a
trend towards considering the sitemap as the central point for
configuration, look at Sylvain's and Carsten's recent work e.g. So my
question remains, what does "extends" buy us?
>> <requires block="http://cocoon.apache.org/blocks/portal-skin/1.0.0"
>> name="skin"/>
>>
>> and be explicit about what we expose from portal-skin/1.0.0?
>>
>>> SITEMAP.XMAP
>>> <map:match pattern="one-special.css">
>>> <map:read src="styles/css/one-special.css"/>
>>> </map:match>
>>
>>
>>
>> Being explicit means that we end the sitemap with:
>>
>> <map:mount uri-prefix="" src="blocks://skin"/>
>
> >
>
>>> - o -
>>>
>>> The project that wants to use the Portal is in the block "MyPortal".
>>> It needs several components from "Portal" (generator, several
>>> transformers) and it needs a block that provides the skin, or more
>>> precisly, it needs a block that implements
>>> http://cocoon.apache.org/interfaces/portal-skin/1.0. This can either
>>> be "portal-skin", the default skin, or "MySkin", that provides one
>>> additional CSS. Everything else is taken from "portal-skin".
>>>
>>>
>>> From my POV this solution is very clear and comprehensible. The
>>> aspects "portal functionality" and "skinning" are separated and the
>>> used implementations can simply be replaced by other implementations
>>> (shown by using the "mySkin" block).
>>>
>>> - o -
>>>
>>> What does your solution that ueses multiple inheritance look like?
>>> (If this is a bad example to show the advantages of MI feel free to
>>> enhance it!)
>>
>>
>>
>> First I will not use the term MI as it doesn't describe what I want
>> to achieve that well and as it also seem to stir all kinds of bad
>> reactions that distracts us from the task at hand.
>>
>> So I agree with most of what you show in your example, it looks neat.
>> What I lack from it is how to reuse the sitemap in the Portal block.
>>
>> I would have a sitemap similar to the one in the demo portal in the
>> Portal block. But e.g. the profiles part in the portal-handler
>> configuration would rather be:
>>
>> Portal Sitemap
>> --------------
>>
>> ...
>> <profiles>
>> <copletbasedata-load
>> uri="blocks:/load-global-profile?profile=copletbasedata"/>
>> <copletdata-global-load
>> uri="blocks:/load-global-profile?profile=copletdata"/>
>> <copletdata-role-load
>> uri="blocks:/load-role-profile?profile=copletdata"/>
>> <copletdata-user-load
>> uri="blocks:/load-user-profile?profile=copletdata"/>
>> <copletinstancedata-global-load
>> uri="blocks:/load-global-profile?profile=copletinstancedata"/>
>> <copletinstancedata-role-load
>> uri="blocks:/load-role-profile?profile=copletinstancedata"/>
>> <copletinstancedata-user-load
>> uri="blocks:/load-user-profile?profile=copletinstancedata"/>
>> <copletinstancedata-user-save
>> uri="blocks:/save-user-profile?profile=copletinstancedata"/>
>> <layout-global-load uri="blocks:/load-global-profile?profile=layout"/>
>> <layout-role-load uri="blocks:/load-role-profile?profile=layout"/>
>> <layout-user-load uri="blocks:/load-user-profile?profile=layout"/>
>> <layout-user-save uri="blocks:/save-user-profile?profile=layout"/>
>> </profiles>
>> ...
>>
>> Meaning that the different configuration pipelines are found through
>> the blocks manager that would ask the extending block (recursively)
>> for the configuration pipelines first, and if they not are found
>> there, the own pipeline would be used.
>>
>> Then MyPortal could redefine some of the configuration pipelines and
>> reuse the rest from Portal:
>>
>> MyPortal Sitemap
>> ----------------
>>
>> ...
>> <pipeline>
>> <match pattern="load-user-profile">
>> ...
>> </match>
>>
>> <mount uri-prefix="" src="blocks://portal"/>
>> </pipline>
>> ...
>>
>> Now this mechanism is more limited than real inheritance. map:mount
>> become a two way contract where the mounting sitemap can be asked
>> about services through the block manager, but it doesn't export the
>> interface of the "extended" block. If we have something like the we
>> probably should have some way to differ between mounts that allow the
>> mounted block to ask and those who don't.
>
> (I think) I understand what you want. You called it an "application
> block" which is the base for all your applications. This application
> block (e.g. a company portal) provides services that can be used and
> customized by other blocks.
No it's much simpler ;) I'm not talking about reuse I'm talking about
*use*. To make blocks a success they must of course be easy to use in
user applications. And to make shure that they are easy to use, we must
of course discuss what it looks like when we really use them.
So my application block above is not at all intended for reuse, it is an
actual application (actually nearly all of what I have discussed in this
thread is about ease of use rather than reuse). If you don't like
packaging your applications as blocks that's fine with me we can discuss
that case instead.
The reason that I want to package my applications as (not intended for
reuse) blocks is that it will solve a number of practical problems for
us in a convenient way. Today I have a (large) number of applications
running under the same Cocoon at my developer machine. When we have
added some new functionality to a webapp I run a script that packages
the particular webapp with dependencies and some deployment info and
installs it on a production machine. When the customer is satisfied with
the test release I update the production release in a similar way.
Packaging my webapp as a block will make it able for me to achieve the
same thing without much scripting at all as it takes care about
dependencies, deploy time parameters (db connections e.g.) and packaging.
For the idea of creating a reusable "application block" it is in my
experience not such a good idea. We started that way when we wanted to
reuse a whole application, using the design pattern that I have tried to
explain in this thread. We did it more because of time constraint than
because we actually believed it to be a good idea. Since then we have
factored out a numeber of "vertical" blocks from the original
application that handles different concerns, and that makes reuse much
more flexible.
>
>> --- o0o ---
>>
>> Concerning the skin I find it somewhat burocratic to need to define a
>> new block for beeing able to extend it but I'm ok with it for the
>> time beeing, we will see when we start to use the things. What I
>> would prefer would be to do something like:
>>
>> MyPortal Sitemap
>> ----------------
>>
>> ...
>> <pipeline>
>> <match pattern="load-user-profile">
>> ...
>> </match>
>>
>> <match pattern="skin/one-special.css">
>> <read src="styles/css/one-special.css"/>
>> </match>
>>
>> <mount uri-prefix="skin" src="blocks://skin"/>
>>
>> <mount uri-prefix="" src="blocks://portal"/>
>> </pipline>
>> ...
>>
>> --- o0o ---
>>
>> So what do you think about this?
>
>
> I think I got the idea. Personally, I would solve this by composition;
> the profiling is just another reference of the block. Of course, as
> Stefano said, blocks have to be designed for this. If the application
> block hasn't factored out the profile aspect, then you can't replace
> implementation A by implementation B:
>
> ---------------------------------------------------------------------------
>
> "Application block" (to be reused in many projects)
> ---------------------------------------------------------------------------
>
> <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
> id="http://mycompany.com/blocks/application-block/1.0.0">
> <name>Application block</name>
> <requirements>
> <requires interface="http://mycompany.com/interfaces/skin/1.0"
> name="skin"
> default="http://mycompany.com/blocks/myskin/1.0.0"/>
> <requires interface="http://cocoon.apache.org/interfaces/profile/1.0"
> name="profile"
> default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
> <requires interface="http://cocoon.apache.org/interfaces/portal/1.0"
> name="portal"
> default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
> </requirements>
> </block>
It would work, but to achieve what I did in a few sitemap lines (above)
you have to create and deploy a special MyProfile block, and as I just
wanted to override a few things in my customized profile I have to
extend the original profile from the Portal block in some way. In the
sitemap in MyProfile you have to write a copy of the profiles section
in the Portal block:
MyProfile sitemap
-----------------
...
<profiles>
<copletbasedata-load
uri="blocks:/profile/load-global-profile?profile=copletbasedata"/>
<copletdata-global-load
uri="blocks:/profile/load-global-profile?profile=copletdata"/>
<copletdata-role-load
uri="blocks:/profile/load-role-profile?profile=copletdata"/>
<copletdata-user-load
uri="blocks:/profile/load-user-profile?profile=copletdata"/>
<copletinstancedata-global-load
uri="blocks:/profile/load-global-profile?profile=copletinstancedata"/>
<copletinstancedata-role-load
uri="blocks:/profile/load-role-profile?profile=copletinstancedata"/>
<copletinstancedata-user-load
uri="blocks:/profile/load-user-profile?profile=copletinstancedata"/>
<copletinstancedata-user-save
uri="blocks:/profile/save-user-profile?profile=copletinstancedata"/>
<layout-global-load
uri="blocks:/profile/load-global-profile?profile=layout"/>
<layout-role-load uri="blocks:/profile/load-role-profile?profile=layout"/>
<layout-user-load uri="blocks:/profile/load-user-profile?profile=layout"/>
<layout-user-save uri="blocks:/profile/save-user-profile?profile=layout"/>
</profiles>
...
<pipeline>
<match pattern="profile/load-user-profile">
...
</match>
Here the blocks protocol is supposed to first look in the own sitemap
(and find "load-user-profile") before it asks the super block. As you
can see you need a copy of the profiles section of the sitemap booth in
Portal and in MyProfile. And you define and deploy small blocks for each
aspect you want to override in the original block. The behaviour of an
actual application will be spread out in all these small extended
blocks. I found it clumsy, complicated and burocratic compared to the
simple sitemap based extension mechanism I used in my example.
> What I do like is <mount uri-prefix="" src="blocks://portal"/> which
> makes it explicit what a block exports. I'm not sure about why this
> has to be a "two way contract".
It must be a two way contract, as "extend and overide" is a two way
contract. If you have it one way you end up having to copy everything
that is an agregate of functionality as in the profile example above.
For another example of two way communication beween a default sitemap
and an extending one you can look at Forrest which make good use of
allowing user extensions
(http://forrest.apache.org/docs/dev/sitemap-ref.html,
http://svn.apache.org/viewcvs.cgi/forrest/trunk/main/webapp/sitemap.xmap?view=markup
e.g.).
Here is an example:
<map:resource name="skinit">
<map:select type="exists">
<map:when test="{project:skins-dir}{forrest:skin}/xslt/html/{type}.xsl">
<map:transform src="{project:skins-dir}{forrest:skin}/xslt/html/{type}.xsl">
<map:parameter name="notoc" value="{notoc}"/>
<!-- For backwards-compat with 0.2 - 0.4 skins -->
<map:parameter name="isfaq" value="{notoc}"/>
<map:parameter name="nopdf" value="{nopdf}"/>
<map:parameter name="path" value="{path}"/>
<map:parameter name="config-file" value="{project:skinconf}"/>
</map:transform>
</map:when>
<map:otherwise>
<map:transform src="{forrest:context}/skins/{forrest:skin}/xslt/html/{type}.xsl">
<map:parameter name="notoc" value="{notoc}"/>
<!-- For backwards-compat with 0.2 - 0.4 skins -->
<map:parameter name="isfaq" value="{notoc}"/>
<map:parameter name="nopdf" value="{nopdf}"/>
<map:parameter name="path" value="{path}"/>
<map:parameter name="config-file" value="{project:skinconf}"/>
</map:transform>
</map:otherwise>
</map:select>
<map:serialize/>
</map:resource>
if the style sheet exists in the extending directory given by
"project:skins-dir" it is used otherwise the default variant from
"forrest:context" is used. As you see it is a two way communication
there Forrest need explicit info about the loocation of the extending
application at deploy time. With the mechanism I propose we would get:
Forrest block sitemap
---------------------
<map:resource name="skinit">
<map:transform src="blocks:/skins/{forrest:skin}/xslt/html/{type}.xsl">
<map:parameter name="notoc" value="{notoc}"/>
<!-- For backwards-compat with 0.2 - 0.4 skins -->
<map:parameter name="isfaq" value="{notoc}"/>
<map:parameter name="nopdf" value="{nopdf}"/>
<map:parameter name="path" value="{path}"/>
<map:parameter name="config-file" value="{project:skinconf}"/>
</map:transform>
<map:serialize/>
</map:resource>
instead and could use Forrest from our own app with:
Own documentation pipeline
--------------------------
<pipeline>
<match pattern="skins/common/xslt/html/document2html.xsl">
...
</match>
<mount uri-prefix="" src="blocks://forrest"/>
</pipeline>
where mount:/ gives polymorphic lookup. The advantage, except for being
terser, with this solution compared to the one Forrest use today for the
block context is that the Forrest block doesn't need to know any
explicit paths to the extending application wich is especially important
if you want to use the same block in several contexts.
> If you write <copletdata-role-load
> uri="blocks:/load-role-profile?profile=copletdata"/> then it means
> that you make it explicit what can be overriden and what not.
> I would use <copletdata-role-load
> uri="blocks:/profile/load-role-profile?profile=copletdata"/> which
> requires another reference. Using the proposed <mount>-mechanism, you
> can reuse the "portal"-pipeline.
I'm not certain that I follow you. I would (possibly) use:
blocks://profile/load-profile
for refering to another block, and:
blocks:/load-profile
for refering to the same block possibly with sub protocols:
blocks:polymorph:
if we want to be explicit about when something can be looked up from an
extending sitemap
blocks:super:
for refereing to the extended block.
A problem with blocks://profile, rather than blocks:profile// is if one
want to access the "root" block sitemap from a sub sitemap, but that
could maybe be done with blocks://this/.
> - o -
>
> I think for now we shoudn't support these two-way contracts but favour
> composition by references (incl. <map:mount uri="[another-block]"/>).
> If this gets too bureaucratic, we can still think about alternatives.
>
> WDYT?
I think that it becomes to bureaucratic. But you maybe have some better
solutions to the issues I adress above. Also, I'm intersted in your view
about how to actually use the blocks in an application.
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Reinhard Poetz <re...@apache.org>.
Daniel Fagerstrom wrote:
> Reinhard Poetz wrote:
> <snip/>
>
>> As promised, I've tried to come up with some pseudo-code that shows
>> how "single-inheritance + composition" looks like in a particular
>> example (portal + skinning).
>
>
> That is excelent.
>
>> - o -
>>
>> We have following block interfaces:
>> ===================================
>> - http://cocoon.apache.org/interfaces/portal/1.0
>> - http://cocoon.apache.org/interfaces/portal-skin/1.0
>> - http://mycompany.com/interfaces/skin/1.0
>>
>>
>> Here the block implementations:
>> ===============================
>>
>> ---------------------------------------------------------------------------
>>
>> "Portal"
>> ---------------------------------------------------------------------------
>>
>> BLOCK.XML
>> <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
>> id="http://cocoon.apache.org/blocks/portal/1.0.0">
>> <name>portal</name>
>> <requirements>
>> <requires
>> interface="http://cocoon.apache.org/interface/portal-skin/1.0"
>> name="portal"
>> default="http://cocoon.apache.org/blocks/portal-skin/1.0.0"/>
>> </requirements>
>> <implements>
>> <interface id="http://cocoon.apache.org/interfaces/portal/1.0"/>
>> </implements>
>> </block>
>>
>> ---------------------------------------------------------------------------
>>
>> "Portal-Skin"
>> ---------------------------------------------------------------------------
>>
>> BLOCK.XML <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
>> id="http://cocoon.apache.org/blocks/portal-skin/1.0.0">
>> <name>portal-skin</name>
>> <implements>
>> <interface id="http://cocoon.apache.org/interfaces/portal-skin/1.0"/>
>> </implements>
>> </block>
>>
>> SITEMAP.XMAP
>> <map:match pattern="*.css">
>> <map:read src="styles/css/{1}.css"/>
>> </map:match>
>> <map:match pattern="styles/portal-page.xsl">
>> <map:read src="styles/portal-page.xsl"/>
>> </map:match>
>>
>>
>> ---------------------------------------------------------------------------
>>
>> "MyPortal"
>> ---------------------------------------------------------------------------
>>
>
>
> Is MyPortal an actual application or is it a block that you are going to
> use for building applications? Let's call them application block and
> reusable block respectively. We must take application blocks into
> account to get the whole picture, so I assume that MyPortal is an
> application block that will contain real user profiles etc. Seeing that
> it neither implements nor extends but rather use the portal block
> enforces that view.
>
>> BLOCK.XML <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
>> id="http://mycompany.com/blocks/my-Portal/1.0.0">
>> <name>MyPortal</name>
>> <requirements>
>> <requires interface="http://mycompany.com/interfaces/skin/1.0"
>> name="skin"
>> default="http://mycompany.com/blocks/myskin/1.0.0"/>
>> <requires interface="http://cocoon.apache.org/interfaces/portal/1.0"
>> name="portal"
>> default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
>> </requirements>
>> </block>
>>
>> SITEMAP.XMAP
>> <map:match pattern="portal">
>> <map:act type="portal:auth-protect">
>> <map:parameter name="handler" value="portal-handler"/>
>> <map:parameter name="application" value="portal"/>
>>
>> <map:generate type="portal:portal"/>
>> <map:transform src="blocks://skin/styles/portal-page.xsl">
>> <map:parameter name="user" value="{ID}"/>
>> </map:transform>
>> <map:transform type="core:cinclude"/>
>> <map:transform type="portal:portal-coplet"/>
>> <map:transform type="portal:portal-new-eventlink"/>
>> <map:transform type="core:encodeURL"/>
>> <map:serialize type="portal:html-include"/>
>> </map:act>
>> </map:match>
>
>
> Shouldn't this sitemap be part of Portal rather than MyPortal, AFAICS it
> is a "blockified" version of the "portal" rule from the demo portal, so
> there seem no to be no reason to reimplement it in MyBlock.
>
>> (Note: Most of the used components come from the portal block, the
>> rest from Cocon core; the stylesheet is provided by the "skin" block.)
>>
>> ---------------------------------------------------------------------------
>>
>> "MySkin"
>> ---------------------------------------------------------------------------
>>
>> BLOCK.XML
>> <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
>> id="http://mycompany.com/blocks/my-Portal/1.0.0">
>> <name>MySkin</name>
>> <implements>
>> <interface id="http://cocoon.apache.org/interfaces/portal/1.0"/>
>> </implements>
>> <extends>http://cocoon.apache.org/blocks/portal-skin/1.0.0</extends>
>> </block>
>
>
> What does extends actually buy us here, couldn't we just use "requrires"
> for the relation to portal-skin/1.0.0.
IIUC using "extends" was the original idea here.
>
> <requires block="http://cocoon.apache.org/blocks/portal-skin/1.0.0"
> name="skin"/>
>
> and be explicit about what we expose from portal-skin/1.0.0?
>
>> SITEMAP.XMAP
>> <map:match pattern="one-special.css">
>> <map:read src="styles/css/one-special.css"/>
>> </map:match>
>
>
> Being explicit means that we end the sitemap with:
>
> <map:mount uri-prefix="" src="blocks://skin"/>
>
>> - o -
>>
>> The project that wants to use the Portal is in the block "MyPortal".
>> It needs several components from "Portal" (generator, several
>> transformers) and it needs a block that provides the skin, or more
>> precisly, it needs a block that implements
>> http://cocoon.apache.org/interfaces/portal-skin/1.0. This can either
>> be "portal-skin", the default skin, or "MySkin", that provides one
>> additional CSS. Everything else is taken from "portal-skin".
>>
>>
>> From my POV this solution is very clear and comprehensible. The
>> aspects "portal functionality" and "skinning" are separated and the
>> used implementations can simply be replaced by other implementations
>> (shown by using the "mySkin" block).
>>
>> - o -
>>
>> What does your solution that ueses multiple inheritance look like? (If
>> this is a bad example to show the advantages of MI feel free to
>> enhance it!)
>
>
> First I will not use the term MI as it doesn't describe what I want to
> achieve that well and as it also seem to stir all kinds of bad reactions
> that distracts us from the task at hand.
>
> So I agree with most of what you show in your example, it looks neat.
> What I lack from it is how to reuse the sitemap in the Portal block.
>
> I would have a sitemap similar to the one in the demo portal in the
> Portal block. But e.g. the profiles part in the portal-handler
> configuration would rather be:
>
> Portal Sitemap
> --------------
>
> ...
> <profiles>
> <copletbasedata-load
> uri="blocks:/load-global-profile?profile=copletbasedata"/>
> <copletdata-global-load
> uri="blocks:/load-global-profile?profile=copletdata"/>
> <copletdata-role-load uri="blocks:/load-role-profile?profile=copletdata"/>
> <copletdata-user-load uri="blocks:/load-user-profile?profile=copletdata"/>
> <copletinstancedata-global-load
> uri="blocks:/load-global-profile?profile=copletinstancedata"/>
> <copletinstancedata-role-load
> uri="blocks:/load-role-profile?profile=copletinstancedata"/>
> <copletinstancedata-user-load
> uri="blocks:/load-user-profile?profile=copletinstancedata"/>
> <copletinstancedata-user-save
> uri="blocks:/save-user-profile?profile=copletinstancedata"/>
> <layout-global-load uri="blocks:/load-global-profile?profile=layout"/>
> <layout-role-load uri="blocks:/load-role-profile?profile=layout"/>
> <layout-user-load uri="blocks:/load-user-profile?profile=layout"/>
> <layout-user-save uri="blocks:/save-user-profile?profile=layout"/>
> </profiles>
> ...
>
> Meaning that the different configuration pipelines are found through the
> blocks manager that would ask the extending block (recursively) for the
> configuration pipelines first, and if they not are found there, the own
> pipeline would be used.
>
> Then MyPortal could redefine some of the configuration pipelines and
> reuse the rest from Portal:
>
> MyPortal Sitemap
> ----------------
>
> ...
> <pipeline>
> <match pattern="load-user-profile">
> ...
> </match>
>
> <mount uri-prefix="" src="blocks://portal"/>
> </pipline>
> ...
>
> Now this mechanism is more limited than real inheritance. map:mount
> become a two way contract where the mounting sitemap can be asked about
> services through the block manager, but it doesn't export the interface
> of the "extended" block. If we have something like the we probably
> should have some way to differ between mounts that allow the mounted
> block to ask and those who don't.
(I think) I understand what you want. You called it an "application block" which
is the base for all your applications. This application block (e.g. a company
portal) provides services that can be used and customized by other blocks.
> --- o0o ---
>
> Concerning the skin I find it somewhat burocratic to need to define a
> new block for beeing able to extend it but I'm ok with it for the time
> beeing, we will see when we start to use the things. What I would prefer
> would be to do something like:
>
> MyPortal Sitemap
> ----------------
>
> ...
> <pipeline>
> <match pattern="load-user-profile">
> ...
> </match>
>
> <match pattern="skin/one-special.css">
> <read src="styles/css/one-special.css"/>
> </match>
>
> <mount uri-prefix="skin" src="blocks://skin"/>
>
> <mount uri-prefix="" src="blocks://portal"/>
> </pipline>
> ...
>
> --- o0o ---
>
> So what do you think about this?
I think I got the idea. Personally, I would solve this by composition; the
profiling is just another reference of the block. Of course, as Stefano said,
blocks have to be designed for this. If the application block hasn't factored
out the profile aspect, then you can't replace implementation A by implementation B:
---------------------------------------------------------------------------
"Application block" (to be reused in many projects)
---------------------------------------------------------------------------
<block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
id="http://mycompany.com/blocks/application-block/1.0.0">
<name>Application block</name>
<requirements>
<requires interface="http://mycompany.com/interfaces/skin/1.0"
name="skin"
default="http://mycompany.com/blocks/myskin/1.0.0"/>
<requires interface="http://cocoon.apache.org/interfaces/profile/1.0"
name="profile"
default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
<requires interface="http://cocoon.apache.org/interfaces/portal/1.0"
name="portal"
default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
</requirements>
</block>
What I do like is <mount uri-prefix="" src="blocks://portal"/> which makes it
explicit what a block exports. I'm not sure about why this has to be a "two way
contract".
If you write <copletdata-role-load
uri="blocks:/load-role-profile?profile=copletdata"/> then it means that you make
it explicit what can be overriden and what not.
I would use <copletdata-role-load
uri="blocks:/profile/load-role-profile?profile=copletdata"/> which requires
another reference. Using the proposed <mount>-mechanism, you can reuse the
"portal"-pipeline.
- o -
I think for now we shoudn't support these two-way contracts but favour
composition by references (incl. <map:mount uri="[another-block]"/>). If this
gets too bureaucratic, we can still think about alternatives.
WDYT?
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] composition vs. inheritance in blocks
Posted by Nicola Ken Barozzi <ni...@apache.org>.
Daniel Fagerstrom wrote:
...
> This means IMO that we have to spend time discussing things even if it
> in the short time horizont and for ones own goals whould have seemed
> more productive to just commit some code.
Or commit two codes in separate branches and see what works best.
OTOMH, all this smells a lot like the Microsoft COM model versus
language features.
It may be beneficial to read things on the Microsoft Component Object
Model, as IIRC it used composition instead of inheritance, with
analogous reasoning.
--
Nicola Ken Barozzi nicolaken@apache.org
- verba volant, scripta manent -
(discussions get forgotten, just code remains)
---------------------------------------------------------------------
Re: [RT] composition vs. inheritance in blocks
Posted by Stefano Mazzocchi <st...@apache.org>.
Daniel Fagerstrom wrote:
> As Stefano doesn't work fulltime at Cocoon anymore, the rest of us must
> take our reponsibilty and make shure that our individual ideas actually
> intgrates with others ideas and are benefical for Cocoon as a whole.
Daniel,
I have never worked fulltime on Cocoon and I have a long track records
of keeping an open mind about architectural decisions and suggestions
and I have not changed my attitude.
At the end of the day, my vote here counts as one, just like yours, so
if you feel I'm an obstacle for your design ideas, get over it and do
yourself a favor understanding that the value of this project is the
community reaction, not the individual action.
--
Stefano.
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Reinhard Poetz wrote:
> Stefano Mazzocchi wrote:
>
>> Thank you.
>>
>> [boy this was exhausting]
>
>
> yes it was and maybe more dicussions will follow.
As both Stefano and I are involved in real blocks it seem unavoidable ;)
Although a friendlier discussion probably had been more efficient, we
actually produced a lot of concretization and clarification of the
involved concepts, so I think it lead us closer to the goal.
> Daniel, some others and I are putting a lot of energy into making real
> blocks reality and its important that we _all_ follow the same vision
> (in the end). Berin summarized
> (http://www.jroller.com/page/bloritsch/20050401#why_can_t_oss_do) it
> very well why I'm sure that we will be successful and that we are
> close to the next step on Cocoon's ladder of evolution.
I agree that a common vision is central for our success. If we are lazy
and just focused on keeping everything nice and cozy, the end result
risk to be a commity product, a patch work of small individual visons
whithout coherency. Such a thing will at most be mediocre.
We can compare Cocoon as a publishing framework which is based on one
strong vision with Cocoon as a webapp framework where several different
approaches coexists, whithout much integration and where we haven't
pruned away abanoned paths. And as the different approaches are good at
different things one often has to be knowledgable in all of them to
build applications. Something that makes it unnecesarilly hard to learn
developing Cocoon webapps and something that diffusses our effort as
everything has to be supported.
As Stefano doesn't work fulltime at Cocoon anymore, the rest of us must
take our reponsibilty and make shure that our individual ideas actually
intgrates with others ideas and are benefical for Cocoon as a whole.
This means IMO that we have to spend time discussing things even if it
in the short time horizont and for ones own goals whould have seemed
more productive to just commit some code.
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Reinhard Poetz <re...@apache.org>.
Stefano Mazzocchi wrote:
> Thank you.
>
> [boy this was exhausting]
yes it was and maybe more dicussions will follow. Daniel, some others and I are
putting a lot of energy into making real blocks reality and its important that
we _all_ follow the same vision (in the end). Berin summarized
(http://www.jroller.com/page/bloritsch/20050401#why_can_t_oss_do) it very well
why I'm sure that we will be successful and that we are close to the next step
on Cocoon's ladder of evolution.
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] composition vs. inheritance in blocks
Posted by Stefano Mazzocchi <st...@apache.org>.
Daniel Fagerstrom wrote:
> Stefano Mazzocchi wrote:
>
>> Daniel Fagerstrom wrote:
>>
>>> Concerning the skin I find it somewhat burocratic to need to define a
>>> new block for beeing able to extend it but I'm ok with it for the
>>> time beeing, we will see when we start to use the things.
>>
>>
>>
>> Cool.
>>
>>> What I would prefer would be to do something like:
>>>
>>> MyPortal Sitemap
>>> ----------------
>>>
>>> ...
>>> <pipeline>
>>> <match pattern="load-user-profile">
>>> ...
>>> </match>
>>>
>>> <match pattern="skin/one-special.css">
>>> <read src="styles/css/one-special.css"/>
>>> </match>
>>>
>>> <mount uri-prefix="skin" src="blocks://skin"/>
>>>
>>> <mount uri-prefix="" src="blocks://portal"/>
>>> </pipline>
>>> ...
>>>
>>> --- o0o ---
>>>
>>> So what do you think about this?
>>
>>
>>
>> Did you really mean the above or you meant
>>
>> <mount uri-prefix="skin" src="block:skin://"/>
>> <mount uri-prefix="" src="block:portal://"/>
>
> >
> > ?
>
> I meant what you suggest, I adapted my notation to Reinhard's example.
>
>> in that case, and the above is your sitemap mount at /, how do you
>> avoid the conflict emerging by the fact that somebody else has mount
>> another implementation of the skin block on /skin ?
>
>
> I general I would only mount applications or applications that are
> packaged as a block to an external path. The blocks that just are part
> of applications will only get accessed through the blocks protocol. And
> its quite likely that I want to control or adapt the uri space from the
> used block (skin e.g.) in my application which only is possible if I
> serve it through the sitemap of my application.
>
> In the example above I would only have mounted MyPortal if I acually
> used it as an application and not as a building block in another
> application. And I would only have mounted it at "/" if it was the sole
> or main application within my Cocoon instance. So I don't see why I
> should get any conflicts.
>
> Furthermore it's not either or, if you have some good reason for
> mounting all your (building) blocks at the exposed uri space of your
> Cocoon I have no plans in trying to stop you from it ;). Then you should
> of course avoid mounting them so that they shadow the uri space of other
> blocks or your applications.
>
>> Daniel, I perfectly understand why you want those features, but I have
>> a bigger goal: allow blocks to be really polymorphic, not just an
>> easier deploy tool.
>
>
> Cool, then we share the same goal. Real polymorphism means that if I
> have two classes:
>
> public class Base {
> public String name() { return "Base"; }
> public String msg() { return "I'm " + foo(); }
> }
>
> public class Extended extends Base {
> public String name() { return "Extended"; }
> }
>
> then
>
> Extended e = new Extended();
> System.out.println(e.name());
>
> will obviously print "Extended".
>
> and
>
> System.out.println(e.msg());
>
> will print "I'm Extended" rather than "I'm Base".
>
> --- o0o ---
>
> Translating this to blocks we get:
>
> BaseBlock Sitemap
> -----------------
>
> <pipeline>
> <match pattern="content">
> <read src="base-content.xml"/>
> </match>
>
> <match pattern="view">
> <generate src="blocks:/content"/>
> <transform src="content2html.xsl"/>
> <serialize/>
> </match>
> </pipeline>
>
> ExtendedBlock Sitemap
> ---------------------
>
> ExtendedBlock extends BaseBlock
>
> <pipeline>
> <match pattern="content">
> <read src="extended-content.xml"/>
> </match>
> </pipeline>
>
> Saying that we mount ExtendedBlock at "/" then
>
> /content
>
> obviuosly will respond with the content of "extended-content.xml"
>
> with mere shadowing
>
> /view
>
> would respond with an html rendered view of "base-content.xml" and with
> real polymorphism it would respond with an html rendered view of
> "extended-content.xml".
Daniel, you are beating a dead horse. This has been in the original
design since day 1.
What I'm fighting against, in case you haven't noticed yet, is the
concept of a blocking having more than one "extends", not on the concept
of extension alltogether.
> --- o0o ---
>
> As long as we agree that we want real polymorphism for blocks rather
> than just shadowing, I can wait with some adaption of MI until other
> people see that they need it.
Great. Hopefully we can move on now.
>> With that in mind, the complexity increases, if you are composing your
>> block out of several others (if you have just one block or you just
>> use ones that provide java components, that is not the case).
>>
>> "explicit" mounting of blocks yields mount collision nightmares:
>> blocks should be mount implicitly and thru the block manager (sort of
>> a mount-table on steroids).
>
> Are you refering to the blocks wiring.xml
> (http://wiki.apache.org/cocoon/BlocksWiring)?
yes
>> explicit mounting works fine only if you are in control of all the
>> dependencies, but this cannot be assumed, since blocks should be
>> downloadable from the outside as well and might bring new dependencies.
>
> Can you give an example of how this could happen?
You install "Linotype2", is a real block and it requires "Linotype
Skin", "JCR Repository", "RDF TripleStore". The block manager goes to
the block library on cocoon.apache.org and finds a list of possible
blocks that implement those interfaces and that are known to be
compatible with the version of the block you are now installing.
A dialog between you, the block manager and the block mirrors starts.
The blocks are downloaded, unpacked, verified, installed and configured.
One of the configurations is the blocks suggest you their default mount
point (or not, depending if the block is meant for direct public
exposure or not), but you like your URIs in italian, so you move them.
All this was done without touching a single line in any block, including
yours.
>> This said, I can't stop the above from happening: even if we have
>> implicit mounting, you can go ahead and 'remount' it explicitly as you
>> did above.
>>
>> The fact is that it's not needed if you do the following:
>>
>> <pipeline>
>> <match pattern="load-user-profile">
>> ...
>> </match>
>>
>> <match pattern="skin/one-special.css">
>> <read src="styles/css/one-special.css"/>
>> </match>
>>
>> <mount-blocks/>
>>
>> </pipline>
>
> What does "mount-blocks" do?
That's an idea I've been playing with, the use of <mount-blocks/> as the
mounting equivalent of <xsl:apply-templates/> not sure it's a good idea,
but allows you to explicitly indicate in what part of the pipeline the
block mounts happen.
It solves some problems (and makes things more explicit) but I'm still
not sure it really helps.
>> and the above is the sitemap of MyPortal that extends "Portal" and
>> it's mount on / and requires "Skin" that is mount on '/skin'.
>>
>> Note however, how if you mount 'Skin' on '/style', the above breaks!
>> The way I designed it to avoid this problem is:
>
> As explained above, I don't mount Skin in itself, MyPortal only access
> Skin through "blocks:skin" and its mount of skin in its own sitemap, so
> nothing will not break.
Hmmm, I see.
The reason why I don't like this is that if I have things like a skin,
which might be shared by lots of blocks, mount it in a 'block-relative'
URL makes it appear as the same information is duplicated all over the
place, making proxying/caching less efficient.
But sure, it's an approach.
>> MyPortal
>> - extends Portal
>> - requires Skin
>> - mount on "/"
>> -----------------
>>
>> <pipeline>
>> <match pattern="load-user-profile">
>> ...
>> </match>
>>
>> </pipeline>
>>
>> MySkin
>> - extends Skin
>> - mount on "/styles/"
>> ----------------------
>>
>> <pipeline>
>>
>> <match pattern="one-special.css">
>> <read src="styles/css/one-special.css"/>
>> </match>
>>
>> </pipeline>
>>
>> Since <mount> exists and block: will be a Source protocol, it's
>> impossible to stop you from doing explicit block mounting into your
>> own block URL space. Note that this scatters the URL control in many
>> files, instead of centralizing it at the block management level.
>
>
> I usually have several applications running under one Cocoon, so for me
> its not attrcative to handle the "whithin application" url space in a
> central place, I'll do that in the main sitemap of my application
> (application block) instead. At the central level I would only mount my
> applications and possibly some central resources that I want to make
> available for all applications, without any adaptions or restrictions.
>
>> I personally won't use it for the above reasons, but if it floats your
>> boat, go ahead.
>
>
> Cool.
>
>> My point remains: we don't need multiple inheritance of blocks to
>> achieve what you need!
>
>
> As you have avoided commenting on my use cases for the adapted form of
> MI that I have proposed, it seem to me like a rather far reaching
> conclusion.
>
> But we obviously doesn't get anywhere in this discussion. So let's move
> on and start to actualy design and implement the blocks manager for
> really polymorphic blocks with single inheritance.
Thank you.
[boy this was exhausting]
--
Stefano.
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Stefano Mazzocchi wrote:
> Daniel Fagerstrom wrote:
>
>> Concerning the skin I find it somewhat burocratic to need to define a
>> new block for beeing able to extend it but I'm ok with it for the time
>> beeing, we will see when we start to use the things.
>
>
> Cool.
>
>> What I would prefer would be to do something like:
>>
>> MyPortal Sitemap
>> ----------------
>>
>> ...
>> <pipeline>
>> <match pattern="load-user-profile">
>> ...
>> </match>
>>
>> <match pattern="skin/one-special.css">
>> <read src="styles/css/one-special.css"/>
>> </match>
>>
>> <mount uri-prefix="skin" src="blocks://skin"/>
>>
>> <mount uri-prefix="" src="blocks://portal"/>
>> </pipline>
>> ...
>>
>> --- o0o ---
>>
>> So what do you think about this?
>
>
> Did you really mean the above or you meant
>
> <mount uri-prefix="skin" src="block:skin://"/>
> <mount uri-prefix="" src="block:portal://"/>
>
> ?
I meant what you suggest, I adapted my notation to Reinhard's example.
> in that case, and the above is your sitemap mount at /, how do you avoid
> the conflict emerging by the fact that somebody else has mount another
> implementation of the skin block on /skin ?
I general I would only mount applications or applications that are
packaged as a block to an external path. The blocks that just are part
of applications will only get accessed through the blocks protocol. And
its quite likely that I want to control or adapt the uri space from the
used block (skin e.g.) in my application which only is possible if I
serve it through the sitemap of my application.
In the example above I would only have mounted MyPortal if I acually
used it as an application and not as a building block in another
application. And I would only have mounted it at "/" if it was the sole
or main application within my Cocoon instance. So I don't see why I
should get any conflicts.
Furthermore it's not either or, if you have some good reason for
mounting all your (building) blocks at the exposed uri space of your
Cocoon I have no plans in trying to stop you from it ;). Then you should
of course avoid mounting them so that they shadow the uri space of other
blocks or your applications.
> Daniel, I perfectly understand why you want those features, but I have a
> bigger goal: allow blocks to be really polymorphic, not just an easier
> deploy tool.
Cool, then we share the same goal. Real polymorphism means that if I
have two classes:
public class Base {
public String name() { return "Base"; }
public String msg() { return "I'm " + foo(); }
}
public class Extended extends Base {
public String name() { return "Extended"; }
}
then
Extended e = new Extended();
System.out.println(e.name());
will obviously print "Extended".
and
System.out.println(e.msg());
will print "I'm Extended" rather than "I'm Base".
--- o0o ---
Translating this to blocks we get:
BaseBlock Sitemap
-----------------
<pipeline>
<match pattern="content">
<read src="base-content.xml"/>
</match>
<match pattern="view">
<generate src="blocks:/content"/>
<transform src="content2html.xsl"/>
<serialize/>
</match>
</pipeline>
ExtendedBlock Sitemap
---------------------
ExtendedBlock extends BaseBlock
<pipeline>
<match pattern="content">
<read src="extended-content.xml"/>
</match>
</pipeline>
Saying that we mount ExtendedBlock at "/" then
/content
obviuosly will respond with the content of "extended-content.xml"
with mere shadowing
/view
would respond with an html rendered view of "base-content.xml" and with
real polymorphism it would respond with an html rendered view of
"extended-content.xml".
--- o0o ---
As long as we agree that we want real polymorphism for blocks rather
than just shadowing, I can wait with some adaption of MI until other
people see that they need it.
> With that in mind, the complexity increases, if you are composing your
> block out of several others (if you have just one block or you just use
> ones that provide java components, that is not the case).
>
> "explicit" mounting of blocks yields mount collision nightmares: blocks
> should be mount implicitly and thru the block manager (sort of a
> mount-table on steroids).
Are you refering to the blocks wiring.xml
(http://wiki.apache.org/cocoon/BlocksWiring)?
> explicit mounting works fine only if you are
> in control of all the dependencies, but this cannot be assumed, since
> blocks should be downloadable from the outside as well and might bring
> new dependencies.
Can you give an example of how this could happen?
> This said, I can't stop the above from happening: even if we have
> implicit mounting, you can go ahead and 'remount' it explicitly as you
> did above.
>
> The fact is that it's not needed if you do the following:
>
> <pipeline>
> <match pattern="load-user-profile">
> ...
> </match>
>
> <match pattern="skin/one-special.css">
> <read src="styles/css/one-special.css"/>
> </match>
>
> <mount-blocks/>
>
> </pipline>
What does "mount-blocks" do?
>
> and the above is the sitemap of MyPortal that extends "Portal" and it's
> mount on / and requires "Skin" that is mount on '/skin'.
>
> Note however, how if you mount 'Skin' on '/style', the above breaks! The
> way I designed it to avoid this problem is:
As explained above, I don't mount Skin in itself, MyPortal only access
Skin through "blocks:skin" and its mount of skin in its own sitemap, so
nothing will not break.
> MyPortal
> - extends Portal
> - requires Skin
> - mount on "/"
> -----------------
>
> <pipeline>
> <match pattern="load-user-profile">
> ...
> </match>
>
> </pipeline>
>
> MySkin
> - extends Skin
> - mount on "/styles/"
> ----------------------
>
> <pipeline>
>
> <match pattern="one-special.css">
> <read src="styles/css/one-special.css"/>
> </match>
>
> </pipeline>
>
> Since <mount> exists and block: will be a Source protocol, it's
> impossible to stop you from doing explicit block mounting into your own
> block URL space. Note that this scatters the URL control in many files,
> instead of centralizing it at the block management level.
I usually have several applications running under one Cocoon, so for me
its not attrcative to handle the "whithin application" url space in a
central place, I'll do that in the main sitemap of my application
(application block) instead. At the central level I would only mount my
applications and possibly some central resources that I want to make
available for all applications, without any adaptions or restrictions.
> I personally won't use it for the above reasons, but if it floats your
> boat, go ahead.
Cool.
> My point remains: we don't need multiple inheritance of blocks to
> achieve what you need!
As you have avoided commenting on my use cases for the adapted form of
MI that I have proposed, it seem to me like a rather far reaching
conclusion.
But we obviously doesn't get anywhere in this discussion. So let's move
on and start to actualy design and implement the blocks manager for
really polymorphic blocks with single inheritance.
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Stefano Mazzocchi <st...@apache.org>.
Daniel Fagerstrom wrote:
> Concerning the skin I find it somewhat burocratic to need to define a
> new block for beeing able to extend it but I'm ok with it for the time
> beeing, we will see when we start to use the things.
Cool.
> What I would prefer
> would be to do something like:
>
> MyPortal Sitemap
> ----------------
>
> ...
> <pipeline>
> <match pattern="load-user-profile">
> ...
> </match>
>
> <match pattern="skin/one-special.css">
> <read src="styles/css/one-special.css"/>
> </match>
>
> <mount uri-prefix="skin" src="blocks://skin"/>
>
> <mount uri-prefix="" src="blocks://portal"/>
> </pipline>
> ...
>
> --- o0o ---
>
> So what do you think about this?
Did you really mean the above or you meant
<mount uri-prefix="skin" src="block:skin://"/>
<mount uri-prefix="" src="block:portal://"/>
?
in that case, and the above is your sitemap mount at /, how do you avoid
the conflict emerging by the fact that somebody else has mount another
implementation of the skin block on /skin ?
Daniel, I perfectly understand why you want those features, but I have a
bigger goal: allow blocks to be really polymorphic, not just an easier
deploy tool.
With that in mind, the complexity increases, if you are composing your
block out of several others (if you have just one block or you just use
ones that provide java components, that is not the case).
"explicit" mounting of blocks yields mount collision nightmares: blocks
should be mount implicitly and thru the block manager (sort of a
mount-table on steroids). explicit mounting works fine only if you are
in control of all the dependencies, but this cannot be assumed, since
blocks should be downloadable from the outside as well and might bring
new dependencies.
This said, I can't stop the above from happening: even if we have
implicit mounting, you can go ahead and 'remount' it explicitly as you
did above.
The fact is that it's not needed if you do the following:
<pipeline>
<match pattern="load-user-profile">
...
</match>
<match pattern="skin/one-special.css">
<read src="styles/css/one-special.css"/>
</match>
<mount-blocks/>
</pipline>
and the above is the sitemap of MyPortal that extends "Portal" and it's
mount on / and requires "Skin" that is mount on '/skin'.
Note however, how if you mount 'Skin' on '/style', the above breaks! The
way I designed it to avoid this problem is:
MyPortal
- extends Portal
- requires Skin
- mount on "/"
-----------------
<pipeline>
<match pattern="load-user-profile">
...
</match>
</pipeline>
MySkin
- extends Skin
- mount on "/styles/"
----------------------
<pipeline>
<match pattern="one-special.css">
<read src="styles/css/one-special.css"/>
</match>
</pipeline>
Since <mount> exists and block: will be a Source protocol, it's
impossible to stop you from doing explicit block mounting into your own
block URL space. Note that this scatters the URL control in many files,
instead of centralizing it at the block management level.
I personally won't use it for the above reasons, but if it floats your
boat, go ahead.
My point remains: we don't need multiple inheritance of blocks to
achieve what you need!
--
Stefano.
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Reinhard Poetz wrote:
<snip/>
> As promised, I've tried to come up with some pseudo-code that shows
> how "single-inheritance + composition" looks like in a particular
> example (portal + skinning).
That is excelent.
> - o -
>
> We have following block interfaces:
> ===================================
> - http://cocoon.apache.org/interfaces/portal/1.0
> - http://cocoon.apache.org/interfaces/portal-skin/1.0
> - http://mycompany.com/interfaces/skin/1.0
>
>
> Here the block implementations:
> ===============================
>
> ---------------------------------------------------------------------------
>
> "Portal"
> ---------------------------------------------------------------------------
>
> BLOCK.XML
> <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
> id="http://cocoon.apache.org/blocks/portal/1.0.0">
> <name>portal</name>
> <requirements>
> <requires
> interface="http://cocoon.apache.org/interface/portal-skin/1.0"
> name="portal"
> default="http://cocoon.apache.org/blocks/portal-skin/1.0.0"/>
> </requirements>
> <implements>
> <interface id="http://cocoon.apache.org/interfaces/portal/1.0"/>
> </implements>
> </block>
>
> ---------------------------------------------------------------------------
>
> "Portal-Skin"
> ---------------------------------------------------------------------------
>
> BLOCK.XML
> <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
> id="http://cocoon.apache.org/blocks/portal-skin/1.0.0">
> <name>portal-skin</name>
> <implements>
> <interface id="http://cocoon.apache.org/interfaces/portal-skin/1.0"/>
> </implements>
> </block>
>
> SITEMAP.XMAP
> <map:match pattern="*.css">
> <map:read src="styles/css/{1}.css"/>
> </map:match>
> <map:match pattern="styles/portal-page.xsl">
> <map:read src="styles/portal-page.xsl"/>
> </map:match>
>
>
> ---------------------------------------------------------------------------
>
> "MyPortal"
> ---------------------------------------------------------------------------
>
Is MyPortal an actual application or is it a block that you are going to
use for building applications? Let's call them application block and
reusable block respectively. We must take application blocks into
account to get the whole picture, so I assume that MyPortal is an
application block that will contain real user profiles etc. Seeing that
it neither implements nor extends but rather use the portal block
enforces that view.
> BLOCK.XML
> <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
> id="http://mycompany.com/blocks/my-Portal/1.0.0">
> <name>MyPortal</name>
> <requirements>
> <requires interface="http://mycompany.com/interfaces/skin/1.0"
> name="skin"
> default="http://mycompany.com/blocks/myskin/1.0.0"/>
> <requires interface="http://cocoon.apache.org/interfaces/portal/1.0"
> name="portal"
> default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
> </requirements>
> </block>
>
> SITEMAP.XMAP
> <map:match pattern="portal">
> <map:act type="portal:auth-protect">
> <map:parameter name="handler" value="portal-handler"/>
> <map:parameter name="application" value="portal"/>
>
> <map:generate type="portal:portal"/>
> <map:transform src="blocks://skin/styles/portal-page.xsl">
> <map:parameter name="user" value="{ID}"/>
> </map:transform>
> <map:transform type="core:cinclude"/>
> <map:transform type="portal:portal-coplet"/>
> <map:transform type="portal:portal-new-eventlink"/>
> <map:transform type="core:encodeURL"/>
> <map:serialize type="portal:html-include"/>
> </map:act>
> </map:match>
Shouldn't this sitemap be part of Portal rather than MyPortal, AFAICS it
is a "blockified" version of the "portal" rule from the demo portal, so
there seem no to be no reason to reimplement it in MyBlock.
> (Note: Most of the used components come from the portal block, the
> rest from Cocon core; the stylesheet is provided by the "skin" block.)
>
> ---------------------------------------------------------------------------
>
> "MySkin"
> ---------------------------------------------------------------------------
>
> BLOCK.XML
> <block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
> id="http://mycompany.com/blocks/my-Portal/1.0.0">
> <name>MySkin</name>
> <implements>
> <interface id="http://cocoon.apache.org/interfaces/portal/1.0"/>
> </implements>
> <extends>http://cocoon.apache.org/blocks/portal-skin/1.0.0</extends>
> </block>
What does extends actually buy us here, couldn't we just use "requrires"
for the relation to portal-skin/1.0.0.
<requires block="http://cocoon.apache.org/blocks/portal-skin/1.0.0"
name="skin"/>
and be explicit about what we expose from portal-skin/1.0.0?
> SITEMAP.XMAP
> <map:match pattern="one-special.css">
> <map:read src="styles/css/one-special.css"/>
> </map:match>
Being explicit means that we end the sitemap with:
<map:mount uri-prefix="" src="blocks://skin"/>
> - o -
>
> The project that wants to use the Portal is in the block "MyPortal".
> It needs several components from "Portal" (generator, several
> transformers) and it needs a block that provides the skin, or more
> precisly, it needs a block that implements
> http://cocoon.apache.org/interfaces/portal-skin/1.0. This can either
> be "portal-skin", the default skin, or "MySkin", that provides one
> additional CSS. Everything else is taken from "portal-skin".
>
>
> From my POV this solution is very clear and comprehensible. The
> aspects "portal functionality" and "skinning" are separated and the
> used implementations can simply be replaced by other implementations
> (shown by using the "mySkin" block).
>
> - o -
>
> What does your solution that ueses multiple inheritance look like? (If
> this is a bad example to show the advantages of MI feel free to
> enhance it!)
First I will not use the term MI as it doesn't describe what I want to
achieve that well and as it also seem to stir all kinds of bad reactions
that distracts us from the task at hand.
So I agree with most of what you show in your example, it looks neat.
What I lack from it is how to reuse the sitemap in the Portal block.
I would have a sitemap similar to the one in the demo portal in the
Portal block. But e.g. the profiles part in the portal-handler
configuration would rather be:
Portal Sitemap
--------------
...
<profiles>
<copletbasedata-load uri="blocks:/load-global-profile?profile=copletbasedata"/>
<copletdata-global-load uri="blocks:/load-global-profile?profile=copletdata"/>
<copletdata-role-load uri="blocks:/load-role-profile?profile=copletdata"/>
<copletdata-user-load uri="blocks:/load-user-profile?profile=copletdata"/>
<copletinstancedata-global-load uri="blocks:/load-global-profile?profile=copletinstancedata"/>
<copletinstancedata-role-load uri="blocks:/load-role-profile?profile=copletinstancedata"/>
<copletinstancedata-user-load uri="blocks:/load-user-profile?profile=copletinstancedata"/>
<copletinstancedata-user-save uri="blocks:/save-user-profile?profile=copletinstancedata"/>
<layout-global-load uri="blocks:/load-global-profile?profile=layout"/>
<layout-role-load uri="blocks:/load-role-profile?profile=layout"/>
<layout-user-load uri="blocks:/load-user-profile?profile=layout"/>
<layout-user-save uri="blocks:/save-user-profile?profile=layout"/>
</profiles>
...
Meaning that the different configuration pipelines are found through the
blocks manager that would ask the extending block (recursively) for the
configuration pipelines first, and if they not are found there, the own
pipeline would be used.
Then MyPortal could redefine some of the configuration pipelines and
reuse the rest from Portal:
MyPortal Sitemap
----------------
...
<pipeline>
<match pattern="load-user-profile">
...
</match>
<mount uri-prefix="" src="blocks://portal"/>
</pipline>
...
Now this mechanism is more limited than real inheritance. map:mount
become a two way contract where the mounting sitemap can be asked about
services through the block manager, but it doesn't export the interface
of the "extended" block. If we have something like the we probably
should have some way to differ between mounts that allow the mounted
block to ask and those who don't.
--- o0o ---
Concerning the skin I find it somewhat burocratic to need to define a
new block for beeing able to extend it but I'm ok with it for the time
beeing, we will see when we start to use the things. What I would prefer
would be to do something like:
MyPortal Sitemap
----------------
...
<pipeline>
<match pattern="load-user-profile">
...
</match>
<match pattern="skin/one-special.css">
<read src="styles/css/one-special.css"/>
</match>
<mount uri-prefix="skin" src="blocks://skin"/>
<mount uri-prefix="" src="blocks://portal"/>
</pipline>
...
--- o0o ---
So what do you think about this?
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Reinhard Poetz <re...@apache.org>.
Daniel Fagerstrom wrote:
> Ok, I'll give you a new example trying to explain the concept. Let's
> start with the portal block and say that I want to use that for my app,
> MyPortal, but I want a different skin. The skin consists of the
> stylesheet "styles/portal-page.xsl" among other things. We assume that
> the designer of the portal block wanted to make the skin overridable so
> there is a sitemap rule that exposes the stylesheet in the Portal block.
>
> <match pattern="styles/portal-page.xsl">
> <read src="default-portal-page.xsl"/>
> </match>
>
> Now I let MyPortal extends Portal and reimplements the stylesheet in
> MyPortal
>
> <match pattern="styles/portal-page.xsl">
> <read src="my-portal-page.xsl"/>
> </match>
>
> and thanks to polymorphism the user of MyPortal will get
> "my-portal-page.xsl" when asking for "styles/portal-page.xsl" and
> everything else will be delivered from Portal.
>
> But is that what we want? Taking a closer look at the sitemap in Portal
> there are a number of sitemap rules that uses "styles/portal-page.xsl"
> for creating other resources: "portal", "loggedin" and
> "resources/login-error.xml". What about them, should they use the the
> stylesheet from Portal or from MyPortal? In general it depends, but in
> this case our aim was to change to our on skin for the portal so we
> should use it everywhere.
>
> This is also covered by the polymorphism concept from OO. A service that
> is defined and used in the base block but overridden in the extending
> block should use the overriding service in the base block as well. But
> IMO it could be confusing if the default behaviour would be to have
> polymorphic lookup as default in blocks and because of that I proposed a
> block:polymorph subprotocol for being explicit about what service
> accesses in a (base) block that are supposed to be overridable. So in
> the Portal block we could have a sitemap rule:
>
> <match pattern="portal">
> ...
> <transform src="block:polymorph:/styles/portal-page.xsl"/>
> ...
> </match>
>
> if we access "portal" from the MyPortal block and have overrided
> "styles/portal-page.xsl" in MyPortal, the version from MyPortal will be
> used instead.
As promised, I've tried to come up with some pseudo-code that shows how
"single-inheritance + composition" looks like in a particular example (portal +
skinning).
- o -
We have following block interfaces:
===================================
- http://cocoon.apache.org/interfaces/portal/1.0
- http://cocoon.apache.org/interfaces/portal-skin/1.0
- http://mycompany.com/interfaces/skin/1.0
Here the block implementations:
===============================
---------------------------------------------------------------------------
"Portal"
---------------------------------------------------------------------------
BLOCK.XML
<block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
id="http://cocoon.apache.org/blocks/portal/1.0.0">
<name>portal</name>
<requirements>
<requires interface="http://cocoon.apache.org/interface/portal-skin/1.0"
name="portal"
default="http://cocoon.apache.org/blocks/portal-skin/1.0.0"/>
</requirements>
<implements>
<interface id="http://cocoon.apache.org/interfaces/portal/1.0"/>
</implements>
</block>
---------------------------------------------------------------------------
"Portal-Skin"
---------------------------------------------------------------------------
BLOCK.XML
<block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
id="http://cocoon.apache.org/blocks/portal-skin/1.0.0">
<name>portal-skin</name>
<implements>
<interface id="http://cocoon.apache.org/interfaces/portal-skin/1.0"/>
</implements>
</block>
SITEMAP.XMAP
<map:match pattern="*.css">
<map:read src="styles/css/{1}.css"/>
</map:match>
<map:match pattern="styles/portal-page.xsl">
<map:read src="styles/portal-page.xsl"/>
</map:match>
---------------------------------------------------------------------------
"MyPortal"
---------------------------------------------------------------------------
BLOCK.XML
<block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
id="http://mycompany.com/blocks/my-Portal/1.0.0">
<name>MyPortal</name>
<requirements>
<requires interface="http://mycompany.com/interfaces/skin/1.0"
name="skin"
default="http://mycompany.com/blocks/myskin/1.0.0"/>
<requires interface="http://cocoon.apache.org/interfaces/portal/1.0"
name="portal"
default="http://cocoon.apache.org/blocks/portal/1.0.0"/>
</requirements>
</block>
SITEMAP.XMAP
<map:match pattern="portal">
<map:act type="portal:auth-protect">
<map:parameter name="handler" value="portal-handler"/>
<map:parameter name="application" value="portal"/>
<map:generate type="portal:portal"/>
<map:transform src="blocks://skin/styles/portal-page.xsl">
<map:parameter name="user" value="{ID}"/>
</map:transform>
<map:transform type="core:cinclude"/>
<map:transform type="portal:portal-coplet"/>
<map:transform type="portal:portal-new-eventlink"/>
<map:transform type="core:encodeURL"/>
<map:serialize type="portal:html-include"/>
</map:act>
</map:match>
(Note: Most of the used components come from the portal block, the rest from
Cocon core; the stylesheet is provided by the "skin" block.)
---------------------------------------------------------------------------
"MySkin"
---------------------------------------------------------------------------
BLOCK.XML
<block xmlns="http://apache.org/cocoon/blocks/cob/1.0"
id="http://mycompany.com/blocks/my-Portal/1.0.0">
<name>MySkin</name>
<implements>
<interface id="http://cocoon.apache.org/interfaces/portal/1.0"/>
</implements>
<extends>http://cocoon.apache.org/blocks/portal-skin/1.0.0</extends>
</block>
SITEMAP.XMAP
<map:match pattern="one-special.css">
<map:read src="styles/css/one-special.css"/>
</map:match>
- o -
The project that wants to use the Portal is in the block "MyPortal". It needs
several components from "Portal" (generator, several transformers) and it needs
a block that provides the skin, or more precisly, it needs a block that
implements http://cocoon.apache.org/interfaces/portal-skin/1.0. This can either
be "portal-skin", the default skin, or "MySkin", that provides one additional
CSS. Everything else is taken from "portal-skin".
From my POV this solution is very clear and comprehensible. The aspects "portal
functionality" and "skinning" are separated and the used implementations can
simply be replaced by other implementations (shown by using the "mySkin" block).
- o -
What does your solution that ueses multiple inheritance look like? (If this is a
bad example to show the advantages of MI feel free to enhance it!)
--
Reinhard Pötz Independent Consultant, Trainer & (IT)-Coach
{Software Engineering, Open Source, Web Applications, Apache Cocoon}
web(log): http://www.poetz.cc
--------------------------------------------------------------------
Re: [RT] composition vs. inheritance in blocks
Posted by Ralph Goers <Ra...@dslextreme.com>.
Daniel Fagerstrom wrote:
> Ralph Goers wrote:
>
>> Daniel Fagerstrom wrote:
>>
>>> Ok, I'll give you a new example trying to explain the concept. Let's
>>> start with the portal block and say that I want to use that for my
>>> app, MyPortal, but I want a different skin. The skin consists of the
>>> stylesheet "styles/portal-page.xsl" among other things. We assume
>>> that the designer of the portal block wanted to make the skin
>>> overridable so there is a sitemap rule that exposes the stylesheet
>>> in the Portal block.
>>>
>>> <match pattern="styles/portal-page.xsl">
>>> <read src="default-portal-page.xsl"/>
>>> </match>
>>>
>>> Now I let MyPortal extends Portal and reimplements the stylesheet in
>>> MyPortal
>>>
>>> <match pattern="styles/portal-page.xsl">
>>> <read src="my-portal-page.xsl"/>
>>> </match>
>>>
>>> and thanks to polymorphism the user of MyPortal will get
>>> "my-portal-page.xsl" when asking for "styles/portal-page.xsl" and
>>> everything else will be delivered from Portal.
>>
>>
>>
>> Normally, I try to avoid these "theoretical" posts, but since you are
>> picking on the portal... Frankly, if the way you are proposing this
>> was actually how the portal worked we would not be using it.
>> Luckily, to do what you are suggesting is as simply as doing
>> something like:
>>
>> <map:match pattern="styles/portal-page.xsl">
>> <map:read
>> src="{globalConfig:/global-variables/skin}styles/portal-page.xsl"/>
>> </map:match>
>>
>> I understand you were trying to make a point, but sometimes I feel
>> like these diatribes resort to using a sledgehammer where a simple
>> screwdriver would do the job nicely.
>
>
> I based my example on the portal as Carsten asked about how one could
> use blocks for skins and for the portal (although my example didn't
> answer his questions). I also chosed it, to make the discussion less
> theoretical as it in the end is about highly practical things. And I
> doubt that we will ever get to the "real blocks", if we don't discuss
> and get feedback on practical usage.
>
> Now I'm aware that the portal samples use the construction you show
> above, but it doesn't achieve exactly the same thing as the
> construction I propose. If you want to use a slightly modified skin, I
> would assume that you start by copying the +30 files from
> skins/commons and then point "global-variables/skin" to the new
> location and start to modify whatever you wanted to modify.
>
> With my solution you just copy the file, in this case
> "portal-page.xsl" that you actually want to modify and write an
> overriding sitemap rule to use it. After having used thing like the
> global variable trick for a number of years in various applications,
> we had a tremendous amonount of different generations of esentially
> the same files and numerous copies of slightly modified sitemap
> snippets. Hardly supprising it was a maintainance nightmare. After
> having start to use the pattern that I propose we have seen a drastic
> decrease in the number of files in our new applications.
>
> So is it complicated? Not particular. As we use it in our apps we
> would write:
>
> <map:match pattern="styles/portal-page.xsl">
> <map:read src="cocoon://{request:sitemapPath}/styles/portal-page.xsl"/>
> </map:match>
>
Actually, we use
<map:read src="prefs://presentation/styles/.portal-page.xsl"/>
The input source takes care of finding the "correct" version of the file
based upon who the client is and whether they actually have a file. If
they don't, the default version of the file is used. The point is, the
problem is being attacked where it exists, not by making many
incarnations of a block. That will get to be unwieldy and cumbersome.
Ralph
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Ralph Goers wrote:
> Daniel Fagerstrom wrote:
>
>> Ok, I'll give you a new example trying to explain the concept. Let's
>> start with the portal block and say that I want to use that for my
>> app, MyPortal, but I want a different skin. The skin consists of the
>> stylesheet "styles/portal-page.xsl" among other things. We assume
>> that the designer of the portal block wanted to make the skin
>> overridable so there is a sitemap rule that exposes the stylesheet in
>> the Portal block.
>>
>> <match pattern="styles/portal-page.xsl">
>> <read src="default-portal-page.xsl"/>
>> </match>
>>
>> Now I let MyPortal extends Portal and reimplements the stylesheet in
>> MyPortal
>>
>> <match pattern="styles/portal-page.xsl">
>> <read src="my-portal-page.xsl"/>
>> </match>
>>
>> and thanks to polymorphism the user of MyPortal will get
>> "my-portal-page.xsl" when asking for "styles/portal-page.xsl" and
>> everything else will be delivered from Portal.
>
>
> Normally, I try to avoid these "theoretical" posts, but since you are
> picking on the portal... Frankly, if the way you are proposing this
> was actually how the portal worked we would not be using it. Luckily,
> to do what you are suggesting is as simply as doing something like:
>
> <map:match pattern="styles/portal-page.xsl">
> <map:read
> src="{globalConfig:/global-variables/skin}styles/portal-page.xsl"/>
> </map:match>
>
> I understand you were trying to make a point, but sometimes I feel
> like these diatribes resort to using a sledgehammer where a simple
> screwdriver would do the job nicely.
I based my example on the portal as Carsten asked about how one could
use blocks for skins and for the portal (although my example didn't
answer his questions). I also chosed it, to make the discussion less
theoretical as it in the end is about highly practical things. And I
doubt that we will ever get to the "real blocks", if we don't discuss
and get feedback on practical usage.
Now I'm aware that the portal samples use the construction you show
above, but it doesn't achieve exactly the same thing as the construction
I propose. If you want to use a slightly modified skin, I would assume
that you start by copying the +30 files from skins/commons and then
point "global-variables/skin" to the new location and start to modify
whatever you wanted to modify.
With my solution you just copy the file, in this case "portal-page.xsl"
that you actually want to modify and write an overriding sitemap rule to
use it. After having used thing like the global variable trick for a
number of years in various applications, we had a tremendous amonount of
different generations of esentially the same files and numerous copies
of slightly modified sitemap snippets. Hardly supprising it was a
maintainance nightmare. After having start to use the pattern that I
propose we have seen a drastic decrease in the number of files in our
new applications.
So is it complicated? Not particular. As we use it in our apps we would
write:
<map:match pattern="styles/portal-page.xsl">
<map:read src="cocoon://{request:sitemapPath}/styles/portal-page.xsl"/>
</map:match>
in the reusable portal sitemap. The "cocoon://{request:sitemapPath}/"
prefix "absolutizes" the URI so that it will be searched from the root
sitemap and a sitemap that mounts the portal sitemap can modify the
behaviour by writing an alternative rule for an uri. request:sitemapPath
is new in 2.2, so in 2.1 one need to write a module that makes
Environment.getURIPefix() available.
When you want to resue and modify the behaviour of the reusable portal
sitemap you write a new sitemap:
...
<pipeline>
<match pattern="styles/portal-page.xsl">
<read src="my-portal-page.xsl"/>
</match>
<mount uri-prefix="" src="context://block/portal"/>
</pipeline>
If this mechanism was used in the portal, there could be a small base
portal with overridable example configurations and example data, in the
portal jar. And a new portal user could start trying it as simple as:
<pipeline>
<mount uri-prefix="" src="resource://org/apache/cocoon/portal/site"/>
</pipeline>
and the incrementally add own behaviour while always having a working
portal. Today I would assume that a typical new user start by copying
the demo and goes from there. It works, but it mean that they after a
while they have several copies of base functionality in different portal
based webapps, that they need to maintain and maybe synchronize with
improvements in new Cocoon versions.
--- o0o ---
My aim is to make this mechanism or something equally powerful part of
the blocks.
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Ralph Goers <Ra...@dslextreme.com>.
Daniel Fagerstrom wrote:
> Ok, I'll give you a new example trying to explain the concept. Let's
> start with the portal block and say that I want to use that for my
> app, MyPortal, but I want a different skin. The skin consists of the
> stylesheet "styles/portal-page.xsl" among other things. We assume that
> the designer of the portal block wanted to make the skin overridable
> so there is a sitemap rule that exposes the stylesheet in the Portal
> block.
>
> <match pattern="styles/portal-page.xsl">
> <read src="default-portal-page.xsl"/>
> </match>
>
> Now I let MyPortal extends Portal and reimplements the stylesheet in
> MyPortal
>
> <match pattern="styles/portal-page.xsl">
> <read src="my-portal-page.xsl"/>
> </match>
>
> and thanks to polymorphism the user of MyPortal will get
> "my-portal-page.xsl" when asking for "styles/portal-page.xsl" and
> everything else will be delivered from Portal.
Normally, I try to avoid these "theoretical" posts, but since you are
picking on the portal... Frankly, if the way you are proposing this was
actually how the portal worked we would not be using it. Luckily, to do
what you are suggesting is as simply as doing something like:
<map:match pattern="styles/portal-page.xsl">
<map:read
src="{globalConfig:/global-variables/skin}styles/portal-page.xsl"/>
</map:match>
I understand you were trying to make a point, but sometimes I feel like
these diatribes resort to using a sledgehammer where a simple
screwdriver would do the job nicely.
Ralph
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Stefano Mazzocchi wrote:
> Daniel Fagerstrom wrote:
>
> [snip]
>
>> Can you describe how you would prefer to adress the "building a webapp
>> from several blocks" scenario that I described above.
>
>
> Daniel, you are asking for two things:
>
> 1) the existence of a super() equivalence in the block protocol
> 2) the introduction of multiple inheritance of block implementations
>
> the first is harmless and while I have never thought about needing it, I
> don't see how it could harm us, so I would not be against introducing it
> it. So, if Block A extends Block B, calling
>
> block:super://blah.xml
>
> from Block A would yield the call to 'blah.xml' in Block B. Does this
> satisfy your needs?
No, you still don't get it. Super can certainly be useful in some cases
but that's not what I'm talking about. Lets just forget about the
multiplicity of the inheritance or even the term inheritance until we at
least are discussing the same subject.
Ok, I'll give you a new example trying to explain the concept. Let's
start with the portal block and say that I want to use that for my app,
MyPortal, but I want a different skin. The skin consists of the
stylesheet "styles/portal-page.xsl" among other things. We assume that
the designer of the portal block wanted to make the skin overridable so
there is a sitemap rule that exposes the stylesheet in the Portal block.
<match pattern="styles/portal-page.xsl">
<read src="default-portal-page.xsl"/>
</match>
Now I let MyPortal extends Portal and reimplements the stylesheet in
MyPortal
<match pattern="styles/portal-page.xsl">
<read src="my-portal-page.xsl"/>
</match>
and thanks to polymorphism the user of MyPortal will get
"my-portal-page.xsl" when asking for "styles/portal-page.xsl" and
everything else will be delivered from Portal.
But is that what we want? Taking a closer look at the sitemap in Portal
there are a number of sitemap rules that uses "styles/portal-page.xsl"
for creating other resources: "portal", "loggedin" and
"resources/login-error.xml". What about them, should they use the the
stylesheet from Portal or from MyPortal? In general it depends, but in
this case our aim was to change to our on skin for the portal so we
should use it everywhere.
This is also covered by the polymorphism concept from OO. A service that
is defined and used in the base block but overridden in the extending
block should use the overriding service in the base block as well. But
IMO it could be confusing if the default behaviour would be to have
polymorphic lookup as default in blocks and because of that I proposed a
block:polymorph subprotocol for being explicit about what service
accesses in a (base) block that are supposed to be overridable. So in
the Portal block we could have a sitemap rule:
<match pattern="portal">
...
<transform src="block:polymorph:/styles/portal-page.xsl"/>
...
</match>
if we access "portal" from the MyPortal block and have overrided
"styles/portal-page.xsl" in MyPortal, the version from MyPortal will be
used instead.
--- o0o ---
So we have two aspects of polymorphism, the first is that services from
an extending block overides services in an extended block. But also that
services that are used as *part* of other services in the extended
block will be overrided by corresponding services in the extending block.
So, my main message is that I want this second aspect of polymorphism in
blocks as well. IMO (and experience) it makes blocks much more useful. A
block can contain overridable default values and example data so that it
can be used at once, then the user can override one thing at a time
during development. I gave an example of how one can work by using this
aspect of polymorphism in my last mail.
--- o0o ---
So what I'm proposing is that we should have this kind of polymorphism
in block. Or if anyone have a better mechanism that solves the same problem.
> [and no, let's not go over the super(2) to indicate the case where there
> is more than one layer of inheritance! that's FS!]
Don't worry, I don't like deep inheritance hierarchies.
> - o -
>
> As for MI, like I said before (and you carefully snipped),
Funny that you comment my snipping, in a mail where you snipped away
everything but two lines from my mail.
> MI makes it
> *easier* to glue pieces together that were not designed to be reused,
> while composition, since it forces you to define a behavioral interface
> for every exposed service, will very likely slow you down (yes! this is
> true! it's a feature not a bug) but will make you think about how to
> design those services.... A by product of this is that your services are
> instantanously more reusable and the contracts between components are
> more solid, and SoC/polymorphism much more effective (the size of the
> cocoon distribution proves my point).
I read it before and didn't comment because 1) I don't agree 2) IMO we
waste time by discussing sweeping analogues. If we want to get any
closer to real blocks we need to discuss concrete cases.
> So, instead of multiply inherit a bunch of blocks, you have to define a
> behavioral interface for every block (which is a URI at the end, not
> such a big deal) and indicate that you "require" the use of a block that
> implements that functionality.
>
> So, instead of what you are proposing:
>
> A -(extends)-> B
> A -(extends)-> C
No I don't. If you read my answer to Peter you could see that I even
start to doubt that it is meaningful to state that a block extends
another at some global level. I'm interested in being able to use, and
in some cases use and override services from several other blocks.
>
> I proposed to do:
>
> A -(requires)-> 1 <-(implements) B
> A -(requires)-> 2 <-(implements) C
>
> (where letters are implementations and numbers are interfaces), and if
> you need to extend B and C to provide a slightly different
> functionality, then you would have something like
>
> A -(requires)-> 1 <-(implements)- B2 -(extends)-> B
> A -(requires)-> 2 <-(implements)- C2 -(extends)-> C
>
> or fragmented in statements
>
> A -(requires)-> 1
> A -(requires)-> 2
> B -(implements)-> 1
> C -(implements)-> 2
> B2 -(extends)-> B
> C2 -(extends)-> C
>
> where you could have 'default' statements that say
>
> A -(prefers)-> B2
> A -(prefers)-> C2
>
> and the block manager would reason on the above graph and infer that
> it's sane and that
>
> A -(connects to)-> B2
> A -(connects to)-> C2
>
> which achieves the same exact functional effect as MI, but with more
> explicit contracts.
It's OK for me as long as A and B2 (or C2) can have the kind of
polymorph connection that I described innthe beginning.
Also I would appriciate if you could replace the letters and the numbers
above with something more concrete, and if you could flesh out some
details about how they actually are going to communicate. Before that it
is rather hard to compare our different approaches or even know if it is
different rather than complementing approaches. And above all it is hard
to get to the point where we can start to actually implement it.
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Stefano Mazzocchi <st...@apache.org>.
Daniel Fagerstrom wrote:
[snip]
> Can you describe how you would prefer to adress the "building a webapp
> from several blocks" scenario that I described above.
Daniel, you are asking for two things:
1) the existence of a super() equivalence in the block protocol
2) the introduction of multiple inheritance of block implementations
the first is harmless and while I have never thought about needing it, I
don't see how it could harm us, so I would not be against introducing it
it. So, if Block A extends Block B, calling
block:super://blah.xml
from Block A would yield the call to 'blah.xml' in Block B. Does this
satisfy your needs?
[and no, let's not go over the super(2) to indicate the case where there
is more than one layer of inheritance! that's FS!]
- o -
As for MI, like I said before (and you carefully snipped), MI makes it
*easier* to glue pieces together that were not designed to be reused,
while composition, since it forces you to define a behavioral interface
for every exposed service, will very likely slow you down (yes! this is
true! it's a feature not a bug) but will make you think about how to
design those services.... A by product of this is that your services are
instantanously more reusable and the contracts between components are
more solid, and SoC/polymorphism much more effective (the size of the
cocoon distribution proves my point).
So, instead of multiply inherit a bunch of blocks, you have to define a
behavioral interface for every block (which is a URI at the end, not
such a big deal) and indicate that you "require" the use of a block that
implements that functionality.
So, instead of what you are proposing:
A -(extends)-> B
A -(extends)-> C
I proposed to do:
A -(requires)-> 1 <-(implements) B
A -(requires)-> 2 <-(implements) C
(where letters are implementations and numbers are interfaces), and if
you need to extend B and C to provide a slightly different
functionality, then you would have something like
A -(requires)-> 1 <-(implements)- B2 -(extends)-> B
A -(requires)-> 2 <-(implements)- C2 -(extends)-> C
or fragmented in statements
A -(requires)-> 1
A -(requires)-> 2
B -(implements)-> 1
C -(implements)-> 2
B2 -(extends)-> B
C2 -(extends)-> C
where you could have 'default' statements that say
A -(prefers)-> B2
A -(prefers)-> C2
and the block manager would reason on the above graph and infer that
it's sane and that
A -(connects to)-> B2
A -(connects to)-> C2
which achieves the same exact functional effect as MI, but with more
explicit contracts.
--
Stefano.
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Stefano Mazzocchi wrote:
> Daniel Fagerstrom wrote:
>
>> Stefano Mazzocchi wrote:
>>
>>> Daniel Fagerstrom wrote:
>>
>> <snip/>
>>
>>> I don't like multiple inheritance and this is not just because I
>>> learned OOP thru java, but because every single time I wish I had
>>> multiple implementation inheritance in java I found a way to go
>>> around the problem with single implementation inheritance that was
>>> more elegant.
>>
>> I learned OOP thru C++, so I even have had the possibility of using
>> multiple implementation inheritance, not just the work arounds ;) And
>> in most cases composition is better than multiple implementation
>> inheritance, but in the cases where you merge two different concern
>> areas it is useful and natural according to my experience. While I
>> don't find the "extend the largest abstract base class and repeat the
>> interface and delgate to the other" ideom used in Java particulary
>> elegant.
>>
>> But, although I believe that we should use well known concepts from
>> OO as much as possible in the design of blocks, as we know some of
>> the consequnces of them and as they are familiar to the users, we
>> must be aware about that blocks and typical objects have quite
>> different levels of granularity and are not completely analogous.
>>
>> --- o0o ---
>>
>> So what I propose is that "extend and override" is a convenient and
>> productive way to build webapps. You start from a working default
>> application and add your own data and modify the behaviours that you
>> need to modify. If you have used Forrest, you know what I'm talking
>> about. But the difference between Forrest and what I propose is that
>> you don't need any complicated sitemap tricks and global
>> configurations with search paths, if we makes the block polymorphic.
>>
>> --- o0o ---
>>
>> This is not just armchair speculations from me. We have built a
>> number of webapps during the last year based on sitemap polymorphism.
>> The mechanism is rather simple, in the sitemap of the base
>> application we use a variant of the cocoon protocol:
>>
>> cocoon:polymorph:/foo.xml
>>
>> that basically calls
>>
>> cocoon://<sitemap-path>/foo.xml
>>
>> by mounting the base application in the end of the "extending"
>> sitemap, the polymorph sitemap rules can be overrided just by
>> defining the uri in the before the mount.
>>
>> Its easy and works well. Of course one have to do some thinking to
>> build a reusable base application, but that goes generally for
>> reusability.
>>
>> We started to use this pattern because we had a webapp, that a number
>> of customers wanted slight variations of. In the beging we just made
>> the new webapps extend a slight abstraction of the original webapp.
>> Not because I thought it was a good idea, but more because of time
>> constraints. Our experience is, hardly supprising, that it is more
>> flexible to base your webapp on a number of orthogonal vertical
>> frameworks. So we have factored out some such from the original webapp.
>>
>> --- o0o ---
>>
>> So our experience is:
>> * extend and override is productive
>> * vertical frameworks are easier to reuse
>
>
> If you are talking about
>
> block A extends block B
>
> then the functionality that you describe above is already included in
> the original real block design and you don't even need the (ugly!)
> polymorphic protocol flavor, since the block protocol should takes
> care of all this transparently (thru the block dependency map of the
> block manager).
Citing from
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=111209768003970&w=2
>In your example block A extends block B, then in block B we can have a
>sitemap rule like:
>
><map:match pattern="**.html">
> <map:generate src="{1}.xml"/>
> <map:transform src="block:polymorph:/stylesheets/document2html.xslt"/>
> <map:serialize/>
></map:match>
>
>The block:polymorphism makes that stylesheets/document2html.xslt is
>taken from A rather than B. Say that you use that stylesheet in several
>rules, then you change multiple behaviours by overriding it.
>
>
I described why I think its safer to be explicit about when an
(extended) block should find a service by polymorphic rather than local
lookup in
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=111183895029727&w=2:
>Ok, allready discussed that above. I think we need to be more explicit
>about what behaviour we want. If we just write:
>
><map:transform src="stylesheets/document2html.xslt"/>
>
>that means normally the same as:
>
><map:transform src="context:/stylesheets/document2html.xslt"/>
>
>and I don't think it is a good idea for isolation between block to be
>able to overide what is in the current context, only things that are
>exposed through the sitemap should IMO be overidable:
>
><map:transform src="block:polymorph:/stylesheets/document2html.xslt"/>.
>
>
So I talk about polymorphic access *whithin* a possibly extended block.
I'm fully aware that you described how A can override B by exposing an
uri that is exposed in B, and I agree with the proposed mechanism.
Question is how to handle the use of a service within the extended block
(B) if this service is overriden i the extending block (A).
> But (as usual), you jumped directly from that to
>
> block A extends block b *and* c
I wrote:
> Our experience is, hardly supprising, that it is more flexible to base
> your webapp on a number of orthogonal vertical frameworks. So we have
> factored out some such from the original webapp.
on the line before my conclusion, and also described why I wanted it
earlier in the thread, but (as usual) you jumped in and started
screaming without bothering to read the whole thread.
> which, to me, is not the painless jump that you (and Peter) seem to
> suggest.
As already said, I have practical experience of using multiple
inheritance in C++ and poymorphic extensions of sitemaps in Cocoon. And,
like any other powerful construct, you have to learn how to use it and
it can be missused, but in my experience, it simplifies life if you use
it in the right way.
A coleauge of mine was involved in building some rather large systems in
Common Lisp long time ago, and used multiple (implementation)
inheritance as one of the major ways to compose the systems. Hi find the
single inheriatnce idea in Java ridiculous, and claims that he was about
a magnitude more productive when he programmed in Common Lisp rather
than in Java. Now comparing langauges is rather unproductive, I just
wanted to point out that multiple inheritance not is bad per se, it all
depends on what you use it for and how it is implemented in the
particular language.
>> This implies AFAICS multiple inheritance
>
> not at all. you can have block 'cascading'/'wrapping' (you name it)
> without multiple inheritance.
Sure, but if you want to base your webapp on several blocks that takes
care of different concerns you have to chose which of them you want to
be able to extend if you have single inheritance.
--- o0o ---
But let's take a look at an example instead. We have built a number of
webapps for administring sells campaigns for a number of companies
within the same concern that are based on the polymorphic sitemap
inheritance scheme that I described above. The webapps have
functionality for administring the campaigns (of course), functionality
for selecting and optimizing what customers to communicate with,
documentation of how it works and about data models, visualization of
the results of the campaigns, it communicates with some other systems,
database administration functionality that we use internally etc.
Ok, when building a new system like this I start with a sitemap like:
...
<pipeline>
<match pattern="sysadm/**">
<mount uri-prefix="sysadm" src="context://block/sysadm"/>
</match>
<match pattern="campaign/**">
<mount uri-prefix="campaign" src="context://block/campaign"/>
</match>
<match pattern="doc/**">
<mount uri-prefix="doc" src="context://block/doc"/>
</match>
<!- other "blocks" -->
<match pattern="**">
<mount uri-prefix="" src="context://block/skin"/>
</match>
</pipeline>
...
By typing "index.html" in my browser I get the default start page from
"/block/skin", its a little bit like the default start page from
Forrest: menu, menubar, bread crumb, short description about how to
continue the development in the main page, etc.
First step is puting the other functionality in the menu, so I write an
own "site.xml" that overides the polymorphically used in skin:
<pipeline>
<match pattern="site.xml">
...
</match>
<!-- as before -->
whithin skin "site.xml" is used through "block:polymorph:/site.xml" and
the overriding version will be used instead. Now my application have
menu links to the default implementation of the other blocks (that may
contain own manu definitions). I continue by overiding the uris to some
of the icons, the start page, some css rules and maybe a "setting.xml"
that describe some of the texts etc in the skin. Now I have customized
how the application looks, start page an the top menu structure.
Next, probably after having created sub sitemaps for campaign, doc etc,
I start to customize the parts of my webapp, by overriding some default
behaviour in campaign, doc etc. I override the default (example) db meta
description for my particular campaign database, change some of the adm
forms etc. I use the same db meta description to my doc "block" as well
for geting various data views: table overview and a connection diagram.
For more general use we should of course factor out the db documentation
to a separate dbdoc block, but all our webapps are db based so we
haven't found it worthwhile yet.
--- o0o ---
The important thing here is that my "blocks" are useable as is with
example or default data, so that you just can mount them and test them.
Then the things that are designed to be overidden is used through the
"block:polymorph" protocol and can be overiding by puting a rule before
the mount in the mounting sitemap.
To make this way of building webapps as simple and convenient as
possible it is of course important to have common formats and design
conventions between the block. And to focus the blocks so that they do
one thing good instead of doing a little bit of everything. Also most of
the blocks: systemadm, campaign and doc above should be "content" blocks
and let the skin take care of view aspects.
If the blocks doesn't use the same formats things get more complicated,
but it is still possible to handle. Say that "campaign" and "doc" uses
different db description formats. Then you could write something like:
<match pattern="campaign/db.xml"/>
<read src="db.xml"/>
</match>
<match pattern="doc/db.meta"/>
<generate src="db.xml"/>
<transform src="myDMMeta2TheirDBMeta.xsl"/>
<serialize/>
</match>
<!-- mount the campaign and doc blocks -->
--- o0o ---
So what I want to have in blocks, is this possiblity to extend and
override functionality in several blocks. But I don't see any need for
leting my "application level" blocks export all the services from the
blocks it extend the functionality from. For sitemap services I prefer
to explicitly export things with "mount" and for components we could
have some similar mechanism as I described in my comment to Peter's mail.
>> as you have to implement polymorphism by hand if you use composition.
>
>
> No. Absolutely not. Go back and read all my emails about the block
> protocol: the functionality you describe is already there and doesn't
> require MI at all.
I have read the ones that have links from
http://wiki.apache.org/cocoon/Blocks and serched the archives for block
discussions numerous times, and haven't found anything that adresses the
usage scenario that I described above. If there are other relevant mails
that adresses this, please do us all a service and add the links to the
Wiki.
<snip/>
Can you describe how you would prefer to adress the "building a webapp
from several blocks" scenario that I described above.
/Daniel
Re: [RT] composition vs. inheritance in blocks
Posted by Stefano Mazzocchi <st...@apache.org>.
Daniel Fagerstrom wrote:
> Stefano Mazzocchi wrote:
>
>> Daniel Fagerstrom wrote:
>
>
> <snip/>
>
>> I don't like multiple inheritance and this is not just because I
>> learned OOP thru java, but because every single time I wish I had
>> multiple implementation inheritance in java I found a way to go around
>> the problem with single implementation inheritance that was more elegant.
>
>
> I learned OOP thru C++, so I even have had the possibility of using
> multiple implementation inheritance, not just the work arounds ;) And in
> most cases composition is better than multiple implementation
> inheritance, but in the cases where you merge two different concern
> areas it is useful and natural according to my experience. While I don't
> find the "extend the largest abstract base class and repeat the
> interface and delgate to the other" ideom used in Java particulary elegant.
>
> But, although I believe that we should use well known concepts from OO
> as much as possible in the design of blocks, as we know some of the
> consequnces of them and as they are familiar to the users, we must be
> aware about that blocks and typical objects have quite different levels
> of granularity and are not completely analogous.
>
> --- o0o ---
>
> So what I propose is that "extend and override" is a convenient and
> productive way to build webapps. You start from a working default
> application and add your own data and modify the behaviours that you
> need to modify. If you have used Forrest, you know what I'm talking
> about. But the difference between Forrest and what I propose is that you
> don't need any complicated sitemap tricks and global configurations with
> search paths, if we makes the block polymorphic.
>
> --- o0o ---
>
> This is not just armchair speculations from me. We have built a number
> of webapps during the last year based on sitemap polymorphism. The
> mechanism is rather simple, in the sitemap of the base application we
> use a variant of the cocoon protocol:
>
> cocoon:polymorph:/foo.xml
>
> that basically calls
>
> cocoon://<sitemap-path>/foo.xml
>
> by mounting the base application in the end of the "extending" sitemap,
> the polymorph sitemap rules can be overrided just by defining the uri in
> the before the mount.
>
> Its easy and works well. Of course one have to do some thinking to build
> a reusable base application, but that goes generally for reusability.
>
> We started to use this pattern because we had a webapp, that a number of
> customers wanted slight variations of. In the beging we just made the
> new webapps extend a slight abstraction of the original webapp. Not
> because I thought it was a good idea, but more because of time
> constraints. Our experience is, hardly supprising, that it is more
> flexible to base your webapp on a number of orthogonal vertical
> frameworks. So we have factored out some such from the original webapp.
>
> --- o0o ---
>
> So our experience is:
> * extend and override is productive
> * vertical frameworks are easier to reuse
If you are talking about
block A extends block B
then the functionality that you describe above is already included in
the original real block design and you don't even need the (ugly!)
polymorphic protocol flavor, since the block protocol should takes care
of all this transparently (thru the block dependency map of the block
manager).
But (as usual), you jumped directly from that to
block A extends block b *and* c
which, to me, is not the painless jump that you (and Peter) seem to suggest.
> This implies AFAICS multiple inheritance
not at all. you can have block 'cascading'/'wrapping' (you name it)
without multiple inheritance.
> as you have to implement
> polymorphism by hand if you use composition.
No. Absolutely not. Go back and read all my emails about the block
protocol: the functionality you describe is already there and doesn't
require MI at all.
> If you have better ideas
> about how to achive default behaviour that is easy to override, I'm of
> course interested to discus them instead.
see above.
> We have only used polymorphism on sitemap level, if it is usefull for
> components is another question, I would assume that, but it needs
> further thinking.
exactly.
>> I would go a little further and say that I believe inheritance is
>> useful only when used as a 'cascading' mechanism, in any other sense
>> is harmful: composition should be used instead.
>>
>> Why so?
>>
>> It's extremely hard to design for inheritance, a lot easier to design
>> for composition.
>
> These are different concerns. Of course we should support composition,
> no doubt about that, but based on the reasons and experiences described
> above I want inheritance as well.
I completely agree that inheritance is useful. Dead useful. But single
inheritance not multiple one.
> And it is no doubt easier to design
> components than vertical frameworks, but that doesn't mean that we
> should avoid designing framewoks.
hell no. I had enough 'build the framework before we even know where the
problem is' avalonish crap in my life, thanks.
Until somebody proves me that this is no way to obtain a required
functionality without MI, I'm -1 on it.
>> And performing composition thru multiple-inheritance is a really
>> terrible way to do it. Why? because you need to go very deep in
>> describing what behaviors get exposed and what are protected,
>> otherwise things get messy very fast.
>
> Sure, it is well known deep hierarchies of implementation inheritance
> often leads to problems. People tried to use it as "the golden hammer"
> once, but that doesn't make it less usefull for what it is good for.
Sure, for cascading. Agreed. therefore 'single' inheritance.
>> Also, multiple-inheritance stops further composition: you seem to
>> suggest that a block that inherit multiply is a 'leaf block', one that
>> is your own application and that will not be used by others.
>
> Yes, that is correct, I want it to be as simple as possible to put
> together a webapp based on ready made vertical frameworks.
and can you tell me why MI is supposed to help you achieving this?
>> Well, one of the reasons for block design was to sparkle the creation
>> of reusable application components without people to think much about
>> them: multiple-inheritance yields horizontal behavior changes to the
>> inherited components, which means that if I have block A inherit block
>> B and then block C that wants to use A but was already using B, but A
>> modified B's behavior a little with the inheritance, you have a problem!
>
> Sure, you have to keep your blocks orthogonal to make them reusable,
> overlapping behaviour leads to a mess.
Bingo.
> But honestly, reusabillity has been considered a major topic in the
> software business for a number of decades. We all know that it doesn't
> happen spontaniously, you have to design for it and you have to reuse
> your component or framework a number of times and make lot of
> improvements before it becomes more generally reusable.
Very very true, and my argument is that MI moves the pain one step down,
so that you never go thru exactly *that* design for reuse phase that
composition forces you to go thru.
>> I am strongly against multiple implementation inheritance for blocks,
>> because what you want to do, if you care about reusability, is really
>> multiple composition and that is achieved with being allowed to
>> implement multiple behavioral interfaces.
>
> Of course I want to support that as well.
Very well, then we have composition (multiple implementation of
interfaces) and single inherit
>
>> If you *don't* care for reusability, then it's true that multiple
>> implementation inheritnace can serve as a cheaper form of composition.
>
>
> For the majority of Cocoon users I would assume that blocks that are
> possible to extend and override is easier to reuse (considered that they
> have a good design of course), than just a lump of components and
> stylesheets.
>
>> But if I had to pick between improving block reusability or ease of
>> composition, I would go with the first, hoping that tools/syntax-sugar
>> would help the second (as it happened with Java).
>
>
> It's not either or. It's not exactly rocket science to build a mechanism
> for mutiple inheritance so we can have booth.
>
> We just need to discuss what we want to achieve and how to achive it to
> get it right.
>
> /Daniel
>
>
>
--
Stefano.
Re: [RT] composition vs. inheritance in blocks
Posted by Daniel Fagerstrom <da...@nada.kth.se>.
Stefano Mazzocchi wrote:
> Daniel Fagerstrom wrote:
<snip/>
> I don't like multiple inheritance and this is not just because I
> learned OOP thru java, but because every single time I wish I had
> multiple implementation inheritance in java I found a way to go around
> the problem with single implementation inheritance that was more elegant.
I learned OOP thru C++, so I even have had the possibility of using
multiple implementation inheritance, not just the work arounds ;) And in
most cases composition is better than multiple implementation
inheritance, but in the cases where you merge two different concern
areas it is useful and natural according to my experience. While I don't
find the "extend the largest abstract base class and repeat the
interface and delgate to the other" ideom used in Java particulary elegant.
But, although I believe that we should use well known concepts from OO
as much as possible in the design of blocks, as we know some of the
consequnces of them and as they are familiar to the users, we must be
aware about that blocks and typical objects have quite different levels
of granularity and are not completely analogous.
--- o0o ---
So what I propose is that "extend and override" is a convenient and
productive way to build webapps. You start from a working default
application and add your own data and modify the behaviours that you
need to modify. If you have used Forrest, you know what I'm talking
about. But the difference between Forrest and what I propose is that you
don't need any complicated sitemap tricks and global configurations with
search paths, if we makes the block polymorphic.
--- o0o ---
This is not just armchair speculations from me. We have built a number
of webapps during the last year based on sitemap polymorphism. The
mechanism is rather simple, in the sitemap of the base application we
use a variant of the cocoon protocol:
cocoon:polymorph:/foo.xml
that basically calls
cocoon://<sitemap-path>/foo.xml
by mounting the base application in the end of the "extending" sitemap,
the polymorph sitemap rules can be overrided just by defining the uri in
the before the mount.
Its easy and works well. Of course one have to do some thinking to build
a reusable base application, but that goes generally for reusability.
We started to use this pattern because we had a webapp, that a number of
customers wanted slight variations of. In the beging we just made the
new webapps extend a slight abstraction of the original webapp. Not
because I thought it was a good idea, but more because of time
constraints. Our experience is, hardly supprising, that it is more
flexible to base your webapp on a number of orthogonal vertical
frameworks. So we have factored out some such from the original webapp.
--- o0o ---
So our experience is:
* extend and override is productive
* vertical frameworks are easier to reuse
This implies AFAICS multiple inheritance, as you have to implement
polymorphism by hand if you use composition. If you have better ideas
about how to achive default behaviour that is easy to override, I'm of
course interested to discus them instead.
We have only used polymorphism on sitemap level, if it is usefull for
components is another question, I would assume that, but it needs
further thinking.
> I would go a little further and say that I believe inheritance is
> useful only when used as a 'cascading' mechanism, in any other sense
> is harmful: composition should be used instead.
>
> Why so?
>
> It's extremely hard to design for inheritance, a lot easier to design
> for composition.
These are different concerns. Of course we should support composition,
no doubt about that, but based on the reasons and experiences described
above I want inheritance as well. And it is no doubt easier to design
components than vertical frameworks, but that doesn't mean that we
should avoid designing framewoks.
> And performing composition thru multiple-inheritance is a really
> terrible way to do it. Why? because you need to go very deep in
> describing what behaviors get exposed and what are protected,
> otherwise things get messy very fast.
Sure, it is well known deep hierarchies of implementation inheritance
often leads to problems. People tried to use it as "the golden hammer"
once, but that doesn't make it less usefull for what it is good for.
> Also, multiple-inheritance stops further composition: you seem to
> suggest that a block that inherit multiply is a 'leaf block', one that
> is your own application and that will not be used by others.
Yes, that is correct, I want it to be as simple as possible to put
together a webapp based on ready made vertical frameworks.
> Well, one of the reasons for block design was to sparkle the creation
> of reusable application components without people to think much about
> them: multiple-inheritance yields horizontal behavior changes to the
> inherited components, which means that if I have block A inherit block
> B and then block C that wants to use A but was already using B, but A
> modified B's behavior a little with the inheritance, you have a problem!
Sure, you have to keep your blocks orthogonal to make them reusable,
overlapping behaviour leads to a mess.
But honestly, reusabillity has been considered a major topic in the
software business for a number of decades. We all know that it doesn't
happen spontaniously, you have to design for it and you have to reuse
your component or framework a number of times and make lot of
improvements before it becomes more generally reusable.
> I am strongly against multiple implementation inheritance for blocks,
> because what you want to do, if you care about reusability, is really
> multiple composition and that is achieved with being allowed to
> implement multiple behavioral interfaces.
Of course I want to support that as well.
> If you *don't* care for reusability, then it's true that multiple
> implementation inheritnace can serve as a cheaper form of composition.
For the majority of Cocoon users I would assume that blocks that are
possible to extend and override is easier to reuse (considered that they
have a good design of course), than just a lump of components and
stylesheets.
> But if I had to pick between improving block reusability or ease of
> composition, I would go with the first, hoping that tools/syntax-sugar
> would help the second (as it happened with Java).
It's not either or. It's not exactly rocket science to build a mechanism
for mutiple inheritance so we can have booth.
We just need to discuss what we want to achieve and how to achive it to
get it right.
/Daniel