0

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?

Danny Lo
  • 1,553
  • 4
  • 26
  • 48

1 Answers1

0

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 );
Christian Schneider
  • 19,420
  • 2
  • 39
  • 64
  • For some reason i thought the initialized bean and the service object I get from bundle would be 2 different objects. Removing `ServiceTracker` seems to resolve my issue, can't be 100% sure cause now i'm getting another exceptions. Just for understanding, could you explain what you mean by "service tracker lookup"? – Danny Lo Jan 06 '16 at 13:02
  • In this line you configure the ServiceTracker to lookup a service with a specific class name "new ServiceTracker(context, this.getClass(), null)". The name you give there must be the one the service is published with. The objects this and the service are indeed different. Blueprint registers a proxy for the service. You need this proxy if you use an interceptor like for JPA or transactions. – Christian Schneider Jan 06 '16 at 14:06
  • Yes, i use transactions indeed. Probably that's why I get an error message "Need active coordination". I also found [a log](http://irclogs.dankulp.com/logs/irclogger_log/apache-karaf?date=2015-11-12,Thu&sel=472#l468) where you explain why this Exception is thrown :) So it seems I really need a ServiceTracker. – Danny Lo Jan 06 '16 at 15:12
  • Thanks for saving my day! Now I understand my mistake. I publish the service not its implementation so of course my `ServiceTracker` can only successfully wait for a service. – Danny Lo Jan 06 '16 at 15:35
  • You can still avoid the servicetracker in this case. Simply create a second class and inject the blueprint bean into it using annotations. In the @PostConstruct of the second class you can then safely publish the injected bean in jndi. – Christian Schneider Jan 06 '16 at 18:37
  • What would be a benefit of a second class by comparison to a service tracker? – Danny Lo Jan 07 '16 at 08:08
  • You do not need the dependecy on the OSGi APIs and the code is less complex. – Christian Schneider Jan 07 '16 at 08:16