I've read with a lot of interest the thoughts and requirements coming out of this thread - in particular the comments from Daz, Gary, and Adam. One of comments that I found profound but obvious was the observation that current concepts/thinking is very container architecture driven. I've been thinking and thinking about this and I've reached some sort of a conclusion that would enable the end user to express component relationships independently of the context/service split.

The the avalon-sandbox info and meta packages both force the container driven perspective on context/service separation - and I've come to the conclusion the (a) this is not needed, and (b) that potable context can be provided - if we rehash the meta model.


If you familiar with either the info or meta package you will be aware of the following pattern:

[meta-info-for-component]

* [general-info-block]
* [context-block]
* [services-provided-block]
* [service-dependencies-block]

I'm starting to think about an alternative approach. I've identified three distinct groups that can be both consumed and provided (from a container perspective). These include the following:

* Service providers

These are the classic services that can be assembled
based on consumption and production declarations.

* Service locator

This is a new concept that is very similar to the
Merlin extension handler. It a component that provides
a plug-in lookup solution that can be narrowed to a
particular interface (and can be located by the container
using the interface name as the key). A service locator
can be applied to the following three areas:

* context value lookup
* service lookup
* lifecycle stage handler lookup

If we re-examine things from the the component authors perspective, it seems reasonable to describe the mapping of a service, context and lifecycle in terms of production and consumption relationships.

[meta-info]

* [general-info]
* [consumption-info]
* [production-info]

From this model we can esily map in the container view of the world by doing something like the following:

[meta-info]

* [general-info]
* [consumption-info]
* [context]
* [service-dependencies]
* [locator-dependencies]
* [service]
* [services-dependencies]
* [locator-dependencies]
* [lifecycle]
* [stage-dependencies]
* [production-info]
* [service-provision]
* [locator-provision]
* [stage-provision]


What's interesting about the above is that (a) the object model for context and service is parallel. This means that the client can narrow a supplied context instance to a particular interface, and can do the same thing with a supplied service manager. The container author can forget about declaring typed context entries, and instead, he/she can simply declare a set of locator dependencies - e.g. an author may want a BlockContext locator and a MailetContext locator. The container can handle the establishment of the respective context and service managers so that any pure key based request still map to the appropriate locator and any casting against interfaces supported by the set of associated locators can be wrapped in a composite proxy.

A second interesting point is that the component author has 100% control over which services and locators are mapped to the context abstraction as opposed to the service abstraction. The component author would be to include totally different locators into a single context without any client side impact relative to current framework interfaces. And most importantly, the entire models can portable across containers that support a standard locator object model.

From the container authors point of view locators can be treated as components and as such that can have their own dependencies. This means that something like a BlockContext locator can plugged into the system and the container simply assembles it and assigns it as appropriate.

A complete DTD for component model on the above with both consumption and production features would look something like:

<type>

<info name="demo" version="2.0"/>

<consumes>

<lifecycle>
<stage type="org.demo.Demonstratable"/>
</lifecycle>

<context>
<locator type="org.a.a.f.context.SystemLocator" version="4.1.2"/>
<locator type="org.a.j.MailetLocator" version="2"/>
<service type="org.demo.SimpleService" key="simple" version="1"/>
</context>

<services>
<service type="org.demo.Store" key="vault"/>
<locator type="org.demo.SecurityLocator" version="4.1.2"/>
<services>

</consumes>

<produces>

<service type="org.demo.PathResolver" version="3.2" />
<locator type="org.demo.Directory" />
<stage type="org.demo.Exploitable" version=2"/>

</produces>

</type>

From the point of view of current framework interfaces, it would be feasible to incorporate a framework level Locator interface as a super-type of both ServiceManager and Context so that operations on the supplied parameter to contextualize and service could be treated in the same way. It would even be possible to incorporate migration interfaces into 4.2 version of Contextulizable and Serviceable under which a Locator is passed as the parameter.

E.g.

public void contextualize( Locator locator ) throws LocatorException
{
SystemLocator system = (SystemLocator) locator;
File base = system.getWorkingDirectory();
m_name = locator.locate( "urn:avalon:name" );
}

public void service( Locator locator ) throws LocatorException
{
SecurityLocator sec = (SecurityLocator) locator;
Privalege[] sec.getPrivaliges( m_name );
// etc.
}

From here, the differentiating factor between contextualization and services phases is reduced to the ordered sequence in the lifecycle.

Any thoughts ?



Darrell DeBoer wrote:

Thanks Gary,

It's funny, I woke up this morning with a similar conclusion. Yesterday, for the first time, I could see both Peter's and Stephen's arguments for a distinction between Container-supplied and Peer-supplied services (or "(non)priviledged" as Stephen is calling the distinction).

The problem with both of these distinctions is that they are about Container implementation. My take on it is thus:

