Hi, Rajini.

Thank you for the detailed writeup. I copied your note into the following wiki page so we can capture the design points.

http://cwiki.apache.org/confluence/display/TUSCANYWIKI/Classloading+in+Tuscany+SCA+Java

I found it a bit difficult to reply in long e-mails so I decide to attack the problem from a slightly different angle.

A) What's the purpose of classloading scheme?
I think it's used to provide sharing and isolation of java classes.

B) What are the players?

1. SCA/Tuscany APIs (and potentially other APIs such as SDO)
2. Tuscany runtime code
3. Tuscany extension code
4. 3rd party code that Tuscany runtime/extension depends on
5. Application code from SCA contributions

3) What's desired visibility?

5 --> imported java classes by the owning contribution
  --> 1

2 --> 1
  --> 4

3 --> 2 (SPI portion)
  --> 1
  --> 4
  --> potentially other extensions

I created a graph at http://cwiki.apache.org/confluence/download/attachments/68801/classloader-dependencies.png as the starting point. Once we have the relationship flushed out, we could then apply techniques such as OSGi or multi-parent classloaders, or a combination to enforce the loading scheme.

Raymond

----- Original Message ----- From: "Rajini Sivaram" <[EMAIL PROTECTED]>
To: <tuscany-dev@ws.apache.org>
Sent: Monday, October 15, 2007 12:52 AM
Subject: Re: Classloading in Tuscany


Mike,

There are two sets of classloading in Tuscany that we need to look at and
these can be handled independently of each other.
 1) Classloading architecture for SCA contributions
 2) Classloading architecture for SCA runtime modules

In both cases, there are two ways of improving modularity in Tuscany
 a) Use separate classloaders per module to provide isolation, using a
classloader architecture similar to OSGi, but without actually running in an
OSGi runtime.
 b) Use OSGi bundles to provide module isolation and versioning, where the
versioning support would rely on an OSGi runtime.


For both 1) and 2), we could support a) and/or b).

Tuscany already supports 1b), and the proposed fixes will support 1a).

Tuscany does not implement 2a) or 2b), and if done properly, the
implementation would required code changes that are pervasive across
Tuscany. So the question is - do we really want to run Tuscany modules as
separate OSGi bundles (or isolate modules using separate classloaders)?
IMHO, it is only worth the hassle, if Tuscany modules are properly versioned
and dynamically replaceable - ie, run as bundles in an OSGi runtime (2b).
The proposed fixes do not implement 2a) and provide a partial solution for
2b) based on OSGi manifest files to minimize code changes to Tuscany.


1) Classloading architecture for SCA contributions

At the moment, OSGi bundle contributions can be used in Tuscany which
provide modularity and versioning with the help of an OSGi runtime. Plain
Jar contributions or folders use a single classloader at the moment and the
proposed fixes will introduce contribution classloaders to isolate
contributions.

SCA contributions can specify dependencies in terms of import/export
statements in the same way as OSGi bundles. If you consider Java
contributions, SCA contribution dependencies are a subset of OSGi bundle
dependencies, because SCA does not support versioning or any of the other
attributes that can be associated with importing packages in OSGi. So SCA
contribution classloading will be a simpler version of OSGi bundle
classloading. The code for supporting SCA import/export is already in place in Tuscany- it just doesn't get used because the thread context classloader
is currently used to resolve classes.

2) Classloading architecture for SCA runtime modules

At the moment, Tuscany uses a single classloader for the runtime and its
dependencies, and even though Tuscany runtime architecture uses extensible
modules with reasonably well defined dependencies, module isolation is not
achieved because of the use of a single classloader. Tuscany also has
dependencies on many libraries which rely on the thread context classloader.


Even though we are looking at running Tuscany in an OSGi runtime to support
distributed-OSGi, at the moment we are still assuming that by default
Tuscany would be run without an OSGi runtime. Hence the proposed fixes aim
to minimize Tuscany changes required to implement 2b). Tuscany's use of
thread context classloader will be removed wherever possible, but the
requirement on thread context classloader will not be removed altogether
since it is used by libraries that Tuscany depends on.


There are two issues with modularizing Tuscany runtime using OSGi or
OSGi-style classloading. Thread context classloaders and OSGi dont go very
well together. And the extension module architecture used by Tuscany where a
core module is extended through the use of extension modules ends up in a
classloader hierarchy which is the reverse of what is required - the core
bundle does not have visibility of the classes from the extension bundles.

There is an OSGi RFP which addresses classloading enhancements for OSGi
including those required for applications relying on thread context
classloaders. Possible solutions to implement 2b) now include the use of
DynamicImport-Package, Eclipse buddy policy, Spring-OSGi Extender Model or
OSGi services.

If we want to implement 2a) and 2b) properly at some point, it might make
sense to provide a solution that uses a utility library to implement all
classloading (which can then do something different based on whether Tuscany is running inside an OSGi runtime or outside). But the changes required for
this will be pervasive across Tuscany code.


