Search code examples
osgiopenstackopenstack4j

Use OpenStack4j in an OSGi platform


I want to use OpenStack4j in an OSGi platform. Specifically I'm using Apache Karaf OSGi runtime (based on Apache Felix OSGi implementation).

Issue arises when OpenStack4j tries to discovers Connectors. Based on Getting started official documentation guide, I'm trying to instantiate a v2.0 client with this line:

OSClient os = OSFactory.builder()
                .endpoint("http://host:5000/v2.0")
                .credentials("user", "password")
                .tenantName("tenant")
                .authenticate();

And I'm getting this exception:

Caused by: java.lang.ExceptionInInitializerError
    at org.openstack4j.openstack.internal.OSAuthenticator.authenticateV2(OSAuthenticator.java:77)
    at org.openstack4j.openstack.internal.OSAuthenticator.invoke(OSAuthenticator.java:41)
    at org.openstack4j.openstack.client.OSClientBuilder$ClientV2.authenticate(OSClientBuilder.java:84)
    at org.openstack4j.openstack.client.OSClientBuilder$ClientV2.authenticate(OSClientBuilder.java:65)
    ... 19 more
Caused by: java.lang.NullPointerException
    at org.openstack4j.core.transport.internal.HttpExecutor.initService(HttpExecutor.java:32)
    at org.openstack4j.core.transport.internal.HttpExecutor.<init>(HttpExecutor.java:25)
    at org.openstack4j.core.transport.internal.HttpExecutor.<clinit>(HttpExecutor.java:20)
    ... 27 more

It seems to be related with Connector discovery, but I'm not sure.

OpenStack4j does not support OSGi, I asked for it. I tried to solve the issue declaring a Apache Karaf feature, based on HTTPClient 4 like this:

<?xml version="1.0" encoding="UTF-8"?>
<features>

    <feature name="openstack4j" version="${openstack4j-version}">
        <feature version="${openstack4j-version}">openstack4j-httpclient</feature>

        <bundle dependency="true">mvn:com.google.guava/guava/17.0</bundle>

        <bundle dependency="true">mvn:com.fasterxml.jackson.core/jackson-databind/2.3.5</bundle>
        <bundle dependency="true">mvn:com.fasterxml.jackson.core/jackson-annotations/2.3.5</bundle>
        <bundle dependency="true">mvn:com.fasterxml.jackson.core/jackson-core/2.3.5</bundle>

        <bundle dependency="true">mvn:com.fasterxml.jackson.dataformat/jackson-dataformat-yaml/2.3.5</bundle>
        <bundle dependency="true">mvn:org.yaml/snakeyaml/1.14</bundle>

        <bundle dependency="true">wrap:mvn:com.google.code.findbugs/jsr305/2.0.0</bundle>

        <bundle>wrap:mvn:org.pacesys/openstack4j-core/${openstack4j-version}</bundle>       
    </feature>

    <feature name="openstack4j-httpclient" version="${openstack4j-version}">
        <bundle dependency="true">wrap:mvn:commons-logging/commons-logging/${commons.logging.version}</bundle>

        <bundle dependency="true">wrap:mvn:org.apache.httpcomponents/httpclient/4.3.1</bundle>
        <bundle dependency="true">wrap:mvn:org.apache.httpcomponents/httpcore/4.3</bundle>

        <bundle>wrap:mvn:org.pacesys.openstack4j.connectors/openstack4j-httpclient/${openstack4j-version}</bundle>      
    </feature>

</features>

But it does not solve my problem.

How can I use OpenStack4j in my OSGi environment?

EDIT: I have discovered that the NullPointerException is caused by a bug in the code (here the issue). It has been fixed.

Anyway, the issue with SPI persist.


Solution

  • I fear there is no simple solution for your issue. Regarding to the sources, the HttpExecutor is looking for a HttpExecutorService via the ServiceLoader. This most likely doesn't work as the ServiceLoader doesn't know anything about BundleClassloaders, and since your instantiating it from your Bundle it most likely is lacking the required package import. Another reason might be the ServiceLoader uses the parent classloader.

    So you have three possibilities.
    1) Make sure you are also importing org.openstack4j.core.transport.internal in your bundle
    2) set the TCCL (Thread Context ClassLoader) to the classloader of the bundle containing the package. So the ServiceLoader is capable of finding it.
    3) as Neil commented, use Aries SPY Fly ...