Peter wants to distinguish Container-provided services, because the person doing the assembly doesn't have to specify them in the assembly file. Unfortunately, it's quite easy to imagine one container which provides a certain service directly, and a different one which requries a user-configured component to provide the same service. So by distinguishing between these in *code*, the component will be inherently non-portable. (Whereas the assembly file can be thought of as container-specific? - At least it's easy to change for a new deployment).

Stephen wants to have the notion of priviledged services, so he can implement life-cycle handlers and context providers as components (at least this is what I've garnered from the emails, I don't know the code). While this sounds cool from the design perspective, it seems like this notion should be kept out of Framework, as it's a specific requirement of the Merlin container. Other containers may want to provide extensibility in a completely different way (maybe the "interceptors" Pete has eluded to fall into this). What follows is that regular components which rely just on Framework contracts will be portable, whereas Merlin lifecycle extension components don't need to be, so they can use a Merlin-specific contracts and interfaces.

(Who says having competing container implementations is a bad thing? ;)

This example is giving me a few troubles:

getServletContext().isPrincipleInRole( String role, Principle p );
getSessionContext().isCallerInRole( String role );

These are container provided services, and it would "feel" right that they would be split out from the provision of other services. But then you realise: - these interfaces are defined as part of a specification. The container can't choose whether or not to provides these things, they are required. And the container can't arbitrarily provide new stuff in this way, since then a component would become non-portable.

So I can't see the argument for the Container-provided/Peer-provided divide. But I can see an argument for a logical and code separation of services defined in the spec (and therefore part of the Avalon-Framework contracts), and other services (both container and peer).

At the moment, I don't think any such services exist. Maybe we should come up with some, and *maybe* they should be provided in a separate mechanism to regular services. But since they are part of the spec, components won't need to "declare" the context they require, and things like MailetContext and ServletContext are removed from these arguments, since they aren't part of the Avalon-Framework contracts.

This is my take on the matter, anyhow.

ciao
Daz

On Thu, 5 Dec 2002 04:05, Gary Shea wrote:

I've been following this thread with a great deal of interest, since I
have the same questions as Adam has been asking. My experience with
using Avalon is that Context is great until you get someone else's
container involved in the picture. At that point it becomes a minor
nightmare, since each container sees it differently.

My views are from the perspective of a component writer who wants to
avoid container lock-in.

I've been willing to adopt the data/services distinction, because the
container I want to use (merlin) does so. But the data/services
paradigm turns Context into either a less-capable Configuration or a
declaratively-driven object builder. The idea of Context as an object
builder feels kind of baroque to me, and I can't imagine that all
containers will do it, so in merlin I don't use Context at all.

The container-provided/peer-provided view is one I'd be willing to adopt
also. In this view, Context is container-dependent, and is simply
anathema to the component writer who wants to maintain cross-container
portability. That's the extent of my interest. I can see how this
view would be useful to someone building a tightly-coupled
component/container system, but my goal is to avoid that at all costs.

As you can see, I wouldn't use Context under either of the data/service
or container/peer paradigms. I think that's ok.

If this discussion had to end today, I'd say Context is a red herring
and should be discarded. It would be replaced with two new stages:
ObjectConfigurable and ContainerServiceable.

Gary

[2002-12-04 21:56 +1100] Peter Donald ([EMAIL PROTECTED]) wrote:

On Wed, 4 Dec 2002 11:07, Adam Murdoch wrote:

These are useful things, no question. Components need some way to get
at data and services that are supplied by the container. Again, why do
they care that a particular service or piece of data was supplied by
the container or a peer?

Components don't care what the origins of the resource are - all of it is
potentially "contextualized" on a per component basis and all generally
has certain criteria to adhere to but beyond that it is about it. The
different resources are separated out for the sake of humans and no other
reason.

Context is separated from ServiceManager because humans see them as
different things - especially during the assembly process.


Yes, I know that they're "different logical things". But so are, say,
authentication services and persistence services. We don't use
different mechanisms to deliver those services to components. It would
be pointless to do so:

I disagree. If persistence were provided to the component and the
component was effectively made to be an OJB object or something like that
then we would likely provide persistence/transaction capabilities in a
very different manner. Most likely via some transparent EJB-like manner.

In the same way if AAA services were provided to a component as part of
it's environment then it would likely also follow an EJB/Servlet style
setup where the container does it via interception and allows components
to access it programatically via something like

getServletContext().isPrincipleInRole( String role, Principle p );
getSessionContext().isCallerInRole( String role );
(or insert real examples here or JAAS).

If the services are things that the container provides to the component
as part of it's environment then the user perceives them as different to
services that the component uses. I can't think of one API that actually
merges the two concepts.

When we tried to merge the two things together the primary reason we
separated them out again was because of user complaints. ie If a
resources requires resources A, B and C and C is container provided. All
three are accessed in the same way so the person sees them as much the
same (like the component sees them as much the same). However during
assembly they are only required to assemble A and B - which creates a
cognitive dissonance because they are treated as identical in one place
but different in another.


So which of these cases do you think offer the most benefit to the
component writer? Assume logger, config, params have been split out
already: 1. No separation.
2. Separate data and services.
3. Separate container-provided resources and peer-provided resources.

+1


4. Separate container-provided data, container-provided services,
peer-provided data, and peer-provided services.
5. Who cares? Why are you bothering me with these questions?


:)

--
Cheers,

Peter Donald
*------------------------------------------------*

| Those who know how to think need no teachers. |
| - Gandhi |

*------------------------------------------------*


--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional
commands, e-mail: <mailto:[EMAIL PROTECTED]>


--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>




--

Stephen J. McConnell

OSM SARL
digital products for a global economy
mailto:[EMAIL PROTECTED]
http://www.osm.net




--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to