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

Reply via email to