You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tuscany.apache.org by Mike Edwards <mi...@gmail.com> on 2008/12/18 16:12:32 UTC

[2.0] Getting Web Services binding running - some entertainment

Folks,

After rather more work than I would have hoped for, I have finally got Web Services running on the 
2.0 codebase.

There are interesting challenges, some of which have solutions which are not (yet) in a form which 
can be adopted generally in the codebase.  I'll try to describe them here, step by step.

Most of the challenges turn out to be classloading issues - unsurprising given the move to OSGi in 
2.0.  Some of the problems are a bit thorny and some of them involve the handling of 3rd party code.

1) XML Parsing

Parts of the codebase involve the use of XML Parsing, which may either be DOM parsing or SAX 
parsing.  It turns out that some of our code depends explicitly on the Xerces DOM parser 
implementation and some depends on the Woodstox SAX parser implementation.

This turns out to be complex, especially on Java 1.6.0.  The basic problem is that there is an API 
layer for each type of parser, which in turn loads the parser implementation code.  The API layer 
discovers the available parser implementations through Factory declarations in the JAR 
/META-INF/services directory.

So far so good, except that in JDK 1.6.0 BOTH of the API layers (for DOM Parsing and for SAX 
parsing) are actually in the base JDK itself.  When this happens, the API layer and the Parser 
implementation unfortunately end up in different OSGi bundles - the Core bundle and the Equinox 
library bundle (in practice).  And so, when the API layer finds and tries to load the Parser code - 
the Parser class is not found as it is not marked as a dependency of the API code.

I used two alternative strategies to solve this.
For Xerces, I found only one dependency on this in binding-ws-axis2 - and I removed it.  These days, 
XML DOM Parsing is present in the core JDK and there is no need to specify some other parser package.
For Woodstox, there are a number of our modules depending on this and instead of trying to eliminate 
this, I used the technique of putting the wstx-asl-3.2.4.jar into the jre\lib\endorsed directory of 
my JDK1.6.0 installation.  This then treats the Woodstok Parser as an extension of the Core - and in 
OSGi terms puts the Parser code into the same bundle as the rest of Core.

2) Incorrect labelling of OSGi Dependencies

There were a number of Manifest files that stated a dependence on javax.xml.namespace with 
version="1.0.0".  I have no idea where this version number came from - but it is not good.  This 
package is in Core in both JDK 1.5.x and JDK 1.6.0 and it is *NOT* at 1.0.0 level.

Simply removing the version number entirely solves this problem.

3) Cross-Bundle Class Loading Problems

It turns out that some of the 3rd Party libraries that we use involve code that loads classes from 
outside the library, but where there is no explicit dependency of the 3rd party code on the code 
package(s) from which the classes are loaded.  Typically, this involves 3rd party code that supplies 
library extension APIs where the NAME of an extensio class belonging to the CALLER is passed in 
through the API, but the classes are instantiated by the code within the API layer.

There are 2 main cases of this:

1) Axis2 - the axis2-kernel-1.4.1 module.  This has an API which is used to load a class from our 
binding-ws-axis2 module.
2) Axiom - the axiom-api module loads classes from the axiom-dom and from the axiomn-impl modules

In both these cases, there is no explicit dependency of the loading module on the module from which 
the class(es) are loaded - and in reality, neither should there be, since the other module is in a 
sense a "user" of the loading module.

I decided that the way to fix this was to patch the MANIFEST files of the bundles concerned to use 
the Eclipse Buddy technology.  This means that:

a) The bundle doing the loading of these "foreign" classes is marked with
"Eclipse-BuddyPolicy: dependent"
- which says that the module has some "buddy" modules from which some classes will be loaded

b) The bundle(s) providing the loaded classes are marked with:
"Eclipse-RegisterBuddy: xxxxxxxxxxx"
- where xxxxxxxxxxxx is the symbolic name of the bundle from a) - and this indicates that this
bundle provides classes to the first bundle.

