简体   繁体   中英

How to start a JavaFx OSGi bundle

I'm trying to run a JavaFx OSGi module, but I keep getting the error:

org.osgi.framework.BundleException: Unable to resolve OSGiDmHelloWorldProvider [7](R 7.0): missing requirement [OSGiDmHelloWorldProvider [7](R 7.0)] osgi.wiring.package; (osgi.wiring.package=javafx.application) Unresolved requirements: [[OSGiDmHelloWorldProvider [7](R 7.0)] osgi.wiring.package; (osgi.wiring.package=javafx.application)]
    at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4112)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:2118)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:998)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:984)

This is how I load and start the modules:

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;

import java.io.File;
import java.util.*;


public class Launcher {

    private static String[] libs = null;

    private BundleContext context;

    private Launcher() {

        FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next();

        Map<String, String> config = new HashMap<String, String>();
        config.put("osgi.console", "");
        config.put("osgi.clean", "true");
        config.put("osgi.noShutdown", "true");
        config.put("eclipse.ignoreApp", "true");
        config.put("osgi.bundles.defaultStartLevel", "4");
        config.put("osgi.configuration.area", "./configuration");

        // automated bundles deployment
        config.put("felix.fileinstall.dir", "./dropins");
        config.put("felix.fileinstall.noInitialDelay", "true");
        config.put("felix.fileinstall.start.level", "4");

        config.put(Constants.FRAMEWORK_BOOTDELEGATION, "javafx.*,com.sun.javafx.*");
        config.put(Constants.FRAMEWORK_BUNDLE_PARENT, Constants.FRAMEWORK_BUNDLE_PARENT_APP);

        Framework framework = frameworkFactory.newFramework(config);

        try {
            framework.init();
            framework.start();
        } catch (BundleException e) {
            e.printStackTrace();
        }

        context = framework.getBundleContext();

        Bundle OSGiDmHelloWorldProvider = install("OSGiDmHelloWorldProvider");
        try {

            OSGiDmHelloWorldProvider.start();

        } catch (BundleException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Launcher();
    }

    private String[] getLibs() {
        if (libs == null) {
            List<String> jarsList = new ArrayList<String>();
            File pluginsDir = new File("libs");

            System.out.println("PATHS : " + pluginsDir.getAbsolutePath());

            for (String jar : pluginsDir.list()) {
                jarsList.add(jar);
            }
            libs = jarsList.toArray(new String[jarsList.size()]);
        }
        return libs;
    }

    protected Bundle install(String name) {
        String found = null;

        for (String jar : getLibs()) {
            if (jar.startsWith(name)) {
                found = String.format("file:libs/%s", jar);
                System.out.println(found);
                break;
            }
        }
        if (found == null) {
            throw new RuntimeException(String.format("JAR for %s not found", name));
        }
        try {
            return context.installBundle(found);
        } catch (BundleException e) {
            e.printStackTrace();
        }
        return null;
    }
}

The OSGiDmHelloWorldProvider Activator class:

import com.bw.osgi.provider.able.HelloWorldService;
import com.bw.osgi.provider.impl.HelloWorldServiceImpl;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ProviderActivator implements BundleActivator {

    Logger logger = LoggerFactory.getLogger(ProviderActivator.class);

    Stage stage;

    private ServiceRegistration registration;
    BundleContext bundleContext;

    @Override
    public void start(BundleContext bundleContext) throws Exception {
        registration = bundleContext.registerService(
                HelloWorldService.class.getName(),
                new HelloWorldServiceImpl(),
                null);

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                stage = new Stage();
                BorderPane pane = new BorderPane();
                Scene scene = new Scene(pane, 400, 200);
                pane.setCenter(new Label("This is a JavaFX Scene in a Stage"));
                stage.setScene(scene);
                stage.show();
            }
        });

        System.out.println("STAGE CALLED !!!");
    }

    @Override
    public void stop(BundleContext bundleContext) throws Exception {
        registration.unregister();

        logger.info("Set4Jfx Bundle: stop()");
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                stage.close();
            }
        });
    }
}

How can I load a module that uses JavaFx in a Maven OSGi application?

Thank you all in advance.

The error message means that your bundle imports package javafx.application , and no bundle exports that package. Therefore the import cannot be resolved.

I note that in your launcher code you try to set bootdelegation to javafx.* . That might allow the class to be loaded from the boot classpath if your bundle ever got as far as running, however it cannot get that far because of the unresolved import.

If you intend for the JavaFX classes to be loaded from the boot classloader then you should remove the package import from your own bundle. You would also have to arrange for the JavaFX classes to actually be provided by the boot classloader, since AFAIK they are normally only visible from the extension classloader.

However a better solution would be leave the import alone, and arrange for the javafx.application package to be exported from a bundle. That could be done from the system bundle using Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA .

Update

You should probably look at the Drombler FX tool/framework from @Puce, since it sounds like he has already done a lot of these setup tasks. However I felt that his answer didn't directly address your question about why your code was failing.

I've released some first versions of Drombler FX - the modular application framework for JavaFX based on OSGi and Maven (POM first).

It takes care of initializing JavaFX and OSGi.

Maybe you find it useful. The application framework is Open Source and the code is available on GitHub .

There is also a tutorial with a Getting Started trail.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM