Search code examples
javaosgiosgi-bundleresolverbnd

OSGi: can't install more than 1 Resource directly from a Repository?


Hello and thank you for reading,

I am currently having a problem with installing multiple Resources into my OSGi framework. I am using Eclipse IDE with the Bndtools plugin.

I have an online OSGi repository following the RFC 112. I have successfully written a method that can parse all these Resources into a List<Resource>. The Resources are now available for me by being able to obtain then using the .get(int) method of a List.

I have written a method that can install a Resource directly into the framework, for which the code can be found below:

public void installResource(Resource res) {

    RepositoryContent myRepoContext = (RepositoryContent) res;

    InputStream myInputStream = myRepoContext.getContent();

    try {
        installBundle(myInputStream);
        System.out.println("Installation of " + res.toString() + " SUCCESSFUL.");
    } catch (Exception e) {
        System.out.println("Installation of " + res.toString() + " FAILED.");
        e.printStackTrace();
    }

And this is using the installBundle(InputStream inputstream method I wrote which is the following:

public void installBundle(InputStream inputStream) {
    Bundle bundle = null;
    try {
        bundle = context.installBundle(null, inputStream);
        System.out.println("Context installed bundle correctly");

    } catch (BundleException e) {
        System.out.println("Context could not install bundle correctly.");
        e.printStackTrace();
    }

}

Now what I am trying to do is to install multiple Resources into my framework. I do NOT want them to be in the RESOLVED state, just the INSTALLED state is enough.

When I'm trying to install 1 Resource, everything works fine:

installResource(resource1);

This is working correctly because if I then ask for the current installed bundles/resources in the framework using the lb command in the shell, I can see the bundle being there in INSTALLED state:

13|Installed  |    1|org.dyamand.test.serialization (0.13.15)|0.13.15

So far so good, the installation method for the Resource is working. Although I thought. When I'm trying to install another Resource things go wrong. I'm not getting any error message or exception. On the contrary I am seeing my self printed out messages like Installation of " + res.toString() + " SUCCESSFUL.". This should mean that the Resource got installed correctly since no errors or nothing got thrown back.

But when I check for the bundles again using lb, the second resource/bundle is not there. The first one is. This has been tried with many different Resources (some that were just in the INSTALLED state, some that were in the RESOLVED state). It never worked, only to install the first Resource.

For example, if I stop the framework and start it up again with the following code:

installResource(resource1);
installResource(resource2);

The only thing that happens is the resource1 begin installed.

Maybe a second Resource can't be installed if the one before is not in the RESOLVED or ACTIVE state?

This is what I thought at first, but it was simply proven to be wrong. Instead of installing directly from a Resource obtained out of an OSGi repository, I went to Maven Central and got 3 random bundles and their direct URL. The URL's can be found in the code below as well as how the method was called to install. The installBundle method was used again:

     installBundle("https://search.maven.org/remotecontent?filepath=org/osgi/org.osgi/3.0.0/org.osgi-3.0.0.jar");
     installBundle("https://search.maven.org/remotecontent?filepath=org/osgi/enroute/examples/microservice/rest-app-jpa/0.0.1/rest-app-jpa-0.0.1.jar");
     installBundle("https://search.maven.org/remotecontent?filepath=org/coindirect/api/1.0.1/api-1.0.1.jar");

When starting the framework like this and then asking for the bundles using lb, all 3 of them show up in INSTALLED state. See the lb output below:

 13|Installed  |    1|osgi (3.0.0)|3.0.0
 14|Installed  |    1|rest-app-jpa (0.0.1)|0.0.1
 15|Installed  |    1|https://search.maven.org/remotecontent?filepath=org/coindirect/api/1.0.1/api-1.0.1.jar (0.0.0)|0.0.0

I have been searching the internet for an explanation why this happens, so my question here to you all: Does anyone have any idea why I can't install multiple Resources in the framework directly?

I don't see how installing directly from an URL is different as installing directly from a Resource since they both work (atleast the first time). Someone already remarked that I could install all my bundles from their direct URL link and yes that would work but: I don't have the direct URL links for Resources I take out of my repository. I can only access the Capability with namespace osgi.content just like my method does to get the InputStream so that the Resource can be installed.

Help is much appreciated. Thank you!


Solution

  • I assume the context.installBundle(null, inputStream) refers to this method. If so, you are passing null as bundle's location. The specs don't clearly say what should happen if location is null but they do say

    Every bundle is uniquely identified by its location string. If an installed bundle is using the specified location, the installBundle methods must return the Bundle object for that installed bundle and not install a new bundle.

    So my guess is that null is (or somehow becomes) a valid location and then every attempt after the first one tries to use the same location which according to the spec does not install the bundle.