Search code examples
javacommand-lineosgiequinoxbnd

Shutdown an OSGi container after some code has been executed (to create a command-line tool)


I would like to create a command-line tool that starts an OSGi framework, in order to reuse code that is relying on OSGi.

In the answer accessing command-line arguments from OSGi bundle, I got how I can read the command line arguments:

@Component
public class Example {

    String[] args;

    @Activate
    void activate() {
        System.out.println("Hello World");
        System.out.println(args.length + " args:");
        for (String s : args) {
            System.out.println(" - " + s);
        }
    }

    @Reference(target = "(launcher.arguments=*)")
    void args(Object object, Map<String, Object> map) {
        if (map.containsKey("launcher.arguments")) {
            args = (String[]) map.get("launcher.arguments");
        } else {
            args = new String[] {};
        }
    }
}

But now when I run the assembled jar (bnd-export-maven-plugin) like this:

java -jar <path-to>/application.jar lorem ipsum

I get the expected output, but the application does not terminate.

After having read 4.2.6 Stopping a Framework, I was thinking that I need to call stop() on the system bundle. I have tried to change my code to:

@Activate
void activate(BundleContext bundleContext) {
    System.out.println("Hello World");
    System.out.println(args.length + " args:");
    for (String s : args) {
        System.out.println(" - " + s);
    }
    try {
        bundleContext.getBundle().stop();
    } catch (BundleException e) {
        e.printStackTrace();
    }
}

But it does not seems to work like this.


Solution

  • If you want the system bundle to stop you must do (notice the 0):

     bundleContext.getBundle(0).stop();
    

    To do this hyper correctly, you should do this in another thread.

    @Component
    public class ServiceComponent {
    
        @Activate
        void activate(BundleContext c) {
            CompletableFuture.runAsync( ()-> {
                try {
                    c.getBundle(0).stop();
                } catch (BundleException e) {
                    e.printStackTrace();
                }
            } );        
        }
    }
    

    This is, of course, a suicide component ...