[ 
https://issues.apache.org/jira/browse/CMIS-878?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14298034#comment-14298034
 ] 

Sascha Homeier edited comment on CMIS-878 at 1/30/15 1:38 AM:
--------------------------------------------------------------

After some research I like the suggestion of [~fmeschbe] in CMIS-324 most to 
use the OSGi extender model to get the Bundles which contain SPI 
implementations.
But instead of injecting the class loaders of these Bundles we also can consume 
the SPI implementations directly as real OSGI services.

For both options I can think of the following:

h4. *1) Get the ClassLoader from other OSGI Bundles*
Inside the Chemistry OpenCmis OSGI Client Wrapper the Activator needs to be 
adjusted to add a Bundle Listener which listens for Bundle changes (additional 
logic can be added to also iterate over already loaded bundles in case 
Chemistry Client Wrapper was started later then SPI Implementation Bundles).
If a bundle is in proper state (e.g. RESOLVED) we should be able to get the 
Bundle Classloader via BundleWiring:

{code:title=Activator.java|borderStyle=solid}
…
public void bundleChanged(BundleEvent event) {
        if (event.getType() == BundleEvent.RESOLVED) {
            BundleWiring bundleWiring = 
event.getBundle().adapt(BundleWiring.class);
            ClassLoader classLoader = bundleWiring.getClassLoader();
            // pass the class loader to ClassLoaderUtil
        }
}
…
{code}

This ClassLoader then can be passed to ClassLoaderUtil and when it tries to 
load a class it first uses current behaviour by trying to load the class from 
context class loader. If this failed it tries loading class by iterating over 
List of injected class loaders.
When Bundle gets uninstalled of course we need to unregister the class loader 
from ClassLoaderUtil. So we need two additional static methods 
{{registerClassLoader}} and {{unregisterClassLoader}} at ClassLoaderUtil.

We still need to define how to tag the Bundles which contain OpenCmis SPI 
implementations. For example it could be done by setting a Manifest header like
{{Chemistry-SPI}}.
In Activator we then can get the header via:
{code:title=Activator.java|borderStyle=solid}
...
        if (event.getType() == BundleEvent.RESOLVED) {
            String header = (String) 
event.getBundle().getHeaders().get("Chemistry-SPI");
            // if header is not null get the class loader via BundleWiring 
interface and pass it to ClassLoaderUtil
{code}

A better option may be to put a property.

h4. *2) Loading SPI Implementations from other OSGI Bundles*

As OpenCmis does not use java.util.ServiceLoader  I would prefer to provide SPI 
services as real OSGI services instead of specifying them in files 
META-INF/services/<FQCN_OF_SPI>.
The OSGI services then can be accessed in Activator of OpenCmis Client Wrapper. 
For example AuthenticationProvider can be retrieved via:
{code:title=Activator.java|borderStyle=solid}
public void start(BundleContext context) {
    ...
    ServiceReference<?> serviceReference = 
context.getServiceReference(org.apache.chemistry.opencmis.commons.spi.AuthenticationProvider.class.getName());
    AuthenticationProvider authProvider = (AuthenticationProvider) 
context.getService(serviceReference); 
    // pass authProvider to proper places in OpenCmis Client framework
}
{code}

This would make the Client library of OpenCmis much more OSGI compliant but is 
also the most intrusive option:
It requires to pass the SPI implementations to different locations in OpenCmis 
framework. For example AuthenticationProvider implementation could be passed to 
CmisBindingFactory while an own Cache implementation is needed in SessionImpl. 
When injecting ClassLoaders instead of explicit services we can pass them to a 
single location: ClassLoaderUtil.

I'm interested in what the OpenCmis developers think about these options?
Do you see other alternatives or improvements?


was (Author: shomeier):
After some research I like the suggestion of [~fmeschbe] in CMIS-324 most to 
use the OSGi extender model to get the Bundles which contain SPI 
implementations.
But instead of injecting the class loaders of these Bundles we also can consume 
the SPI implementations directly as real OSGI services.

For both options I can think of the following:

h4. *1) Get the ClassLoader from other OSGI Bundles*
Inside the Chemistry OpenCmis OSGI Client Wrapper the Activator needs to be 
adjusted to add a Bundle Listener which listens for Bundle changes (additional 
logic can be added to also iterate over already loaded bundles in case 
Chemistry Client Wrapper was started later then SPI Implementation Bundles).
If a bundle is in proper state (e.g. RESOLVED) we should be able to get the 
Bundle Classloader via BundleWiring:

{code:title=Activator.java|borderStyle=solid}
…
public void bundleChanged(BundleEvent event) {
        if (event.getType() == BundleEvent.RESOLVED) {
            BundleWiring bundleWiring = 
event.getBundle().adapt(BundleWiring.class);
            ClassLoader classLoader = bundleWiring.getClassLoader();
            // pass the class loader to ClassLoaderUtil
        }
}
…
{code}

This ClassLoader then can be passed to ClassLoaderUtil and when it tries to 
load a class it first uses current behaviour by trying to load the class from 
context class loader. If this failed it tries loading class by iterating over 
List of injected class loaders.

We still need to define how to tag the Bundles which contain OpenCmis SPI 
implementations. For example it could be done by setting a Manifest header like
{{Chemistry-SPI}}.
In Activator we then can get the header via:
{code:title=Activator.java|borderStyle=solid}
...
        if (event.getType() == BundleEvent.RESOLVED) {
            String header = (String) 
event.getBundle().getHeaders().get("Chemistry-SPI");
            // if header is not null get the class loader via BundleWiring 
interface and pass it to ClassLoaderUtil
{code}

A better option may be to put a property.

h4. *2) Loading SPI Implementations from other OSGI Bundles*

As OpenCmis does not use java.util.ServiceLoader  I would prefer to provide SPI 
services as real OSGI services instead of specifying them in files 
META-INF/services/<FQCN_OF_SPI>.
The OSGI services then can be accessed in Activator of OpenCmis Client Wrapper. 
For example AuthenticationProvider can be retrieved via:
{code:title=Activator.java|borderStyle=solid}
public void start(BundleContext context) {
    ...
    ServiceReference<?> serviceReference = 
context.getServiceReference(org.apache.chemistry.opencmis.commons.spi.AuthenticationProvider.class.getName());
    AuthenticationProvider authProvider = (AuthenticationProvider) 
context.getService(serviceReference); 
    // pass authProvider to proper places in OpenCmis Client framework
}
{code}

This would make the Client library of OpenCmis much more OSGI compliant but is 
also the most intrusive option:
It requires to pass the SPI implementations to different locations in OpenCmis 
framework. For example AuthenticationProvider implementation could be passed to 
CmisBindingFactory while an own Cache implementation is needed in SessionImpl. 
When injecting ClassLoaders instead of explicit services we can pass them to a 
single location: ClassLoaderUtil.

I'm interested in what the OpenCmis developers think about these options?
Do you see other alternatives or improvements?

> Allow loading classes from other OSGi Bundles in OSGi Client Wrapper
> --------------------------------------------------------------------
>
>                 Key: CMIS-878
>                 URL: https://issues.apache.org/jira/browse/CMIS-878
>             Project: Chemistry
>          Issue Type: Improvement
>          Components: opencmis-client
>    Affects Versions: OpenCMIS 0.12.0
>         Environment: OSGi
>            Reporter: Sascha Homeier
>            Priority: Minor
>
> When using the OpenCMIS OSGi Client Wrapper it is hard to load classes from 
> other bundles. For example if you specify an own Authentication Provider 
> class as Session Parameter then the Wrapper will not find this class when it 
> is located inside another bundle. Same problem should occur when defining an 
> own Cache.
> *1)*
> It would be nice if other bundles could register their Classloaders so that 
> ClassLoaderUtil can use it when trying to load classes.
> *2)*
> Another simpler option would be to simply add "DynamicImport-Package: *" to 
> the Manifest of the Wrapper. By doing this the Wrapper will find all classes 
> which are exported by other bundles. Though this approach feels more like a 
> hack since it breaks modularity.
> What do you think about it?
> Cheers
> Sascha



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to