Failing to pass references to OSGI components and services

Hi!

I was wondering if I could get some insights. I have created a binding and also manged to listen to the eventbus using the code below:

@Component(service = EventSubscriber.class, property = { "service.pid=org.openhab.binding.mybinding.MySubscriber",
        "service.config.description.uri=binding:mybinding", "service.config.label=MyBidning Integration",
        "service.config.category=binding" })
public class MySubscriber implements EventSubscriber {
    private final Logger logger = LoggerFactory.getLogger(MySubscriber.class);
    private final Set<String> subscribedEventTypes = new HashSet<String>();
   
    public MySubscriber() {
        subscribedEventTypes.add(ItemStateEvent.TYPE);
        subscribedEventTypes.add(ItemCommandEvent.TYPE);
    }

    @Override
    public Set<String> getSubscribedEventTypes() {
        return subscribedEventTypes;
    }

    @Override
    public EventFilter getEventFilter() {
        return null;
    }

    
    @Override
    public void receive(Event event) {
        logger.debug("Got Event event: topic {} payload: {}", event.getTopic(), event.getPayload());
    }

I alos have a consumer.xml in the OSG-INF folder.

scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true"
	name="MySubscriber">
	<implementation class="org.openhab.binding.mybinding.internal.automation.MySubscriber"/>
	<service>
		<provide interface="org.openhab.core.events.EventSubscriber"/>
	</service>
</scr:component>

This seems to work, I can get all item updates.
The problem I have i how do I reference this osgi-service in my binding?
For instance I have a factory like this:

@Component(service = ThingHandlerFactory.class, configurationPid = "binding.mybinding")
@NonNullByDefault
public class MyBindingThingHandlerFactory extends BaseThingHandlerFactory {

    @Reference
    private @NonNullByDefault({}) MyBindingEventSubscriber eventSubscriber;

    public MyBindingThingHandlerFactory() {

    @Override
    public boolean supportsThingType(ThingTypeUID thingTypeUID) {
        return MyBindingMachineThingHandler.supportsThingType(thingTypeUID);
    }

    @Override
    protected @Nullable ThingHandler createHandler(Thing thing) {
        ThingTypeUID thingTypeUID = thing.getThingTypeUID();
        if (MyBindingThingHandler.supportsThingType(thingTypeUID)) {
            return new MyBindingThingHandler(thing, eventSubscriber);
        }
        return null;
    }
}

This @Reference doesn’t work. And at the same time I cannot reference the Factory inside the event listener.

The error I get is:

Feature resolution failed for [openhab-binding-mybinding/3.0.0.SNAPSHOT]
[ERROR] Message: Unable to resolve root: missing requirement [root] osgi.identity; osgi.identity

I’ve also tried getting hold of the reference via FramWorkUtil.getBundle and bundleContext.

Any pointers would be appreciated.

Regards, S

You should add MySubscriber.class service in the Component annotation in that class service = { EventSubscriber.class, MySubscriber.class}.

Also you can remove the xml. Xml is just an
alternative to annotations. In openHAB we prefer the annotations way.

1 Like

Thanks, I’ll try it out.

/S

Hi!
Still can’t get it to work.
Adding the class in the component annotation removes the compilation error. The reference is still null. I removed the xml-file as well.

This is what I currently have:

@Component(service = {EventSubscriber.class, MySubscriber.class}, property = { "service.pid=org.openhab.binding.mybinding.MySubscriber",
        "service.config.description.uri=binding:mybinding", "service.config.label=MyBidning Integration",
        "service.config.category=binding" })
public class MySubscriber implements EventSubscriber {
    private final Logger logger = LoggerFactory.getLogger(MySubscriber.class);
    private final Set<String> subscribedEventTypes = new HashSet<String>();
   
    public MySubscriber() {
        subscribedEventTypes.add(ItemStateEvent.TYPE);
        subscribedEventTypes.add(ItemCommandEvent.TYPE);
    }

