Search code examples
javaosgikarafdeclarative-services

State unsatisfied (reference) for service in Karaf - where is the mistake? (OSGi, declarative service, annotations)


I have a very simple service provider and consumer. For some reason I cannot solve the problem that my consumer would use provider's service. Here is the bundle source code for provider:

package test;

import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;

@Component (name = "MyProvider", immediate = true)
public class TestClass implements SimpleMathI {

    public TestClass() {
        System.out.println("contructing TestClass");
    }

    @Activate
    protected void activate(ComponentContext c, BundleContext b) {
        System.out.println("activate testClass ");
    }

    @Deactivate
    protected void deactivate() {
        System.out.println("de-activate testClass");
    }

    @Override
    public void doSimpleAdd(int x, int y) {
        System.out.println("Result(TestClass): " + (x + y));
    }

    @Override
    public void doSimpleSubstract(int x, int y) {
        System.out.println("Result(TestClass): " + (x - y));
    }
}

It registers component MyProvider and the service test.SimpleMathI (listed in karaf)

Here is the consumer:

If I do not reference service SimpleMathI, but only ConfigurationAdmin it works fine!

package test;

import org.osgi.framework.BundleContext;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;

@Component (name = "MyConsumer", immediate = true, configurationPolicy = ConfigurationPolicy.OPTIONAL)
public class TestClass2 {

    public TestClass2() {
        System.out.println("contructing TestClass2");
    }

    @Reference (bind = "bind", unbind = "unbind")
    ConfigurationAdmin cm; // works

    @Reference (bind = "bindSimpleMathI", unbind = "unbindSimpleMathI")
    SimpleMathI simpleMath; // does not work, see screenshot

    @Activate
    protected void activate(ComponentContext c, BundleContext b) {
        System.out.println("activate testClass2");
        // simpleMath.doSimpleAdd(20, 25);
    }

    @Deactivate
    protected void deactivate() {
        System.out.println("de-activate testClass2");
    }

    protected void bind(ConfigurationAdmin a) {
        System.out.println("binding");
    }

    protected void unbind(ConfigurationAdmin a) {
        System.out.println("un-binding");
    }

    protected void bindSimpleMathI(SimpleMathI a) {
        System.out.println("binding!!");
    }

    protected void unbindSimpleMathI(SimpleMathI a) {
        System.out.println("un-binding!!");
    }
}

and here is the output in Karaf webconsole.

I googled enough, but still can't figure out what I missed. Strange, since the code is very simple and transparent. So, what I implemented wrong provider or consumer?

Karaf 4.0.7, no Apache felix used, pure OSGi R6 declarative services


Solution

  • I think you did a simple error. In OSGi you should not have two bundles with the same package.

    A typical setup in OSGi is to have three packages:

    • test.api for the Interface
    • test.impl or test.provider for the service impl
    • some.other.package for your consumer class

    You can either put both test.api and test.impl in the same bundle or have a separate api bundle.

    In any case the consumer should not embed the interface package into its own bundle. Instead it should have an Import-Package in its Manifest for the api package.