0

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

neodix
  • 25
  • 7

2 Answers2

1

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.

Christian Schneider
  • 19,420
  • 2
  • 39
  • 64
  • ok, now I understood it. Also noticed that most of people use three packages approach. It makes sense indeed. – neodix Oct 14 '16 at 15:18
0

It's a very good point, didn't know that. After I changed the package name for consumer to test2 it still was not able to resolve, because it was looking for a service with test2.SimpleMathI.

To solve this I imported provider's Eclipse project with package test into consumer's project and specified in pom.xml dependencies to the provider's bundle:

<dependency>
    <groupId>com</groupId>
    <artifactId>DStestDS</artifactId>
    <version>0.0.18</version>
    <type>bundle</type>
</dependency>

and modified the code of consumer as follows:

@Reference (bind = "bindSimpleMathI", unbind = "unbindSimpleMathI")
test.SimpleMathI simpleMath; 

but I'm not sure if this is right... it somehow connects me to this particular version (18). In manifest.mf I used to specify the range of versions, how to do it in pom.xml?

wokring screenshot

Thank you Christian, you helped me again.

neodix
  • 25
  • 7