From 28f2e4297d4dfd2f980267e9edc9962266c13d2c Mon Sep 17 00:00:00 2001 From: Wouter Born Date: Fri, 11 Sep 2020 00:39:06 +0200 Subject: [PATCH] Fix item channel links not properly initialized Fixes #1596 Signed-off-by: Wouter Born --- .../thing/internal/ChannelLinkNotifier.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/internal/ChannelLinkNotifier.java diff --git a/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/internal/ChannelLinkNotifier.java b/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/internal/ChannelLinkNotifier.java new file mode 100644 index 00000000000..c3b82a24f4c --- /dev/null +++ b/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/internal/ChannelLinkNotifier.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.thing.internal; + +import java.util.function.Consumer; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.common.registry.RegistryChangeListener; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingRegistry; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.link.ItemChannelLink; +import org.openhab.core.thing.link.ItemChannelLinkRegistry; +import org.openhab.core.thing.util.ThingHandlerHelper; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link ChannelLinkNotifier} notifies initialized thing handlers of channels being linked or unlinked. + * + * @author Ɓukasz Dywicki - Initial contribution + * @author Wouter Born - Initial contribution + */ +@Component(immediate = true) +@NonNullByDefault +public class ChannelLinkNotifier implements RegistryChangeListener { + + private final Logger logger = LoggerFactory.getLogger(ChannelLinkNotifier.class); + + private final ItemChannelLinkRegistry itemChannelLinkRegistry; + private final ThingRegistry thingRegistry; + + @Activate + public ChannelLinkNotifier(@Reference ItemChannelLinkRegistry itemChannelLinkRegistry, + @Reference ThingRegistry thingRegistry) { + this.itemChannelLinkRegistry = itemChannelLinkRegistry; + this.thingRegistry = thingRegistry; + + itemChannelLinkRegistry.addRegistryChangeListener(this); + // registry does not dispatch notifications about existing links to listeners + itemChannelLinkRegistry.getAll().forEach(this::added); + } + + @Deactivate + public void deactivate() { + itemChannelLinkRegistry.removeRegistryChangeListener(this); + } + + @Override + public void added(ItemChannelLink element) { + ChannelUID channelUID = element.getLinkedUID(); + ThingUID thingUID = channelUID.getThingUID(); + + call(thingUID, handler -> handler.channelLinked(channelUID), "channelLinked"); + } + + @Override + public void removed(ItemChannelLink element) { + ChannelUID channelUID = element.getLinkedUID(); + ThingUID thingUID = channelUID.getThingUID(); + + call(thingUID, handler -> handler.channelUnlinked(channelUID), "channelUnlinked"); + } + + @Override + public void updated(ItemChannelLink oldElement, ItemChannelLink element) { + removed(oldElement); + added(element); + } + + private void call(ThingUID thingUID, Consumer consumer, String method) { + Thing thing = thingRegistry.get(thingUID); + if (thing != null) { + ThingHandler handler = thing.getHandler(); + if (handler != null && ThingHandlerHelper.isHandlerInitialized(handler)) { + consumer.accept(handler); + } else { + logger.debug("Skipping notification to thing {} handler '{}' method call, as it is not initialized", + thingUID, method); + } + } + } +}