Hi Stephen,
I think I see where you are going with this. As a first step, what do you think if I implement the <specification> section of the <service> declaration, but basically just read the artifact entries from the specification section and promote them up the classloader chain? After that is working, then we could tackle the classloader relocation and extension resolving.
I was chatting to Niclas about this subject a day or two ago and he basically came up with a bunch of issues none of which I can reasonably summarize at 5 in the morning. However - it did get me thinking about the difference in scope of specification between the block and a service.
If we take the http facility as an example block - we basically have a specification of system represented by the set of services provided by the block - i.e. the "http facility specification". If we look at the specification dependencies at this level we see things like the Servlet 2.1 specification. However - if we look down at the services that are exported - the specifications are much more fine grain.
My conclusion is that the specification I'm describing below should declared at the block level - and not at the service level - e.g.:
<classloader>
<specifications>
<specification>
<name>urn:apache:widget</name>
<version>2.1</version>
<artifact>apache/widget#2.1</artifact>
</specification>
</specification>
</specifications>
<classpath>
<!-- as per current approach -->
</classpath
<classloader>From this - we simply merge the spec artifact as an entry in the classloader classpath.
I still think that the notion of including specification details in the service element is a good idea - but I think its a scope related to service usage as distinct from the structural specification presented in the classloader.
Cheers, Stephen.
-Cameron
-----Original Message----- From: Stephen McConnell To: Avalon framework users Sent: 4/24/04 10:30 AM Subject: Re: [merlin] separate api and impl sections in classloader section of block.xml?
Cameron:
The declaration of an <api> classloader set (under the classloader or under a service export directive) is basically stating to the container that to use service X, you need to have in you classloader jar files A, B and C. Problem here is that the your going to express A, B and C in terms of jar artifact references as opposed to specification references.
What we want to be able to say - for a particular service export - is ... "to use this service the consumer's classloader needs to provide support for specification X". If we look at the consumer's classloader we can check manifest entries for the Extension-Name combined with a compatibility check relative to Specification-Version.
Example Manifest:
Extension-Name: urn:apache:widget Specification-Version: 2.1
Example <service> declaration.
<services> <service type="org.apache.Widget> <specification> <name>urn:apache:widget</name> <version>2.1</version> <artifact>apache/widget#2.1</artifact> </specification> </service> </services>
In the above example the <specification> elements is basically saying:
1. any consumer of this service should exist within a classloader that provides support for the "urn:apache:widget" specification version 2.1.
2. when constructing the classloader, if the parent classloader does not provide support for the specification, then add the supplied artifact to the classloader.
This also implies that the "apache/widget#2.1" artifact should not be declared in the <classloader> declaration.
The above becomes possible *if* (a) the repository maintains a cache or extension ids and versions, (b) container classloader construction is moved to the repository code, (c) optional extension management that is currently handled in the classloader model is moved to the repository classloader builder implementation, and (d) packages actually declare specification versions.
Taking the approach of declaring specific artifacts as in the service definition is IMO the wrong approach because this ties the block definition to a particular artifact (e.g. "apache/widget#2.1") when for example the actual artifact in a parent classloader could be "apache/widget#2.1.2".
WDYT?
Cheers, Stephen.
Cameron Fieber wrote:
I was thinking about a new feature to partition the classpath into public and private (or api and impl) sections in the block.xml. This would allow a block.xml that is exporting one or more services to
define
the jars for its service's APIs in a public section of the classpath. Then, if that block.xml or jar was included in a higher level
container,
that container would include the public section of the included
block's
classpath in it's classpath.
This would ensure is that the classes for a service API would be
defined
in the correct classloader so that any client of that service would be able to access it without running into classloader grief.
A potential complication could arise if a container includes a block, then exports services from that included block. I haven't fully
thought
through how that would work, but it doesn't seem too bad to solve.
My main motivation is to allow me to define groups of components in jars, and be able to include them into higher level containers without (preferably) having to modify the classpath of that higher level container.
Any thoughts or opinions? I'll try to take a stab at an
implementation
this weekend to flesh out my example a bit better.
Example: A FooService is specified in the block.xml included in foo-impl-1.0.jar. FooService's interface is defined in
foo-api-1.0.jar,
and it uses a data object defined in foo-bean-1.0.jar. Since these
are
defined in the api section of the block's classpath, when the block is included in the the root container, those artifacts are promoted to
the
root container's classpath.
root-block.xml: <container name="root">
<classpath> <impl> <repository> <resource id="bar:foouser-impl" version="1.0"/> <!-- ... --> </repository> </impl> </classpath>
<include name="fooService" id="bar:foo-impl" version="1.0"/>
<component name="fooUser" class="com.bar.foouser.impl.FooUserImpl"/>
</container>
nested-block.xml: <container name="nested"> <services> <service type="com.bar.foo.FooService"> <source>fooService</source> </service> </services>
<classloader> <api> <repository> <resource id="bar:foo-api" version="1.0"/> <resource id="bar:foo-bean" version="1.0"/> </repository> </api> <impl> <repository> <resource id="bar:foo-impl" version="1.0"/> <!-- ... --> </repository> </impl> </classloader>
<component name="fooService"
class="com.bar.foo.impl.FooServiceImpl"/>
</container>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
--
|---------------------------------------| | Magic by Merlin | | Production by Avalon | | | | http://avalon.apache.org | |---------------------------------------|
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