    @Override
    public Set<String> getSubscribedEventTypes() {
        return subscribedEventTypes;
    }

    @Override
    public EventFilter getEventFilter() {
        return null;
    }

    
    @Override
    public void receive(Event event) {
        logger.debug("Got Event event: topic {} payload: {}", event.getTopic(), event.getPayload());
    }

Below the @Reference object is always null.

@Component(service = {ThingHandlerFactory.class, MyBindingThingHandlerFactory.class} , configurationPid = "binding.mybinding")
@NonNullByDefault
public class MyBindingThingHandlerFactory extends BaseThingHandlerFactory {

    @Reference
    private @NonNullByDefault({}) MySubscriber eventSubscriber;

    public MyBindingThingHandlerFactory() {

    @Override
    public boolean supportsThingType(ThingTypeUID thingTypeUID) {
        return MyBindingMachineThingHandler.supportsThingType(thingTypeUID);
    }

    @Override
    protected @Nullable ThingHandler createHandler(Thing thing) {
        ThingTypeUID thingTypeUID = thing.getThingTypeUID();
        if (MyBindingThingHandler.supportsThingType(thingTypeUID)) {
            return new MyBindingThingHandler(thing, eventSubscriber);
        }
        return null;
    }
}

I’ve experimented with adding immidate=true, and passing the reference in the constructor with @Reference and annotated constructor with @Activate, but doing so the binding silently fail (or the Eventsubscriber is at least not working.

I don’t know if it makes a difference, but can you try setting only service on the MySubscriber class in @Component and add a configurationPid = "binding.mybinding.eventsubscriber

Preferred initialization in Factory class would be:

  
    private final MySubscriber eventSubscriber;
    
    @Activate
    public MyBindingThingHandlerFactory(@Reference MySubscriber eventSubscriber) {
       this.eventSubscriber = eventSubscriber;
      ...

Also I would not expect MyBindingThingHandlerFactory.class to be in the service in the @Component in that class.

1 Like

This worked! Thanks for sorting it out!

For reference this is what it ended up like:

@Component(service = { EventSubscriber.class,
        MySubscriber.class }, configurationPid = "binding.mybinding.eventsubscriber")
public class MySubscriber implements EventSubscriber {
    private final Logger logger = LoggerFactory.getLogger(MySubscriber.class);
    private final Set<String> subscribedEventTypes = new HashSet<String>();
   
    public MySubscriber() {
        subscribedEventTypes.add(ItemStateEvent.TYPE);
        subscribedEventTypes.add(ItemCommandEvent.TYPE);
    }

    @Override
    public Set<String> getSubscribedEventTypes() {
        return subscribedEventTypes;
    }

    @Override
    public EventFilter getEventFilter() {
        return null;
    }

    
    @Override
    public void receive(Event event) {
        logger.debug("Got Event event: topic {} payload: {}", event.getTopic(), event.getPayload());
    }
@Component(service = {ThingHandlerFactory.class} , configurationPid = "binding.mybinding")
@NonNullByDefault
public class MyBindingThingHandlerFactory extends BaseThingHandlerFactory {

    private final MySubscriber eventSubscriber;

    @Activate
    public MyBindingThingHandlerFactory(final @Reference MySubscriber eventSubscriber) {
        this.eventSubscriber = eventSubscriber;
   }
    @Override
    public boolean supportsThingType(ThingTypeUID thingTypeUID) {
        return MyBindingMachineThingHandler.supportsThingType(thingTypeUID);
    }

    @Override
    protected @Nullable ThingHandler createHandler(Thing thing) {
        ThingTypeUID thingTypeUID = thing.getThingTypeUID();
        if (MyBindingThingHandler.supportsThingType(thingTypeUID)) {
            return new MyBindingThingHandler(thing, eventSubscriber);
        }
        return null;
    }
}

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.