One problem with this approach is that it only works for Equinox and I don't think it is available 
for other OSGi implementations such as Felix.

We need to think harder about this problem, but something like the BuddyPolicy solution is needed - 
and we need to coax the 3rd Party providers to add this to their bundle manifests.



Yours,  Mike.



Re: [2.0] Getting Web Services binding running - some entertainment

Posted by Simon Laws <si...@googlemail.com>.
On Wed, Jan 28, 2009 at 12:59 AM, Raymond Feng <en...@gmail.com> wrote:

>  Hi,
>
> I managed to bring up the binding-ws-calculator sample with the following
> changes:
>
> 1) Make binding-ws-axis2 a fragment to axis2-kernel to work around the
> MessageReceiver classloading issue from axis2
> 2) Make databinding-axiom a fragment to axiom-api to work around the
> SOAP11Factory classloading issue from axiom
> 3) Change the osgi.contextClassLoaderParent to "app" to work around the
> DataTypeFactory classloading issue inside Eclipse
> 4) Change the sample to fork a client thread to do the calculation instead
> of the "init" method. The init() can be called when the web service is not
> ready and it will cause deadlock.
>
> It's not ideal but it seems to be a good step.
>
> Thanks,
> Raymond
>
>  *From:* Simon Laws <si...@googlemail.com>
> *Sent:* Tuesday, January 27, 2009 9:08 AM
> *To:* dev@tuscany.apache.org
> *Subject:* Re: [2.0] Getting Web Services binding running - some
> entertainment
>
>  snip.....
>
>>
>>
>>> 3) Cross-Bundle Class Loading Problems
>>>
>>> It turns out that some of the 3rd Party libraries that we use involve
>>> code that loads classes from outside the library, but where there is no
>>> explicit dependency of the 3rd party code on the code package(s) from which
>>> the classes are loaded.  Typically, this involves 3rd party code that
>>> supplies library extension APIs where the NAME of an extensio class
>>> belonging to the CALLER is passed in through the API, but the classes are
>>> instantiated by the code within the API layer.
>>>
>>> There are 2 main cases of this:
>>>
>>> 1) Axis2 - the axis2-kernel-1.4.1 module.  This has an API which is used
>>> to load a class from our binding-ws-axis2 module.
>>> 2) Axiom - the axiom-api module loads classes from the axiom-dom and from
>>> the axiomn-impl modules
>>>
>>> In both these cases, there is no explicit dependency of the loading
>>> module on the module from which the class(es) are loaded - and in reality,
>>> neither should there be, since the other module is in a sense a "user" of
>>> the loading module.
>>>
>>> I decided that the way to fix this was to patch the MANIFEST files of the
>>> bundles concerned to use the Eclipse Buddy technology.  This means that:
>>>
>>> a) The bundle doing the loading of these "foreign" classes is marked with
>>> "Eclipse-BuddyPolicy: dependent"
>>> - which says that the module has some "buddy" modules from which some
>>> classes will be loaded
>>>
>>> b) The bundle(s) providing the loaded classes are marked with:
>>> "Eclipse-RegisterBuddy: xxxxxxxxxxx"
>>> - where xxxxxxxxxxxx is the symbolic name of the bundle from a) - and
>>> this indicates that this
>>> bundle provides classes to the first bundle.
>>>
>>> One problem with this approach is that it only works for Equinox and I
>>> don't think it is available for other OSGi implementations such as Felix.
>>>
>>> We need to think harder about this problem, but something like the
>>> BuddyPolicy solution is needed - and we need to coax the 3rd Party providers
>>> to add this to their bundle manifests.
>>>
>>>
>> It's a bit tricky if the 3rd part library is partially-baked OSGi bundle.
>> If it is a plain jar, we export/import all the packages for the wrapping
>> bundle and they can load all the publicly-exported packages. I see a few
>> options to fix the 3rd party bundle issues:
>>
>> 1) Report the issue back to the owning project and get it fixed at the
>> root
>> 2) Treat them as non-OSGi bundle and use our folder-based bundle packaging
>> technique to change the MANIFEST.MF
>> 3) Add a fragment bundle to the 3rd-party bundle to patch the MANIFEST.MF
>>
>>
>>>
>>> Yours,  Mike.
>>>
>>>
>>>
>>>
> 1) is the right answer but I suspect it will not move us forward very
> quickly
>     As I understand it the axiom problem looks like a bug in the axiom
> bundle so we should just raise a JIRA
>    The axis configuration is a bit more problematic. In this case axis is
> trying to create an instance of a class that belongs to Tuscany. Axis should
> support a different interface for providing configuration information, e.g.
> pass in an object rather than a classname
>
> 2) This sounds like the easiest tactical fix but I;m not sure it works for
> the Axis config problem as Axis needs access to a Tuscany class. How are the
> imports defined in the wrapper bundle?
>
> 3) More complicated but this may have to be the tactical solution if 2)
> isn't sufficient.
>
> What we could do with is some configurable processing that allows us to
> override the code that detects whether a jar is a bundle or not.
>
> Simon
>