Thank you...

Regards,

Rajini

On 10/12/07, Mike Edwards <[EMAIL PROTECTED]> wrote:

Rajini,

Little though here:

- can this be done in a way that moves us closer to the OSGi handling of
classloading?

- so if ever we wanted an OSGi style runtime, it would be easier to
adapt what we have...


Yours,  Mike.

Rajini Sivaram wrote:
> Thank you, Ant. I will try to split the work into small pieces and
submit
> separate patches.
>
>
> Thank you...
>
> Regards,
>
> Rajini
> On 10/12/07, ant elder <[EMAIL PROTECTED]> wrote:
>> On 10/11/07, Rajini Sivaram <[EMAIL PROTECTED]> wrote:
>>> Hello,
>>>
>>> Tuscany's use of classloaders doesn't seem to be well-defined, even
>> though
>>> the concept of a runtime classLoader and contribution classloaders
>> should
>>> have made it easy to isolate these namespaces. All Tuscany samples >>> and
>>> tests
>>> are currently run with a single application classloader containing
>>> absolutely everything including Tuscany, all the jar files Tuscany
>>> requires
>>> and all the Java contribution jars/folders.
>>>
>>> I am running Tuscany as a bundle inside an OSGi runtime, and came
across
>>> some issues with classloading when multiple classloaders are used.
>>> Even though these can be fixed for OSGi without changes to the
non-OSGi
>>> related code in Tuscany, it will be good to fix these properly in
>> Tuscany
>>> since these issues affect anyone who wants to use Tuscany without a
>> great
>>> big classloader hierarchy containing Tuscany, all its dependencies >>> and
>> all
>>> contributions.
>>> Here is my understanding of classloaders used by Tuscany:
>>>
>>> 1) Tuscany Runtime classloader
>>> This is the classloader used to load Tuscany itself. It should be >>> able
>> to
>>> locate all Tuscany jar files and all its dependent jar files (eg.
>> axis2).
>>> There are many locations in Tuscany which explicitly read the
>>> classloader used to load one Tuscany class in order to load another
>>> Tuscany
>>> class. For example, many of the files defined in
META-INF/services  and
>>> the
>>> classes they refer to are loaded in this way.
>>>
>>> 2) Contribution classloaders
>>> Referred to as application classloader in the DefaultSCADomain, a
>> separate
>>> classloader can (in theory) be used to refer to the contributions - >>> in
>> the
>>> case of DefaultSCADomain, this is a single classloader associated >>> with
a
>>> single contribution.
>>>
>>> There is currently no concept of a contribution classloader for each
>>> contribution (except for OSGi contributions), and all resolution of
>>> classes
>>> from contributions is done using a single classloader. This does not
>>> reflect
>>> the SCA specification, which requires contribution imports/exports to
be
>>> explicitly specified - requiring multiple classloaders to enforce the
>>> import/export definition during class resolution.
>>>
>>> 3) Thread context classloader
>>> Tuscany sets thread context classloader only in one class -
>>> HotUpdatableSCADomain (which sets Context classloader to a single
>>> URLClassLoader containing all the contribution jar files, with the
>>> original
>>> context classloader as parent).
>>>
>>> Tuscany uses the thread context classloader in around 30 different
>>> locations. Around half of these have FIXMEs saying that the
classloader
>>> should be passed in. Many of these uses of the context classloader >>> are
>>> trying to obtain the runtime classloader. And at least one is trying
to
>>> obtain the contribution classloader.
>>>
>>> Many libraries which are used by Tuscany require the thread context
>>> classloader to be able to load the library classes. Most of these use
>> the
>>> factory pattern and dynamically load implementation classes to create
>>> instances using the context classloader (eg.
>>> javax.xml.datatype.DataTypeFactory.newInstance()). The context
>> classloader
>>> should in these cases to be able to find classes in Tuscany's
dependent
>>> jar
>>> files, and hence the classloader used to load these dependent jars
>> should
>>> be
>>> on the thread context classloader hierarchy.
>>>
>>> Axis2 libraries (and possibly others) use the thread context
classloader
>>> to
>>> load Tuscany classes. Axis2 needs to find Tuscany's message receivers
>>>
>>>
>>
org.apache.tuscany.sca.binding.ws.axis2.Axis2ServiceInOutSyncMessageReceiverand
>>> org.apache.tuscany.sca.binding.ws.axis2.Axis2ServiceInMessageReceiver,
>> and
>>> these are loaded by Axis2 using the  context classloader. So Tuscany
>>> runtimeClassloader should be on the thread context classloader
>> hierarchy.
>>> 4) Java Application classloader
>>> Tuscany doesn't directly rely on the application classloader (the
>>> classloader corresponding to CLASSPATH). But since Tuscany doesn't >>> set
>> the
>>> thread context classloader, for any application that doesn't
explicitly
>>> set
>>> thread context classloader, there is an indirect dependency on the
>>> application classloader, and hence CLASSPATH should contain >>> everything
>>> required by the thread context classloader (which at the moment
includes
>>> the
>>> entire world).
>>>
>>> So we have the following requirements on classloaders:
>>>
>>>
>>>    1. Tuscany runtime classloader should find Tuscany and all its
>>>    dependencies (essentially tuscany-sca-manifest.jar).
>>>    2. Contributions are not required to be on the classpath, nor do
they
>>>    have to be visible to the thread context classloader. One
classloader
>>> per
>>>    contribution is required to enforce SCA contribution import/export
>>>    semantics.
>>>    3. Thread context classloader should be able to see Tuscany's
>>>    dependencies and also Tuscany classes - so this can be the same as
>> (or
>>> a
>>>    child of) the Tuscany runtime classloader.
>>>    4. Any code using Tuscany should either have Tuscany runtime and
its
>>>    dependencies on the CLASSPATH, or should set the thread context
>>> classloader
>>> for its threads using Tuscany. All Tuscany tests rely on >>> CLASSPATH,
>>> while
>>>    Tuscany can be run inside OSGi without CLASSPATH, by setting the
>>> context
>>>    classloader.
>>>
>>>
>>> I would like to propose the following fixes to Tuscany classloading
(my
>>> aim
>>> is to implement neater isolation without too much impact on the >>> code):
>>>
>>> 1) Fix contribution classloading to enforce SCA contribution
>> specification
>>> by using one classloader per contribution. Remove the requirement for
>>> contributions to be present in the classpath - Tuscany runtime
>>> classloader,
>>> thread context classloader and the application classloader should not
be
>>> required to see the contribution classes.
>>>
>>> 2) Remove unnecessary usages of thread context classloader in Tuscany
>>> where
>>> the classloader that is required is the  Tuscany Runtime classloader.
It
>>> should be possible in many cases to determine the classloader >>> directly
>>> without having to pass classloaders around. This is already done in
some
>>> places, so this is just making the code consistent.
>>>
>>> 3) There are many uses of the thread context classloader where it is
not
>>> very clear which classloader is actually required. I would suggest
that
>> as
>>> far as possible, Tuscany should avoid using the thread context
>>> classloader,
>>> and in places where it cannot be avoided without major changes, the
code
>>> should be commented to show which classloader is required.
>>> As an example (the FIXME is from the existing code)
>>>
>>> *public JAXBElement<?> create(ElementInfo element,
TransformationContext
>>> context) {*
>>> *    .....*
>>> *    ClassLoader classLoader = context != null ?
context.getClassLoader
>> ()
>>> :
>>> null;*
>>> *    if (classLoader == null) {*
>>> *        //FIXME Understand why we need this, the classloader should
be
>>> passed in*
>>> *        classLoader = Thread.currentThread
().getContextClassLoader();*
>>> *    }*
>>> *    Class<?> factoryClass = Class.forName(factoryClassName, true,
>>> classLoader);*
>>> *    ....*
>>> *}*
>>>
>>> Given that Tuscany and its dependencies need to be visible from the
>> thread
>>> context classloader anyway because other libraries need them there,
this
>>> change is to merely to clean up Tuscany classloading and provide more
>>> clarity. It does not aim to remove the external dependencies on the
>> thread
>>> context classloader.
>>>
>>> 4) It will be good to ensure that all uses of the Tuscany runtime
>>> classloader (eg. to load META-INF/services) continue to work even if
>> each
>>> Tuscany module was loaded by a different classloader (ie, Tuscany
>> runtime
>>> classloader is a hierarchy of module classloaders rather than a >>> single
>>> one).
>>> This is not strictly necessary at the moment, but it is necessary if
we
>>> want
>>> to package Tuscany modules as separate OSGi bundles.
>>>
>>> 5) Document Tuscany's requirements on classloaders (CLASSPATH and
thread
>>> context classloader).
>>>
>>>
>>> I would appreciate your feedback, both regarding whether there is
better
>>> way
>>> to fix this, and on areas which I have missed out or
>>> misunderstood. I will be happy to provide a patch if this is an
>> acceptable
>>> solution.
>>>
>>>
>>>
>>>
>>> Thank you...
>>>
>>> Regards,
>>>
>>> Rajini
>>>
>> That all sounds good to me, i've also struggled with classloaders in
the
>> past, it is a bit hotchpotch at the moment so if you want to have a go
at
>> cleaning things up i think that would be wonderful.
>>
>> If you were to just submit one big patch that tries to fix it all in
one
>> go
>> that may get bogged down in discussion about approaches, so the >> smaller
>> bits
>> you can break this down into with a few smaller discrete patches thats
>> better. Don't worry to much if you can't though, one big patch is fine
if
>> thats what it takes.
>>
>>   ...ant
>>
>

---------------------------------------------------------------------
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