tuscany-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Millies, Sebastian" <Sebastian.Mill...@softwareag.com>
Subject RE: Get Contribution at runtime?
Date Thu, 29 Nov 2012 17:46:56 GMT
> -----Original Message-----
> From: Simon Nash [mailto:nash@apache.org]
> Sent: Thursday, November 29, 2012 4:55 PM
> To: user@tuscany.apache.org
> Subject: Re: Get Contribution at runtime?

[snip]

> I think you can put the META-INF/services directory anywhere on the system
> classpath.
>
>    Simon

I have solution of sorts, and will attempt to summarize it here, working in some of Simon's
comments as well.

To re-iterate the problem: I want to set up my contributions, so that they can use
different versions of third-party libraries than the Tuscany 1.6 runtime. My original example
was using recent versions of EMF, another example is using Tuscany with an Apache Solr
4.0 backend, which requires different Apache Http Components.

Some approaches have turned out to be infeasible:
1) patching the built-in ContributionClassLoader to use a parent-last strategy leads to several
errors in Tuscany tests and samples. The fault may lie with the tests being based on wrong
assumptions
and bad-practices, but to correct them all is not a practical option. (Besides, it would be
contrary to the
OASIS specs.)
2) The approach outlined in [1] is quite complicated, and I have not been able to get it to
work.

Instead, I have chosen to exploit the Tuscany extension mechanism in order to provide a class
loader
of my choice as the contribution class loader. This solution will work when one follows the
recommended
best practice of keeping contribution classes separate from the system classpath. The new
class loader is
the delegation parent of the contribution class loader.

The approach has two limitations:
1) the contributions shouldn't pass any references to these overriding external libraries
to the Tuscany
runtime (e. g. in the form of service parameters)
2) the extension mechanism is a applied globally rather than to specific contributions.

(Both these points do not worry me. With regard to the second one, the overriding classes
could be
included in a nested jar in the contribution itself, so even if the mechanism is global, any
overriding
could be kept strictly local, if desired. After all, it's my own class loader doing the work.)

Finally, here's how it really works, without requiring any code changes in Tuscany itself.

1) Define a class loader, e. g. EndorsedLibsClassLoader extends URLClassLoader

2) Define a class loader provider, e. g. EndorsedLibsClassLoaderProvider implements ContributionClassLoaderProvider.
This is the core of the solution. We inject the new class loader between the standard contribution
class loader and
the app class loader:
    public ClassLoader getClassLoader( Contribution contribution, ClassLoader parent )
    {
        EndorsedLibsClassLoader endorsedLoader = new EndorsedLibsClassLoader( parent );
        return new ContributionClassLoader( contribution, endorsedLoader );
    }

3) Define a class loader provider extension point, e. g.
PrioritizedContributionClassLoaderProviderExtensionPoint implements ContributionClassloaderProviderExtensionPoint

The reason for this is that Tuscany will look up ALL class loader providers, not just your
own, then put them in
a HashSet, iterate over the set, and keep one provider per contribution type, whichever one
it happens to find
last (clearly a bug, in my view). The PrioritizedContributionClassLoaderProviderExtensionPoint
allows
class loader providers to have a "priority" attribute, and keeps the one with the highest
priority.

4) Register the provider and the provider extension point in two files in a META-INF/services
directory. The file names
are:
org.apache.tuscany.sca.contribution.java.ContributionClassLoaderProvider
org.apache.tuscany.sca.contribution.java.ContributionClassloaderProviderExtensionPoint

The latter just contains the FQCN of the extension point implementation. The former contains
the FQCN of the class
loader provider, along with its attributes, e. g. like this:
example.contribution.java.EndorsedLibsClassLoaderProvider;type=application/x-compressed,priority=10

5) Put the META-INF directory on the system classpath. But not just anywhere: It must come
BEFORE the Tuscany
runtime, because the tuscany-sca-all.jar will contain an analogous directory, and the extension
point is loaded
only once, from the first text file with appropriate name that is found.

This is really quite simple, after all. It may not be the best of all possible solutions,
but it works for me.

-- Sebastian

PS: I'd like to share some example code (99,9% is original Tuscany code anyway...)
I have put the text of this mail plus a zip archive into the JIRA that has occasioned this
entire exchange:
https://issues.apache.org/jira/browse/TUSCANY-4073

[1] http://mail-archives.apache.org/mod_mbox/tuscany-user/201006.mbox/%3C4C164DD3.8090405@apache.org%3E
[2] https://cwiki.apache.org/TUSCANYWIKI/classloading.html


IDS Scheer Consulting GmbH
Geschäftsführer/Managing Directors: Michael Rehm, Ivo Totev
Sitz/Registered office: Altenkesseler Straße 17, 66115 Saarbrücken, Germany - Registergericht/Commercial
register: Saarbrücken HRB 19681
http://www.ids-scheer-consulting.com

Mime
View raw message