Getting a concrete implementation from Felix

I've been doing OSGi training for a long time, but it still feels like a key piece of the puzzle is missing.

This is my use case:

I am using JAX-RS (Grizzly) to build REST API. I have an interface that has many different implementations. My solution should be able to add new implementations at any time.

Based on some form of input, I should get one of these specific instances. For example, let's say I register two interface implementations with Felix Interface A

and Interface B

. The user must be able to requestImplementation B

Using the command line we get from launch felix.jar

(Apache Felix Gogo) I was able to install and run my own packages. The problem I'm currently facing is how should I extract any of these implementations from one of my controllers.

Here is the activator code for one of my implementations.

public class MyClassActivator implements BundleActivator {

@Override
public void start(BundleContext context) throws Exception {
    System.out.println("Starting ImplementationA");
    Hashtable<String, String> props = new Hashtable<>();
    props.put("Identifier", "ImplementationA");

    context.registerService(MyInterface.class.getName(), new MyClassA(), props);
}

@Override
public void stop(BundleContext context) throws Exception {
    System.out.println("Stopping ImplementationA");

}

private class ImplementationA implements MyInterface { 
     /*my implementation*/ 
}

}

      

From one of my JAX-RS classes, I want to do this somehow:

MyInterface myclassA = getBundle("ImplementationA");

      

The string ImplementationA

is the same string that I placed on the props card.

I have tried so far

BundleContext bc = FrameworkUtil.getBundle(MyInterface.class).getBundleContext();

      

This however just returns null, it doesn't appear to "talk" to my felix instance.

So my questions are: how do I get the interface from Felix? And what do I want to do even with OSGi?

+3


source to share


1 answer


Your question is confusing as you are mixing terms for services and packages. A package is an installable block that contains code. This code can register and consume services. Services are an object that typically implements some interface that is shared between the package that provides the service and the packages that use the services.

So the first order of business is to make sure that the service interface package is exported by some package and imported by all packages that plan to participate in providing and consuming the service. This is for type safety. That is, consuming packages can safely map a service object to the expected service type.

Once this is done, as you observe, there may be multiple service providers. When a provider registers a service, they may indicate some metadata about the service in the form of key / value properties. Your example shows this in the property Identifier

. When a consumer views a service, a filter string can be specified that can indicate information to be checked against the service metadata for selection from multiple provided services.

public class MyServiceConsumer implements BundleActivator {

@Override
public void start(BundleContext context) throws Exception {
    System.out.println("Looking for ImplementationA");

    ServiceReference<MyInterface>[] refs =
    context.getServiceReferences(MyInterface.class, "(Identifier=ImplementationA)");
    MyInterface service = context.getService(refs[0]);
}

}

      



The above is terrible code; don't actually use it. It doesn't deal with the service not running when the consumer package is activated (refs == null) and it is not prepared for the service to go away. I highly recommend using OSGi declarative services when writing packages. It makes service use and deals dynamic super easy.

@Component
public class MyServiceConsumer {
MyInterface service;

@Reference(target="(Identifier=ImplementationA)")
private void bindService(MyInterface s) {
    service = s;
}

@Activate
private activate() {
    // do work
}

@Deactivate
private deactivate() {
    // do work
}

}

      

This is a component that will only be created if the corresponding service is present. It will be called in bindService to inject a service instance, a call will be triggered to enable the component for it to work. If the injected service leaves, the component will be called on deactivation and then discarded. If another corresponding service becomes available later, a new instance of the component will be activated.

See http://enroute.osgi.org/ for a tutorial on OSGi app dev.

+4


source







All Articles