Good work Raymond. I just ran binding-ws-calculator in Eclipse and it works
for me with the latest code. I think 1, 2 and 3 are reasonable tactical
changes. 4 is a bit more problematic. Two points.

- one does the spec say/imply that we should be able to use references from
@init methods regardless of binding type. It's interesting that this works
for binding.sca
- we should do something else rather than forking here. Just rely on service
exposed through SCA and use non-sca clients? I'll make some changes and get
feedback.

Simon

Re: [2.0] Getting Web Services binding running - some entertainment

Posted by Raymond Feng <en...@gmail.com>.
Hi,

I managed to bring up the binding-ws-calculator sample with the following changes:

1) Make binding-ws-axis2 a fragment to axis2-kernel to work around the MessageReceiver classloading issue from axis2
2) Make databinding-axiom a fragment to axiom-api to work around the SOAP11Factory classloading issue from axiom
3) Change the osgi.contextClassLoaderParent to "app" to work around the DataTypeFactory classloading issue inside Eclipse
4) Change the sample to fork a client thread to do the calculation instead of the "init" method. The init() can be called when the web service is not ready and it will cause deadlock.

It's not ideal but it seems to be a good step.

Thanks,
Raymond


From: Simon Laws 
Sent: Tuesday, January 27, 2009 9:08 AM
To: dev@tuscany.apache.org 
Subject: Re: [2.0] Getting Web Services binding running - some entertainment


snip..... 




    3) Cross-Bundle Class Loading Problems

    It turns out that some of the 3rd Party libraries that we use involve code that loads classes from outside the library, but where there is no explicit dependency of the 3rd party code on the code package(s) from which the classes are loaded.  Typically, this involves 3rd party code that supplies library extension APIs where the NAME of an extensio class belonging to the CALLER is passed in through the API, but the classes are instantiated by the code within the API layer.

    There are 2 main cases of this:

    1) Axis2 - the axis2-kernel-1.4.1 module.  This has an API which is used to load a class from our binding-ws-axis2 module.
    2) Axiom - the axiom-api module loads classes from the axiom-dom and from the axiomn-impl modules

    In both these cases, there is no explicit dependency of the loading module on the module from which the class(es) are loaded - and in reality, neither should there be, since the other module is in a sense a "user" of the loading module.

    I decided that the way to fix this was to patch the MANIFEST files of the bundles concerned to use the Eclipse Buddy technology.  This means that:

    a) The bundle doing the loading of these "foreign" classes is marked with
    "Eclipse-BuddyPolicy: dependent"
    - which says that the module has some "buddy" modules from which some classes will be loaded

    b) The bundle(s) providing the loaded classes are marked with:
    "Eclipse-RegisterBuddy: xxxxxxxxxxx"
    - where xxxxxxxxxxxx is the symbolic name of the bundle from a) - and this indicates that this
    bundle provides classes to the first bundle.

    One problem with this approach is that it only works for Equinox and I don't think it is available for other OSGi implementations such as Felix.

    We need to think harder about this problem, but something like the BuddyPolicy solution is needed - and we need to coax the 3rd Party providers to add this to their bundle manifests.




  It's a bit tricky if the 3rd part library is partially-baked OSGi bundle. If it is a plain jar, we export/import all the packages for the wrapping bundle and they can load all the publicly-exported packages. I see a few options to fix the 3rd party bundle issues:

  1) Report the issue back to the owning project and get it fixed at the root
  2) Treat them as non-OSGi bundle and use our folder-based bundle packaging technique to change the MANIFEST.MF
  3) Add a fragment bundle to the 3rd-party bundle to patch the MANIFEST.MF




    Yours,  Mike.





1) is the right answer but I suspect it will not move us forward very quickly
    As I understand it the axiom problem looks like a bug in the axiom bundle so we should just raise a JIRA
   The axis configuration is a bit more problematic. In this case axis is trying to create an instance of a class that belongs to Tuscany. Axis should support a different interface for providing configuration information, e.g. pass in an object rather than a classname

2) This sounds like the easiest tactical fix but I;m not sure it works for the Axis config problem as Axis needs access to a Tuscany class. How are the imports defined in the wrapper bundle?

3) More complicated but this may have to be the tactical solution if 2) isn't sufficient. 

What we could do with is some configurable processing that allows us to override the code that detects whether a jar is a bundle or not. 

Simon

Re: [2.0] Getting Web Services binding running - some entertainment

Posted by Simon Laws <si...@googlemail.com>.
snip.....

>
>
>> 3) Cross-Bundle Class Loading Problems
>>
>> It turns out that some of the 3rd Party libraries that we use involve code
>> that loads classes from outside the library, but where there is no explicit
>> dependency of the 3rd party code on the code package(s) from which the
>> classes are loaded.  Typically, this involves 3rd party code that supplies
>> library extension APIs where the NAME of an extensio class belonging to the
>> CALLER is passed in through the API, but the classes are instantiated by the
>> code within the API layer.
>>
>> There are 2 main cases of this:
>>
>> 1) Axis2 - the axis2-kernel-1.4.1 module.  This has an API which is used
>> to load a class from our binding-ws-axis2 module.
>> 2) Axiom - the axiom-api module loads classes from the axiom-dom and from
>> the axiomn-impl modules
>>
>> In both these cases, there is no explicit dependency of the loading module
>> on the module from which the class(es) are loaded - and in reality, neither
>> should there be, since the other module is in a sense a "user" of the
>> loading module.
>>
>> I decided that the way to fix this was to patch the MANIFEST files of the
>> bundles concerned to use the Eclipse Buddy technology.  This means that:
>>
>> a) The bundle doing the loading of these "foreign" classes is marked with
>> "Eclipse-BuddyPolicy: dependent"
>> - which says that the module has some "buddy" modules from which some
>> classes will be loaded
>>
>> b) The bundle(s) providing the loaded classes are marked with:
>> "Eclipse-RegisterBuddy: xxxxxxxxxxx"
>> - where xxxxxxxxxxxx is the symbolic name of the bundle from a) - and this
>> indicates that this
>> bundle provides classes to the first bundle.
>>
>> One problem with this approach is that it only works for Equinox and I
>> don't think it is available for other OSGi implementations such as Felix.
>>
>> We need to think harder about this problem, but something like the
>> BuddyPolicy solution is needed - and we need to coax the 3rd Party providers
>> to add this to their bundle manifests.
>>
>>
> It's a bit tricky if the 3rd part library is partially-baked OSGi bundle.
> If it is a plain jar, we export/import all the packages for the wrapping
> bundle and they can load all the publicly-exported packages. I see a few
> options to fix the 3rd party bundle issues:
>
> 1) Report the issue back to the owning project and get it fixed at the root
> 2) Treat them as non-OSGi bundle and use our folder-based bundle packaging
> technique to change the MANIFEST.MF
> 3) Add a fragment bundle to the 3rd-party bundle to patch the MANIFEST.MF
>
>
>>
>> Yours,  Mike.
>>
>>
>>
>>
1) is the right answer but I suspect it will not move us forward very
quickly
    As I understand it the axiom problem looks like a bug in the axiom
