Menu

Reference a service in a JavaFX pane

Dirk
2014-10-07
2014-10-15
  • Dirk

    Dirk - 2014-10-07

    Suppose we have two OSGi bundles A and B. A provides a service which will be referenced by B. B is a JavaFX pane which holds a table with data populated from a database. To get data into the table we need the service provided by A.

    I am wondering what would be the preferred way to inject the service into B?

    If B were an OSGi component I could reference the service via @Reference or xml. But that does not work because B is then instantiated by the OSGi framework which happens before the JavaFX toolkit is initialized. Obviously this would also interfere with the Drombler framework which will initialize the pane also.

    How can I solve it without using FrameworkUtils for example.

     
  • Dirk

    Dirk - 2014-10-09

    Just some thoughts..

    Currently I am using an abstract class "FXBaseComponent". Every class representing a JavaFX pane must extend it. In FXBaseComponent I have basically some infrastructure stuff like

        protected Bundle bundle;
    
        public FXBaseComponent() throws IOException {
            this.bundle = FrameworkUtil.getBundle(this.getClass());
    
            loadFXML();
            loadCSS();
        }
    
        protected BundleContext getBundleContext() {
            BundleContext bundleContext = null;
    
            if (bundle != null) {
                bundleContext = bundle.getBundleContext();
            }
    
            return bundleContext;
        }
    
        protected <T> Optional<T> getService(final Class<T> serviceClass) {
            BundleContext bundleContext = getBundleContext();
            ServiceReference<T> serviceReference =     
                      bundleContext.getServiceReference(serviceClass);
    
            return Optional.of(serviceReference != null ? 
                     bundleContext.getService(serviceReference) : null);
        }
    

    As this works great using FrameworkUtil seems always like a workaround to me. What I would really like is just a component where my JavaFX stuff can be loaded and any service or bundle is injected:

    @Component
    class MyComponent {
      @Reference
      MyService myService;
    
      @Activate
      void activatedMethod() {
        loadFXML();
      }
    }
    
     
  • Puce

    Puce - 2014-10-09

    Yes, unfortunatly, it needs currently some work-arounds to get a service into a JavaFX control such as the one you showed (I don't have currently my sample at hand).
    It's a major issue, which I would like to solve. I don't think however that turning a JavaFX control into a Declarative Service will work (as the annotations in your last sample suggests). Declarative Services are instantiated by the Declarative Service framework which uses a different thread than the JavaFX Application Thread. JavaFX controls need to be instantiated on the JavaFX Application Thread however. Correct me if I'm wrong.

    Therefore my current proposed solution is to go for CDI (JSR 299) (see [#37]).
    Using CDI it should be possible to inject CDI and OSGi services with @Inject (JSR 330) into JavaFX controls.

    There doesn't seem to be an official OSGi specification for integration of JSR 330 only. There is one (RFP 146/ RFC-193) for CDI (JSR 299), however, which includes JSR 330, but it still seems to be work in progress. The reference implementation seems to be PAX-CDI.

    I planned [#37] for version 0.6, but it might take several follow up issues until everything works as expected.

     
  • Dirk

    Dirk - 2014-10-13

    MyComponent in the example would act as a controller. When loading fxml the controller would be set in the fxml loader as long with the fxml pane. So controller and pane would be two separate classes. Currently DromblerFX assumes controller and pane is the same class.

    I like the idea to integrate CDI into DromblerFX. Looking forward to it.

     
  • Puce

    Puce - 2014-10-15

    Please note that Drombler FX does not assume that the controller and the pane are the same class. It only requires the annotated dockable class to extend from Node. Although I haven't tried I don't see any thing stopping you to e.g. extend from BorderPane, load a non-fx-root FXML with another controller and assigned the returned Node to the center property.
    That said I still can highly recommend to use the fx-root construct in most cases. You can use/ nest such classes in FXML like the other standard control classes.

     

Log in to post a comment.

MongoDB Logo MongoDB