Search code examples
javaosgikarafblueprint-osgi

Trying to track a service in a bundle deployed to apache karaf. ServiceTracker#addingService doesn't get called


I add an OSGI-service MyService to apache karaf roughly that way:

  1. Create and annotate the service and its imlementation.
public interface MyService {//...}

@OsgiServiceProvider(classes=MyService .class)
@Singleton
public class MyServiceImpl implements MyService {//...}
  1. Use maven build with blueprint-maven-plugin and maven-bundle-plugin to process anotations. A declaration of OSGi-service and its implementation results in bundle.jar!/OSGI-INF/blueprint/autowire.xml:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
  xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0">
<bean id="myServiceImpl" class="com.foo.bar.MyServiceImpl"
  ext:field-injection="true" init-method="init">
    <property name="contextFactory" ref="initialContextFactory-"/>
</bean>
<service ref="myServiceImpl" interface="com.foo.bar.MyService"/>
</blueprint>

That XML is known to the bundle since it's in MANIFEST.MF:

Bundle-Blueprint: OSGI-INF/blueprint/autowire.xml
  1. Copy a feature including that bundle to karaf-home/deploy

Now I would like to bind that service to a JNDI-name for compatibility reasons. I try to achieve that by implementing init() in MyServiceImpl and using a ServiceTracker:

@PostConstruct
public void init() {
    BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
    ServiceTracker tracker = new ServiceTracker(context, this.getClass(), null) {
        @Override
        public Object addingService(ServiceReference reference) {
            Object serviceObj = super.addingService(reference);
            try {
                Context c = new InitialContext();
                bind(c, "java:global/com.foo.bar.bundle/MyServiceImpl!com.foo.bar.MyService", serviceObj );
            }
            catch (NamingException e) { e.printStackTrace(); }
            return serviceObj;
       }
    };
    tracker.open();
}

private void bind(Context ctx, String name, Object value) { //... }

Unfortunately I get a javax.naming.NotContextException if I do a lookup:

new InitialContext().lookup("java:global/com.foo.bar.bundle/MyServiceImpl!com.foo.bar.MyService");

To investigate that I firstly checked if the bundle was started and the service was added in the karaf console:

karaf@root()> bundle:list | grep bundle
155 | Active   |  80 | 0.0.1.SNAPSHOT     | bundle
karaf@root()> bundle:services 155

bundle (155) provides:
----------------------
[com.foo.bar.MyService]

Then I restarted karaf with debug parameter and set a breakpoint into init() and addedService(). The observation showed: init() gets called so the ServiceTracker should be added to the bundle properly. But addingService() doesn't get called.

What am I missing?


Solution

  • In the blueprint.xml you publish the service with its interface "com.foo.bar.MyService". So you need to use the same name in the service tracker lookup.

    Btw. why do you use a ServiceTracker at all? If you publish the service from @PostConstruct of your impl then just publish the impl using:

    Context c = new InitialContext();
    bind(c, "java:global/com.foo.bar.bundle/MyServiceImpl!com.foo.bar.MyService", this );