bundle so we should just raise a JIRA
   The axis configuration is a bit more problematic. In this case axis is
trying to create an instance of a class that belongs to Tuscany. Axis should
support a different interface for providing configuration information, e.g.
pass in an object rather than a classname

2) This sounds like the easiest tactical fix but I;m not sure it works for
the Axis config problem as Axis needs access to a Tuscany class. How are the
imports defined in the wrapper bundle?

3) More complicated but this may have to be the tactical solution if 2)
isn't sufficient.

What we could do with is some configurable processing that allows us to
override the code that detects whether a jar is a bundle or not.

Simon

Re: [2.0] Getting Web Services binding running - some entertainment

Posted by Raymond Feng <en...@gmail.com>.
Hi, Mike.

Thank you for sharing your experience to bring up the binding.ws with OSGi. 
Please see my comments below.

Raymond
--------------------------------------------------
From: "Mike Edwards" <mi...@gmail.com>
Sent: Thursday, December 18, 2008 7:12 AM
To: <de...@tuscany.apache.org>
Subject: [2.0] Getting Web Services binding running - some entertainment

> Folks,
>
> After rather more work than I would have hoped for, I have finally got Web 
> Services running on the 2.0 codebase.
>
> There are interesting challenges, some of which have solutions which are 
> not (yet) in a form which can be adopted generally in the codebase.  I'll 
> try to describe them here, step by step.
>
> Most of the challenges turn out to be classloading issues - unsurprising 
> given the move to OSGi in 2.0.  Some of the problems are a bit thorny and 
> some of them involve the handling of 3rd party code.
>
> 1) XML Parsing
>
> Parts of the codebase involve the use of XML Parsing, which may either be 
> DOM parsing or SAX parsing.  It turns out that some of our code depends 
> explicitly on the Xerces DOM parser implementation and some depends on the 
> Woodstox SAX parser implementation.
>
> This turns out to be complex, especially on Java 1.6.0.  The basic problem 
> is that there is an API layer for each type of parser, which in turn loads 
> the parser implementation code.  The API layer discovers the available 
> parser implementations through Factory declarations in the JAR 
> /META-INF/services directory.
>
> So far so good, except that in JDK 1.6.0 BOTH of the API layers (for DOM 
> Parsing and for SAX parsing) are actually in the base JDK itself.  When 
> this happens, the API layer and the Parser implementation unfortunately 
> end up in different OSGi bundles - the Core bundle and the Equinox library 
> bundle (in practice).  And so, when the API layer finds and tries to load 
> the Parser code - the Parser class is not found as it is not marked as a 
> dependency of the API code.
>
> I used two alternative strategies to solve this.
> For Xerces, I found only one dependency on this in binding-ws-axis2 - and 
> I removed it.  These days, XML DOM Parsing is present in the core JDK and 
> there is no need to specify some other parser package.
> For Woodstox, there are a number of our modules depending on this and 
> instead of trying to eliminate this, I used the technique of putting the 
> wstx-asl-3.2.4.jar into the jre\lib\endorsed directory of my JDK1.6.0 
> installation.  This then treats the Woodstok Parser as an extension of the 
> Core - and in OSGi terms puts the Parser code into the same bundle as the 
> rest of Core.

