0

Note: In my case, I'm using Apache Felix implementation if that's matters.

I have written bundle which I'm using as test. It's very simple "Hello World" bundle that do nothing more than print message to stdout when started/stopped:

public class Activator implements BundleActivator {

    @Override
    public void start(BundleContext context) throws Exception {
        System.out.println("Hello, World.");
    }

    @Override
    public void stop(BundleContext context) throws Exception {
        System.out.println("Goodbye, World.");
    }

}

There is also MANIFEST file which rather pointless to post since when I deploy above bundle through Apache Felix console from standard distribution (which can be downloaded here) bundle starts and print out message.


Next step I'm trying to do is deploy the very same bundle using programmatic approach. Unfortunately this is not working for me. My code looks as follow:

public static void main(String[] args) throws Exception {
    FrameworkFactory frameworkFactory = getFrameworkFactory();
    Framework framework = frameworkFactory.newFramework(null);

    System.out.println("BundleID = " + framework.getBundleId());
    System.out.println("State = " + getState(framework.getState()));

    framework.init();

    System.out.println("BundleID = " + framework.getBundleId());
    System.out.println("State = " + getState(framework.getState()));

    BundleContext bundleContext = framework.getBundleContext();
    bundleContext.addBundleListener((event) -> {
        System.out.println("Bundle Changed Event");
    });
    bundleContext.addFrameworkListener((event) -> {
        System.out.println("Framework Event");
    });
    bundleContext.addServiceListener((event) -> {
        System.out.println("Service Changed Event");
    });

    Bundle bundle = bundleContext.installBundle("file://<absolute-path-to-bundle-jar-same-as-above");

    System.out.println("BundleID = " + bundle.getBundleId());
    System.out.println("State = " + getState(bundle.getState()));

    bundle.start();

    System.out.println("BundleID = " + bundle.getBundleId());
    System.out.println("State = " + getState(bundle.getState()));
}

private static FrameworkFactory getFrameworkFactory() throws IllegalStateException {
    ServiceLoader<FrameworkFactory> loader = ServiceLoader.load(FrameworkFactory.class);

    FrameworkFactory factory = null;
    for (FrameworkFactory iterator : loader) {
        if (factory != null) {
            throw new IllegalStateException("Ambiguous SPI implementations.");
        }

        factory = iterator;
    }

    return factory;
}

private static String getState(int state) {
    switch (state) {
    case Bundle.UNINSTALLED:
        return "UNINSTALLED";
    case Bundle.INSTALLED:
        return "INSTALLED";
    case Bundle.RESOLVED:
        return "RESOLVED";
    case Bundle.STARTING:
        return "STARTING";
    case Bundle.STOPPING:
        return "STOPPING";
    case Bundle.ACTIVE:
        return "ACTIVE";
    default:
        throw new IllegalStateException("Unknown state");
    }
}

The output looks like follow:

BundleID = 0
State = INSTALLED
BundleID = 0
State = STARTING
Bundle Changed Event
BundleID = 1
State = INSTALLED
BundleID = 1
State = INSTALLED

So as far as I understand bundle got installed but last 4 lines indicate that bundle.start() got ignored for some reason.

Could you point out me what am I missing to make this work?

Cœur
  • 37,241
  • 25
  • 195
  • 267
abc
  • 2,371
  • 3
  • 25
  • 36

1 Answers1

0

After hour of debugging and reading through javadoc more carefully this is happening because framework was only initialized instead of being started. To make example work you have to simply add framework.start() after framework.init() (or just call framwork.start() which calls framework.init() if found it necessary).

I'm leaving this information as there are few confusing things:

  1. Official documentation to Apache Felix have information about embedding framework into host application. Unfortunately there is only example that use Apache Felix custom mechanisms that make it not portable to other implementations. What is confusing is warning note which if you want to create portable solution you should use init() and getBundleContext(). Whole note cited bellow:

WARNING The felix.systembundle.activators configuration property is specific to the Felix framework implementation. If you want your code to work with other framework implementations, you should call init() on the framework instance and use getBundleContext() directly. Otherwise, the approach would be very similar.

  1. JavaDoc for parameterless version of init() method do not mention about initialization is not same as starting the framework, although init(FrameworkListener...) have such information.

This Framework will not actually be started until start is called.

abc
  • 2,371
  • 3
  • 25
  • 36