It's actually even more complex than the situation that you outline as we need to deal with a hierarchy of classloaders on both the application and runtime sides. In general, we also will not have the ability to control what gets added to the host environment's classloaders that are the parent to all of these.

The way we have it structured right now we have two fairly simple trees with a common root.

The root is the "host" classloader supplied by the host environment.

In the standalone case, it's the system classloader created to run launcher.jar. The classpath for this is the JVM classes + launcher.jar + the contents of its manifest classpath. This one contains classes that we expect to be shared between the application and the runtime such as the SCA API and the Tuscany proprietary API (but not implementations).

In the webapp case, the host classloader is the web application one supplied by the web container. This is explicitly the thread context classloader in place when the runtime is initialized, which by J2EE rules is the one used to load the webapp (including the contents of WEB-INF/classes and WEB-INF/lib/*).

To boot the Tuscany runtime we need the classes that implement it. This is done by creating a classloader that is a child of the host one and which contains the "boot" classes loaded from the "boot" directory. These are the embedded core classes such as -spi and -core.

We boot the system composite ("tuscany.system") as a composite under that classloader. As a composite it has its own classloader whose parent classloader is the classloader of the parent composite. This allows us to support composites that are packaged in a way that they contribute Java resources e.g. a composite packaged as a jar file. We also allow a composite to extend the classpath of that classloader through <dependency> elements in its scdl.

The extension deployers are components that are part of the "tuscany.system" composite that add additional children to it (the extensions). Each child is a component implemented by a composite and as such gets another child classloader.

On the application side, we deploy the "default" application component as a composite on the application side of the component tree. As a composite it also has its own classloader, one whose classpath is that of the application.

For the webapp host, the default application is contained in the host environment (e.g. it contains JSPs, Servlets et al that are part of the webapp). The default composite has a classloader that is a child of the webapp one so has a classpath that is all the application code + any <dependency>'s specified in the composite scdl.

In this way we get the isolation we need between the application code and the runtime implementation.

Where this bites is when there are resources (classes) that need to be shared between the application programming model and the implementation. The way in which that happens depends on the nature of the sharing.

At one level, the easy solution is to introduce those classes into the host classloader so that they are shared between the application side and the runtime side. This is what we do with the SCA API classes, and what a user can do in the webapp host by adding the classes to the webapp classloader (e.g. by putting them in WEB-INF/ classes or a jar in WEB-INF/lib). There are no problems with this if the runtime code loads classes correctly (using the appropriate classloader which is most probably not the TCCL).

A more complex case is where a composite at some arbitrary depth down the application tree wants to share a class with a system component (such as an extension) that is at some other arbitrary depth down the runtime tree. We have two solutions on the table for this:

1) we can support ordinary jars by adding multi-parent support to the composite classloader. This would work in conjunction with the XML dependency mechanism by allowing the dependency to be loaded in an isolated classloader which would then be one parent of the runtime component and one parent of the application component. The extension would determine which resources it wanted to share with the application and which it would want to keep priviate; for example, the AXIOM databinding might choose to share axiom-api but would keep the impl private.

2) we can support OSGi bundles using the import/export semantics of the OSGi classloader. This would require users and extension providers to package their composites as OSGi bundles.

IMO we need to do both - although OSGi is very flexible it brings quite a bit of baggage with it which users may not want to opt in to. Although more and more resources are making things available as OSGi bundles not everything does. We also need to support legacy applications/libraries that do not have the metadata that OSGi requires.

--
Jeremy

On Oct 5, 2006, at 7:34 AM, Ken Tam wrote:

On 10/5/06, ant elder <[EMAIL PROTECTED]> wrote:
I agree its not clear how all this is supposed to work, Venkat and I have
also both just being struggling with it.

To be complete, adding to your (a) and (b) in (3) there's also a (c) where both the extension and application logic may share a dependency. Examples of this are js.jar for the JavaScript extension, or AXIOM if an application is
using OMElements and the Axis2 WS binding.

I think your (c) is the same as my (a) ?

> a) deps which need to be surfaced to application logic, and thus
> shouldn't be in the same isolating classloader as the extension
> itself.

Is there a statement somewhere (wiki, mail, comments, anything other
than code) about the classloader architecture?  Here's a simple
statement based on my understanding:

For any given hosting environment, there are 2 important "root" classloaders
a) an app-visible one (i.e. where the OSOA API jar goes, where users
might put their own code and libraries they use).  This is typically
defined by the host environment -- for example, in a servlet container
it would be the classloader that sees (WEB-INF/classes &&
WEB-INF/lib).
b) a Tuscany runtime one (i.e. where the Tuscany core jars go).  Given
that extension classloaders have this one as an ancestor, it seems
like this one must have the app-visible one as an ancestor.


Could you give an example for what you mean by "simplifying it by being more
explicit"?

I think we'd need to formalize the concept of the 2 classloader
"roots" I just described, and then expose to users the idea of
specifying explicitly where each dependency of an extension ought to
go.  Transitively, if some dependency gets "pulled up" into the
app-visible classloader, then that overrides any other reference to
that dependency that places it in the Tuscany runtime one.  So.. let's
say the Spring extension uses the Spring framework jars, which in turn
use foobar.  The extension's dep on the Spring framework jars would
have to have metadata indicating that the dep should be resolved into
an app visible classloader.  Because of that, foobar is also resolved
into the app visible classloader, regardless of what some other
extension that might depend on foo might say.




   ...ant

On 10/5/06, Ken Tam <[EMAIL PROTECTED]> wrote:
>
> While working with Andy on fixing some of the Spring samples, and
> taking a look at the way the war plugin has replaced the web distro, I
> ran into a number of issues relating to extensions and their
> dependencies.
>
> 1) It's not obvious how someone building a webapp sample expresses
> their requirement for a particular extension. Given the maven focus > of our current infrastructure, the current way it seems this is done
> is to just include the extension artifact as a <dependency> entry.
> Does anyone have a better proposal? I think some metadata might help
> here -- see the next point.
>
> 2) The war plugin doesn't understand extensions. Right now, anything
> that's a <dependency> by default gets put into WEB-INF/lib, and it
> might get moved into WEB-INF/tuscany/boot if the plugin determines it
> only be a transitive dep of the webapp-host.  This is totally
> disconnected from the webapp extension loading mechanism, which
> requires something to be present in WEB-INF/tuscany/extensions. So it
> seems the war plugin could benefit from understanding what
> dependencies are actually extensions, so it could populate it in the
> right place.  I would expect the standalone case to be similar (ie,
> the sample build would also need to figure out to put it in the
> extension directory where the DirScanExtender looks).  I'm thinking
> about adding metadata to the POM for extensions so that they can be
> identified as such, but haven't thought about how to do this yet..
>
> 3) Extensions are loaded into a classloader that isolates them from
> the application logic (the exact code in deployExtension() has FIXMEs > suggesting that while the exact classloader to be used is in flux, the
> principal of isolation is true).  Extensions often have their own
> dependencies, which I believe fall into 2 categories:
>
> a) deps which need to be surfaced to application logic, and thus
> shouldn't be in the same isolating classloader as the extension
> itself.
> b) deps that ought to be hidden from application logic, and can be in
> the same isolating classloader.
>
> Taking the Spring extension as an example, the Spring framework jars > themselves would be type A deps. Right now, there is no clear way to
> manage this -- for example, via maven the dep between the Spring
> extension and the Spring framework jars is "just another dependency"
> and so get treated just like any other jars.
>
> I'm starting to think that it may actually be counter-productive in
> the short term to attempt automation of all this -- dependency
> management in general tends to be a hard problem to automate anyways > (look how long it's taken maven to attack, and it's still nowhere near > perfect). The war plugin attempts to automagically figure out where
> all jars need to go, but as I think I've shown, there's a lot of
> missing metadata needed to do that right. What do folks think about > simplifying it by being more explicit, and then slowly moving back to
> a more automatic model?
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>



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



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

Reply via email to