This is related to the popular jar service provider pattern. Quite a few JDK 
classes use this technique to discover concrete service providers (see 
http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html#Service%20Provider). 
Unfortunately, its classloading scheme is not OSGi-friendly because it 
depends on the thread context classloader and system classloader.

In your particular case, I think there is a caveat in the following JDK 
FactoryFinder classes (I think they copy it around :-():

javax.xml.parsers.FactoryFinder.class
javax.xml.stream.FactoryFinder.class

If a class is loaded by the JDK, the classloader is null. In this case, the 
FactoryFinder uses the system classloader (which typically is the 
application classloader based on the classpath settings) to search for 
META-INF/services/<spi class name> resources. But then it uses the thread 
context classloader (TCCL) to load the spi implementation class by name. If 
the system classloader is not the same as the TCCL, then TCCL might be able 
to find the classes available from the system classloader.

>
> 2) Incorrect labelling of OSGi Dependencies
>
> There were a number of Manifest files that stated a dependence on 
> javax.xml.namespace with version="1.0.0".  I have no idea where this 
> version number came from - but it is not good.  This package is in Core in 
> both JDK 1.5.x and JDK 1.6.0 and it is *NOT* at 1.0.0 level.
>
> Simply removing the version number entirely solves this problem.

The version is picked up by the Apache Felix Maven Bundle Plugin if there is 
a bundle that exports such a package. Our MANIFEST.MFs were initially 
generated from the plugin. In JDK 1.5, some of the packages are not part of 
the JDK and they are not treated as OSGi system packages.

Removing the version number makes sense.

>
> 3) Cross-Bundle Class Loading Problems
>
> It turns out that some of the 3rd Party libraries that we use involve code 
> that loads classes from outside the library, but where there is no 
> explicit dependency of the 3rd party code on the code package(s) from 
> which the classes are loaded.  Typically, this involves 3rd party code 
> that supplies library extension APIs where the NAME of an extensio class 
> belonging to the CALLER is passed in through the API, but the classes are 
> instantiated by the code within the API layer.
>
> There are 2 main cases of this:
>
> 1) Axis2 - the axis2-kernel-1.4.1 module.  This has an API which is used 
> to load a class from our binding-ws-axis2 module.
> 2) Axiom - the axiom-api module loads classes from the axiom-dom and from 
> the axiomn-impl modules
>
> In both these cases, there is no explicit dependency of the loading module 
> on the module from which the class(es) are loaded - and in reality, 
> neither should there be, since the other module is in a sense a "user" of 
> the loading module.
>
> I decided that the way to fix this was to patch the MANIFEST files of the 
> bundles concerned to use the Eclipse Buddy technology.  This means that:
>
> a) The bundle doing the loading of these "foreign" classes is marked with
> "Eclipse-BuddyPolicy: dependent"
> - which says that the module has some "buddy" modules from which some 
> classes will be loaded
>
> b) The bundle(s) providing the loaded classes are marked with:
> "Eclipse-RegisterBuddy: xxxxxxxxxxx"
> - where xxxxxxxxxxxx is the symbolic name of the bundle from a) - and this 
> indicates that this
> bundle provides classes to the first bundle.
>
> One problem with this approach is that it only works for Equinox and I 
> don't think it is available for other OSGi implementations such as Felix.
>
> We need to think harder about this problem, but something like the 
> BuddyPolicy solution is needed - and we need to coax the 3rd Party 
> providers to add this to their bundle manifests.
>

It's a bit tricky if the 3rd part library is partially-baked OSGi bundle. If 
it is a plain jar, we export/import all the packages for the wrapping bundle 
and they can load all the publicly-exported packages. I see a few options to 
fix the 3rd party bundle issues:

1) Report the issue back to the owning project and get it fixed at the root
2) Treat them as non-OSGi bundle and use our folder-based bundle packaging 
technique to change the MANIFEST.MF
3) Add a fragment bundle to the 3rd-party bundle to patch the MANIFEST.MF

>
>
> Yours,  Mike.
>
>
>