Embedded -- code to start the OSGI framework

foreword

 

In the previous two articles, we started the OSGI framework ( equinox ) directly, and then put all bundles into the framework to run. In normal development, due to historical reasons, it is very difficult to migrate the entire application to the OSGI framework , but we can try to strip out the parts that need hot updates and make them into bundles . Then we embed an OSGI framework in our existing web framework , and use this embedded OSGI framework to load the bundle , thus realizing partial modularization of the program.

 

This demo is to start an embedded OSGI framework through code in a web application under a typical spring mvc framework.

 

The code starts the OSGI framework

 

Since spring is used , you can directly define a spring bean to start an OSGI framework:

/**
 * osgi container management
 */
@Component
public class OsgiInit {
 
    /**
     * Initialize the container
     */
    @PostConstruct
    public void init() {
        ServiceLoader<FrameworkFactory> serviceLoader = ServiceLoader.load(FrameworkFactory.class);
        FrameworkFactory frameworkFactory = serviceLoader.iterator().next();
 
        // some startup parameters
        Map<String, String> properties = new HashMap<>();
        properties.put("osgi.console", "");
        properties.put("osgi.clean", "true");
        properties.put("org.osgi.framework.bootdelegation", "sun.*,com.sun.*,javax.*");
        properties.put("org.osgi.framework.system.capabilities","osgi.ee; osgi.ee=\"JavaSE\";version:List=\"1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8\"");
 
        Framework framework = frameworkFactory.newFramework(properties);
 
        try {
            framework.init();//Initialize the framework
        } catch (BundleException e) {
            e.printStackTrace ();
        }
        try {
            framework.start();//Start the framework
 
            Thread thread = new Thread(() -> {
                try {
                    framework.waitForStop(0);
                } catch (InterruptedException e) {
                    e.printStackTrace ();
                }
            });
            thread.start();
            Constents.getInstence().setThread(thread);
 
            Constents.getInstence().setFramework(framework);
        } catch (BundleException e) {
            e.printStackTrace ();
        }
        System.out.println("osgi container started successfully");
    }
 
    /**
     * destroy the container
     */
    @PreDestroy
    public void destroy(){
        System.out.println("Start destroying the container");
        try {
            Constents.getInstence().getFramework().stop();
 
        } catch (BundleException e) {
            e.printStackTrace ();
        }
        Constents.getInstence().getThread().interrupt();
    }
}
 

 

The class here is annotated by @Component , the spring container will execute the init method annotated with @PostConstruct to start the OSGI framework before initializing the bean ; the spring container will execute the destroy method annotated with @PreDestroy before destroying the bean to destroy the OSGI framework.

 

After the OSGI framework is successfully started, the framework object will be saved by calling the Constants.getInstence().setFramework(framework); method . Take a look at the implementation of Constants:

public class Constents {
    private static final Constents constents = new Constents();
    private Thread thread;
    private Framework framework;//OSGI framework object
    private Map<String,Bundle> bundleMap = new HashMap<>();//Bundle loaded in OSGI framework
 
    private Constents(){}
    public static Constents getInstence(){
        return constents;
    }
 
    public Thread getThread() {
        return thread;
    }
 
    public void setThread(Thread thread) {
        this.thread = thread;
    }
 
    public Framework getFramework() {
        return framework;
    }
 
    public void setFramework(Framework framework) {
        this.framework = framework;
    }
 
    public void setBundle(Bundle bundle){
        this.bundleMap.put(bundle.getSymbolicName(),bundle);
    }
 
    public Bundle getBundle(String name){
        return this.bundleMap.get(name);
    }
}
 

 

Constants uses the singleton pattern to generate a unique Constants object. After the OSGI container is successfully started , the above code will assign the framework object to the Constants object. In the web framework, you can directly call the relevant methods of this object to dynamically load the Bundle .

 

Here we simulate the loading and startup of Bundle in a Spring mvc Controller :

@RequestMapping("/start")
    public String start(){
        Framework framework = Constents.getInstence().getFramework();//
        try {
            File bundleRoot = new File("D:\\test\\bundles");
            File[] files = bundleRoot.listFiles();
            for (File jar :files){
                Bundle temp = framework.getBundleContext().installBundle(jar.toURL().toExternalForm());
                Constents.getInstence().setBundle(temp);
            }
            //Start manager bundle
            Constents.getInstence().getBundle("com.sky.osgi.manager").start();
 
        } catch (Exception e) {
            System.out.println("Failed to install bundle");
            e.printStackTrace ();
        }
        return "start";
}

Of course, other methods such as modifying bundles and deleting bundles can also be defined in the Controller to control the running of the internal bundles of the embedded OSGI container .

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326392564&siteId=291194637