mirror of
https://github.com/danieldemus/openhab-core.git
synced 2026-07-29 12:34:22 +02:00
Added 'ChannelDescriptionChangedEvent' (#1505)
Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
+11
-6
@@ -17,12 +17,14 @@ import static org.openhab.core.magic.binding.MagicBindingConstants.*;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.magic.binding.internal.MagicDynamicCommandDescriptionProvider;
|
||||
import org.openhab.core.magic.binding.internal.MagicDynamicStateDescriptionProvider;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.CommandOption;
|
||||
import org.openhab.core.types.StateOption;
|
||||
|
||||
/**
|
||||
@@ -39,23 +41,26 @@ public class MagicDynamicStateDescriptionThingHandler extends BaseThingHandler {
|
||||
private static final String SYSTEM_COMMAND_SUSPEND = "Suspend";
|
||||
private static final String SYSTEM_COMMAND_QUIT = "Quit";
|
||||
|
||||
private final MagicDynamicCommandDescriptionProvider commandDescriptionProvider;
|
||||
private final MagicDynamicStateDescriptionProvider stateDescriptionProvider;
|
||||
|
||||
public MagicDynamicStateDescriptionThingHandler(Thing thing,
|
||||
MagicDynamicCommandDescriptionProvider commandDescriptionProvider,
|
||||
MagicDynamicStateDescriptionProvider stateDescriptionProvider) {
|
||||
super(thing);
|
||||
this.commandDescriptionProvider = commandDescriptionProvider;
|
||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
ChannelUID systemCommandChannelUID = new ChannelUID(getThing().getUID(), CHANNEL_SYSTEM_COMMAND);
|
||||
stateDescriptionProvider.setStateOptions(systemCommandChannelUID,
|
||||
List.of(new StateOption(SYSTEM_COMMAND_HIBERNATE, SYSTEM_COMMAND_HIBERNATE),
|
||||
new StateOption(SYSTEM_COMMAND_REBOOT, SYSTEM_COMMAND_REBOOT),
|
||||
new StateOption(SYSTEM_COMMAND_SHUTDOWN, SYSTEM_COMMAND_SHUTDOWN),
|
||||
new StateOption(SYSTEM_COMMAND_SUSPEND, SYSTEM_COMMAND_SUSPEND),
|
||||
new StateOption(SYSTEM_COMMAND_QUIT, SYSTEM_COMMAND_QUIT)));
|
||||
commandDescriptionProvider.setCommandOptions(systemCommandChannelUID,
|
||||
List.of(new CommandOption(SYSTEM_COMMAND_HIBERNATE, SYSTEM_COMMAND_HIBERNATE),
|
||||
new CommandOption(SYSTEM_COMMAND_REBOOT, SYSTEM_COMMAND_REBOOT),
|
||||
new CommandOption(SYSTEM_COMMAND_SHUTDOWN, SYSTEM_COMMAND_SHUTDOWN),
|
||||
new CommandOption(SYSTEM_COMMAND_SUSPEND, SYSTEM_COMMAND_SUSPEND),
|
||||
new CommandOption(SYSTEM_COMMAND_QUIT, SYSTEM_COMMAND_QUIT)));
|
||||
|
||||
ChannelUID signalStrengthChannelUID = new ChannelUID(getThing().getUID(), CHANNEL_SIGNAL_STRENGTH);
|
||||
stateDescriptionProvider.setStateOptions(signalStrengthChannelUID, List.of(new StateOption("1", "Unusable"),
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.magic.binding.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.events.EventPublisher;
|
||||
import org.openhab.core.thing.binding.BaseDynamicCommandDescriptionProvider;
|
||||
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
|
||||
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
|
||||
import org.openhab.core.thing.type.DynamicCommandDescriptionProvider;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* Dynamic provider of command options.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@Component(service = { DynamicCommandDescriptionProvider.class, MagicDynamicCommandDescriptionProvider.class })
|
||||
@NonNullByDefault
|
||||
public class MagicDynamicCommandDescriptionProvider extends BaseDynamicCommandDescriptionProvider {
|
||||
|
||||
@Activate
|
||||
public MagicDynamicCommandDescriptionProvider(final @Reference EventPublisher eventPublisher, //
|
||||
final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService, //
|
||||
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
|
||||
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
|
||||
}
|
||||
}
|
||||
+9
-8
@@ -13,9 +13,12 @@
|
||||
package org.openhab.core.magic.binding.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.events.EventPublisher;
|
||||
import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
|
||||
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
|
||||
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
|
||||
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
@@ -28,14 +31,12 @@ import org.osgi.service.component.annotations.Reference;
|
||||
@NonNullByDefault
|
||||
public class MagicDynamicStateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
|
||||
|
||||
@Reference
|
||||
protected void setChannelTypeI18nLocalizationService(
|
||||
final ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
|
||||
@Activate
|
||||
public MagicDynamicStateDescriptionProvider(final @Reference EventPublisher eventPublisher, //
|
||||
final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService, //
|
||||
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
|
||||
}
|
||||
|
||||
protected void unsetChannelTypeI18nLocalizationService(
|
||||
final ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
|
||||
this.channelTypeI18nLocalizationService = null;
|
||||
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -63,10 +63,13 @@ public class MagicHandlerFactory extends BaseThingHandlerFactory {
|
||||
THING_TYPE_CHATTY_THING, THING_TYPE_ROLLERSHUTTER, THING_TYPE_PLAYER, THING_TYPE_IMAGE,
|
||||
THING_TYPE_ACTION_MODULE, THING_TYPE_DYNAMIC_STATE_DESCRIPTION, THING_TYPE_ONLINE_OFFLINE);
|
||||
|
||||
private final MagicDynamicCommandDescriptionProvider commandDescriptionProvider;
|
||||
private final MagicDynamicStateDescriptionProvider stateDescriptionProvider;
|
||||
|
||||
@Activate
|
||||
public MagicHandlerFactory(final @Reference MagicDynamicStateDescriptionProvider stateDescriptionProvider) {
|
||||
public MagicHandlerFactory(final @Reference MagicDynamicCommandDescriptionProvider commandDescriptionProvider, //
|
||||
final @Reference MagicDynamicStateDescriptionProvider stateDescriptionProvider) {
|
||||
this.commandDescriptionProvider = commandDescriptionProvider;
|
||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||
}
|
||||
|
||||
@@ -128,7 +131,8 @@ public class MagicHandlerFactory extends BaseThingHandlerFactory {
|
||||
return new MagicActionModuleThingHandler(thing);
|
||||
}
|
||||
if (THING_TYPE_DYNAMIC_STATE_DESCRIPTION.equals(thingTypeUID)) {
|
||||
return new MagicDynamicStateDescriptionThingHandler(thing, stateDescriptionProvider);
|
||||
return new MagicDynamicStateDescriptionThingHandler(thing, commandDescriptionProvider,
|
||||
stateDescriptionProvider);
|
||||
}
|
||||
if (THING_TYPE_ONLINE_OFFLINE.equals(thingTypeUID)) {
|
||||
return new MagicOnlineOfflineHandler(thing);
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@ public class MagicHandlerFactoryTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
factory = new MagicHandlerFactory(mock(MagicDynamicStateDescriptionProvider.class));
|
||||
factory = new MagicHandlerFactory(mock(MagicDynamicCommandDescriptionProvider.class),
|
||||
mock(MagicDynamicStateDescriptionProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.binding;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventPublisher;
|
||||
import org.openhab.core.thing.events.ChannelDescriptionChangedEvent;
|
||||
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
|
||||
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AbstractDynamicDescriptionProvider} provides a base implementation for dynamic description providers.
|
||||
* <p>
|
||||
* It holds a reference to the {@link ChannelTypeI18nLocalizationService} to provide localized descriptions. Therefore
|
||||
* the inheriting class has to request a reference for the {@link ChannelTypeI18nLocalizationService} on its own.
|
||||
* <p>
|
||||
* It posts {@link ChannelDescriptionChangedEvent}s through the openHAB events bus about a changed dynamic description.
|
||||
* Therefore the subclass has to request references for the {@link EventPublisher} and
|
||||
* {@link ItemChannelLinkRegistry}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractDynamicDescriptionProvider {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
protected @NonNullByDefault({}) BundleContext bundleContext;
|
||||
protected @Nullable EventPublisher eventPublisher;
|
||||
protected @Nullable ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService;
|
||||
protected @Nullable ItemChannelLinkRegistry itemChannelLinkRegistry;
|
||||
|
||||
/**
|
||||
* This method can be used in a subclass in order to post events through the openHAB events bus. A common use case
|
||||
* is to notify event subscribers about a changed dynamic description.
|
||||
*
|
||||
* @param event the {@link Event}
|
||||
*/
|
||||
protected void postEvent(Event event) {
|
||||
if (eventPublisher != null) {
|
||||
try {
|
||||
eventPublisher.post(event);
|
||||
} catch (RuntimeException e) {
|
||||
logger.error("Cannot post '{}' event: {}", event.getType(), e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
logger.debug("Cannot post event as EventPublisher is missing");
|
||||
}
|
||||
}
|
||||
|
||||
@Activate
|
||||
protected void activate(ComponentContext componentContext) {
|
||||
bundleContext = componentContext.getBundleContext();
|
||||
}
|
||||
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
bundleContext = null;
|
||||
}
|
||||
}
|
||||
+19
-18
@@ -15,12 +15,14 @@ package org.openhab.core.thing.binding;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.events.ThingEventFactory;
|
||||
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
@@ -28,37 +30,40 @@ import org.openhab.core.thing.type.DynamicCommandDescriptionProvider;
|
||||
import org.openhab.core.types.CommandDescription;
|
||||
import org.openhab.core.types.CommandDescriptionBuilder;
|
||||
import org.openhab.core.types.CommandOption;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
|
||||
/**
|
||||
* The {@link BaseDynamicCommandDescriptionProvider} provides a base implementation for the
|
||||
* {@link DynamicCommandDescriptionProvider}.
|
||||
* <p>
|
||||
* It provides localized command options. Therefore the inheriting class has to request the reference for the
|
||||
* {@link ChannelTypeI18nLocalizationService} on its own.
|
||||
* It provides localized dynamic {@link CommandOption}s. Therefore the inheriting class has to request a reference for
|
||||
* the {@link ChannelTypeI18nLocalizationService} on its own.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
* @author Christoph Weitkamp - Added ChannelStateDescriptionChangedEvent
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class BaseDynamicCommandDescriptionProvider implements DynamicCommandDescriptionProvider {
|
||||
|
||||
private @NonNullByDefault({}) BundleContext bundleContext;
|
||||
protected @NonNullByDefault({}) ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService;
|
||||
public abstract class BaseDynamicCommandDescriptionProvider extends AbstractDynamicDescriptionProvider
|
||||
implements DynamicCommandDescriptionProvider {
|
||||
|
||||
protected final Map<ChannelUID, List<CommandOption>> channelOptionsMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* For a given channel UID, set a {@link List} of {@link CommandOption}s that should be used for the channel,
|
||||
* For a given {@link ChannelUID}, set a {@link List} of {@link CommandOption}s that should be used for the channel,
|
||||
* instead of the one defined statically in the {@link ChannelType}.
|
||||
*
|
||||
* @param channelUID the channel UID of the channel
|
||||
* @param channelUID the {@link ChannelUID} of the channel
|
||||
* @param options a {@link List} of {@link CommandOption}s
|
||||
*/
|
||||
public void setCommandOptions(ChannelUID channelUID, List<CommandOption> options) {
|
||||
channelOptionsMap.put(channelUID, options);
|
||||
List<CommandOption> oldOptions = channelOptionsMap.get(channelUID);
|
||||
if (!options.equals(oldOptions)) {
|
||||
channelOptionsMap.put(channelUID, options);
|
||||
postEvent(ThingEventFactory.createChannelDescriptionCommandOptionsChangedEvent(channelUID,
|
||||
itemChannelLinkRegistry != null ? itemChannelLinkRegistry.getLinkedItemNames(channelUID) : Set.of(),
|
||||
options, oldOptions));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,14 +97,10 @@ public abstract class BaseDynamicCommandDescriptionProvider implements DynamicCo
|
||||
return options;
|
||||
}
|
||||
|
||||
@Activate
|
||||
protected void activate(ComponentContext componentContext) {
|
||||
bundleContext = componentContext.getBundleContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
channelOptionsMap.clear();
|
||||
bundleContext = null;
|
||||
super.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
+30
-23
@@ -15,12 +15,14 @@ package org.openhab.core.thing.binding;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.events.ThingEventFactory;
|
||||
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
@@ -28,50 +30,58 @@ import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.openhab.core.types.StateDescriptionFragmentBuilder;
|
||||
import org.openhab.core.types.StateOption;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
|
||||
/**
|
||||
* The {@link BaseDynamicStateDescriptionProvider} provides a base implementation for the
|
||||
* {@link DynamicStateDescriptionProvider}.
|
||||
* <p>
|
||||
* It provides localized state patterns and dynamic state options while leaving other state description fields as
|
||||
* original. Therefore the inheriting class has to request the reference for the
|
||||
* It provides localized patterns and dynamic {@link StateOption}s while leaving other {@link StateDescription} fields
|
||||
* as original. Therefore the inheriting class has to request a reference for the
|
||||
* {@link ChannelTypeI18nLocalizationService} on its own.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
* @author Christoph Weitkamp - Added ChannelStateDescriptionChangedEvent
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class BaseDynamicStateDescriptionProvider implements DynamicStateDescriptionProvider {
|
||||
|
||||
private @NonNullByDefault({}) BundleContext bundleContext;
|
||||
protected @NonNullByDefault({}) ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService;
|
||||
public abstract class BaseDynamicStateDescriptionProvider extends AbstractDynamicDescriptionProvider
|
||||
implements DynamicStateDescriptionProvider {
|
||||
|
||||
protected final Map<ChannelUID, String> channelPatternMap = new ConcurrentHashMap<>();
|
||||
protected final Map<ChannelUID, List<StateOption>> channelOptionsMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* For a given channel UID, set a pattern that should be used for the channel, instead of the one defined statically
|
||||
* in the {@link ChannelType}.
|
||||
* For a given {@link ChannelUID}, set a pattern that should be used for the channel, instead of the one defined
|
||||
* statically in the {@link ChannelType}.
|
||||
*
|
||||
* @param channelUID the channel UID of the channel
|
||||
* @param channelUID the {@link ChannelUID} of the channel
|
||||
* @param pattern a pattern
|
||||
*/
|
||||
public void setStatePattern(ChannelUID channelUID, String pattern) {
|
||||
channelPatternMap.put(channelUID, pattern);
|
||||
String oldPattern = channelPatternMap.get(channelUID);
|
||||
if (!pattern.equals(oldPattern)) {
|
||||
channelPatternMap.put(channelUID, pattern);
|
||||
postEvent(ThingEventFactory.createChannelDescriptionPatternChangedEvent(channelUID,
|
||||
itemChannelLinkRegistry != null ? itemChannelLinkRegistry.getLinkedItemNames(channelUID) : Set.of(),
|
||||
pattern, oldPattern));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given channel UID, set a {@link List} of {@link StateOption}s that should be used for the channel, instead
|
||||
* of the one defined statically in the {@link ChannelType}.
|
||||
* For a given {@link ChannelUID}, set a {@link List} of {@link StateOption}s that should be used for the channel,
|
||||
* instead of the one defined statically in the {@link ChannelType}.
|
||||
*
|
||||
* @param channelUID the channel UID of the channel
|
||||
* @param channelUID the {@link ChannelUID} of the channel
|
||||
* @param options a {@link List} of {@link StateOption}s
|
||||
*/
|
||||
public void setStateOptions(ChannelUID channelUID, List<StateOption> options) {
|
||||
channelOptionsMap.put(channelUID, options);
|
||||
List<StateOption> oldOptions = channelOptionsMap.get(channelUID);
|
||||
if (!options.equals(oldOptions)) {
|
||||
channelOptionsMap.put(channelUID, options);
|
||||
postEvent(ThingEventFactory.createChannelDescriptionStateOptionsChangedEvent(channelUID,
|
||||
itemChannelLinkRegistry != null ? itemChannelLinkRegistry.getLinkedItemNames(channelUID) : Set.of(),
|
||||
options, oldOptions));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,14 +149,11 @@ public abstract class BaseDynamicStateDescriptionProvider implements DynamicStat
|
||||
return options;
|
||||
}
|
||||
|
||||
@Activate
|
||||
protected void activate(ComponentContext componentContext) {
|
||||
bundleContext = componentContext.getBundleContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
channelPatternMap.clear();
|
||||
channelOptionsMap.clear();
|
||||
bundleContext = null;
|
||||
super.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -34,8 +34,8 @@ public abstract class AbstractThingRegistryEvent extends AbstractEvent {
|
||||
*
|
||||
* @param topic the topic
|
||||
* @param payload the payload
|
||||
* @param source the source, can be null
|
||||
* @param thing the thing
|
||||
* @param source the source
|
||||
* @param thing the thing data transfer object
|
||||
*/
|
||||
protected AbstractThingRegistryEvent(String topic, String payload, @Nullable String source, ThingDTO thing) {
|
||||
super(topic, payload, source);
|
||||
@@ -43,9 +43,9 @@ public abstract class AbstractThingRegistryEvent extends AbstractEvent {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the thing.
|
||||
* Gets the thing data transfer object.
|
||||
*
|
||||
* @return the thing
|
||||
* @return the thing data transfer object
|
||||
*/
|
||||
public ThingDTO getThing() {
|
||||
return thing;
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.events;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.AbstractEvent;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.types.CommandDescription;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
|
||||
/**
|
||||
* {@link ChannelDescriptionChangedEvent}s will be delivered through the openHAB event bus if the
|
||||
* {@link CommandDescription} or {@link StateDescription} of a channel has changed. Instances must be created with the
|
||||
* {@link ThingEventFactory}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ChannelDescriptionChangedEvent extends AbstractEvent {
|
||||
|
||||
public enum CommonChannelDescriptionField {
|
||||
ALL,
|
||||
COMMAND_OPTIONS,
|
||||
PATTERN,
|
||||
STATE_OPTIONS
|
||||
};
|
||||
|
||||
/**
|
||||
* The channel description changed event type.
|
||||
*/
|
||||
public static final String TYPE = ChannelDescriptionChangedEvent.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* The changed field.
|
||||
*/
|
||||
private CommonChannelDescriptionField field;
|
||||
|
||||
/**
|
||||
* The channel which triggered the event.
|
||||
*/
|
||||
private final ChannelUID channelUID;
|
||||
|
||||
/**
|
||||
* A {@link Set} of linked item names.
|
||||
*/
|
||||
private final Set<String> linkedItemNames;
|
||||
|
||||
/**
|
||||
* The new value (represented as JSON string).
|
||||
*/
|
||||
private final String value;
|
||||
|
||||
/**
|
||||
* The old value (represented as JSON string).
|
||||
*/
|
||||
private final @Nullable String oldValue;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param topic the topic
|
||||
* @param payload the payload
|
||||
* @param field the changed field
|
||||
* @param channelUID the {@link ChannelUID}
|
||||
* @param linkedItemNames a {@link Set} of linked item names
|
||||
* @param value the new value (represented as JSON string)
|
||||
* @param oldValue the old value represented as JSON string)
|
||||
*/
|
||||
protected ChannelDescriptionChangedEvent(String topic, String payload, CommonChannelDescriptionField field,
|
||||
ChannelUID channelUID, Set<String> linkedItemNames, String value, @Nullable String oldValue) {
|
||||
super(topic, payload, null);
|
||||
this.field = field;
|
||||
this.channelUID = channelUID;
|
||||
this.linkedItemNames = linkedItemNames;
|
||||
this.value = value;
|
||||
this.oldValue = oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the changed field.
|
||||
*
|
||||
* @return the changed field
|
||||
*/
|
||||
public CommonChannelDescriptionField getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link ChannelUID}.
|
||||
*
|
||||
* @return the {@link ChannelUID}
|
||||
*/
|
||||
public ChannelUID getChannelUID() {
|
||||
return channelUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the linked item names.
|
||||
*
|
||||
* @return a {@link Set} of linked item names
|
||||
*/
|
||||
public Set<String> getLinkedItemNames() {
|
||||
return linkedItemNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the new value (represented as JSON string).
|
||||
*
|
||||
* @return the new value.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the old value (represented as JSON string).
|
||||
*
|
||||
* @return the old value.
|
||||
*/
|
||||
public @Nullable String getOldValue() {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"Description for field '%s' of channel '%s' changed from '%s' to '%s' for linked items: %s", field,
|
||||
channelUID, oldValue, value, linkedItemNames.stream().collect(Collectors.joining(",", "[", "]")));
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -58,6 +58,11 @@ public class ChannelTriggeredEvent extends AbstractEvent {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event.
|
||||
*
|
||||
@@ -74,13 +79,8 @@ public class ChannelTriggeredEvent extends AbstractEvent {
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return channel + " triggered " + event;
|
||||
return String.format("%s triggered %s", channel, event);
|
||||
}
|
||||
}
|
||||
|
||||
+189
-10
@@ -27,6 +27,9 @@ import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.dto.ThingDTO;
|
||||
import org.openhab.core.thing.dto.ThingDTOMapper;
|
||||
import org.openhab.core.thing.events.ChannelDescriptionChangedEvent.CommonChannelDescriptionField;
|
||||
import org.openhab.core.types.CommandOption;
|
||||
import org.openhab.core.types.StateOption;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
@@ -37,6 +40,7 @@ import org.osgi.service.component.annotations.Component;
|
||||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
* @author Dennis Nobel - Added status changed event
|
||||
* @author Christoph Weitkamp - Added ChannelDescriptionChangedEvent
|
||||
*/
|
||||
@Component(immediate = true, service = EventFactory.class)
|
||||
@NonNullByDefault
|
||||
@@ -51,6 +55,8 @@ public class ThingEventFactory extends AbstractEventFactory {
|
||||
|
||||
static final String THING_UPDATED_EVENT_TOPIC = "openhab/things/{thingUID}/updated";
|
||||
|
||||
static final String CHANNEL_DESCRIPTION_CHANGED_TOPIC = "openhab/channels/{channelUID}/descriptionchanged";
|
||||
|
||||
static final String CHANNEL_TRIGGERED_EVENT_TOPIC = "openhab/channels/{channelUID}/triggered";
|
||||
|
||||
/**
|
||||
@@ -58,7 +64,8 @@ public class ThingEventFactory extends AbstractEventFactory {
|
||||
*/
|
||||
public ThingEventFactory() {
|
||||
super(Set.of(ThingStatusInfoEvent.TYPE, ThingStatusInfoChangedEvent.TYPE, ThingAddedEvent.TYPE,
|
||||
ThingRemovedEvent.TYPE, ThingUpdatedEvent.TYPE, ChannelTriggeredEvent.TYPE));
|
||||
ThingRemovedEvent.TYPE, ThingUpdatedEvent.TYPE, ChannelDescriptionChangedEvent.TYPE,
|
||||
ChannelTriggeredEvent.TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,12 +81,184 @@ public class ThingEventFactory extends AbstractEventFactory {
|
||||
return createRemovedEvent(topic, payload);
|
||||
} else if (ThingUpdatedEvent.TYPE.equals(eventType)) {
|
||||
return createUpdatedEvent(topic, payload);
|
||||
} else if (ChannelDescriptionChangedEvent.TYPE.equals(eventType)) {
|
||||
return createChannelDescriptionChangedEvent(topic, payload);
|
||||
} else if (ChannelTriggeredEvent.TYPE.equals(eventType)) {
|
||||
return createTriggerEvent(topic, payload, source);
|
||||
}
|
||||
throw new IllegalArgumentException("The event type '" + eventType + "' is not supported by this factory.");
|
||||
}
|
||||
|
||||
public static class ChannelDescriptionChangedEventPayloadBean {
|
||||
public @NonNullByDefault({}) CommonChannelDescriptionField field;
|
||||
public @NonNullByDefault({}) String channelUID;
|
||||
public Set<String> linkedItemNames = Set.of();
|
||||
public @NonNullByDefault({}) String value;
|
||||
public @Nullable String oldValue;
|
||||
|
||||
/**
|
||||
* Default constructor for deserialization e.g. by Gson.
|
||||
*/
|
||||
protected ChannelDescriptionChangedEventPayloadBean() {
|
||||
}
|
||||
|
||||
public ChannelDescriptionChangedEventPayloadBean(CommonChannelDescriptionField field, String channelUID,
|
||||
Set<String> linkedItemNames, String value, @Nullable String oldValue) {
|
||||
this.field = field;
|
||||
this.channelUID = channelUID;
|
||||
this.linkedItemNames = linkedItemNames;
|
||||
this.value = value;
|
||||
this.oldValue = oldValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static interface CommonChannelDescriptionFieldPayloadBean {
|
||||
}
|
||||
|
||||
public static class ChannelDescriptionPatternPayloadBean implements CommonChannelDescriptionFieldPayloadBean {
|
||||
public @NonNullByDefault({}) String pattern;
|
||||
|
||||
/**
|
||||
* Default constructor for deserialization e.g. by Gson.
|
||||
*/
|
||||
protected ChannelDescriptionPatternPayloadBean() {
|
||||
}
|
||||
|
||||
public ChannelDescriptionPatternPayloadBean(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ChannelDescriptionStateOptionsPayloadBean implements CommonChannelDescriptionFieldPayloadBean {
|
||||
public @NonNullByDefault({}) List<StateOption> options;
|
||||
|
||||
/**
|
||||
* Default constructor for deserialization e.g. by Gson.
|
||||
*/
|
||||
protected ChannelDescriptionStateOptionsPayloadBean() {
|
||||
}
|
||||
|
||||
public ChannelDescriptionStateOptionsPayloadBean(List<StateOption> options) {
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ChannelDescriptionCommandOptionsPayloadBean
|
||||
implements CommonChannelDescriptionFieldPayloadBean {
|
||||
public @NonNullByDefault({}) List<CommandOption> options;
|
||||
|
||||
/**
|
||||
* Default constructor for deserialization e.g. by Gson.
|
||||
*/
|
||||
protected ChannelDescriptionCommandOptionsPayloadBean() {
|
||||
}
|
||||
|
||||
public ChannelDescriptionCommandOptionsPayloadBean(List<CommandOption> options) {
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ChannelDescriptionChangedEvent} for a changed pattern. New and optional old value will be
|
||||
* serialized to a JSON string from the {@link ChannelDescriptionPatternPayloadBean} object.
|
||||
*
|
||||
* @param channelUID the {@link ChannelUID}
|
||||
* @param linkedItemNames a {@link Set} of linked item names
|
||||
* @param pattern the new pattern
|
||||
* @param oldPattern the old pattern
|
||||
* @return Created {@link ChannelDescriptionChangedEvent}
|
||||
*/
|
||||
public static ChannelDescriptionChangedEvent createChannelDescriptionPatternChangedEvent(ChannelUID channelUID,
|
||||
Set<String> linkedItemNames, String pattern, @Nullable String oldPattern) {
|
||||
checkNotNull(linkedItemNames, "linkedItemNames");
|
||||
checkNotNull(channelUID, "channelUID");
|
||||
checkNotNull(pattern, "pattern");
|
||||
|
||||
String patternPayload = serializePayload(new ChannelDescriptionPatternPayloadBean(pattern));
|
||||
String oldPatternPayload = oldPattern != null
|
||||
? serializePayload(new ChannelDescriptionPatternPayloadBean(oldPattern))
|
||||
: null;
|
||||
ChannelDescriptionChangedEventPayloadBean bean = new ChannelDescriptionChangedEventPayloadBean(
|
||||
CommonChannelDescriptionField.PATTERN, channelUID.getAsString(), linkedItemNames, patternPayload,
|
||||
oldPatternPayload);
|
||||
String payload = serializePayload(bean);
|
||||
String topic = buildTopic(CHANNEL_DESCRIPTION_CHANGED_TOPIC, channelUID);
|
||||
return new ChannelDescriptionChangedEvent(topic, payload, CommonChannelDescriptionField.PATTERN, channelUID,
|
||||
linkedItemNames, patternPayload, oldPatternPayload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ChannelDescriptionChangedEvent} for changed {@link StateOption}s. New and optional old value
|
||||
* will be serialized to a JSON string from the {@link ChannelDescriptionStateOptionsPayloadBean} object.
|
||||
*
|
||||
* @param channelUID the {@link ChannelUID}
|
||||
* @param linkedItemNames a {@link Set} of linked item names
|
||||
* @param options the new {@link StateOption}s
|
||||
* @param oldOptions the old {@link StateOption}s
|
||||
* @return Created {@link ChannelDescriptionChangedEvent}
|
||||
*/
|
||||
public static ChannelDescriptionChangedEvent createChannelDescriptionStateOptionsChangedEvent(ChannelUID channelUID,
|
||||
Set<String> linkedItemNames, List<StateOption> options, @Nullable List<StateOption> oldOptions) {
|
||||
checkNotNull(linkedItemNames, "linkedItemNames");
|
||||
checkNotNull(channelUID, "channelUID");
|
||||
checkNotNull(options, "options");
|
||||
|
||||
String stateOptionsPayload = serializePayload(new ChannelDescriptionStateOptionsPayloadBean(options));
|
||||
String oldStateOptionsPayload = oldOptions != null
|
||||
? serializePayload(new ChannelDescriptionStateOptionsPayloadBean(oldOptions))
|
||||
: null;
|
||||
ChannelDescriptionChangedEventPayloadBean bean = new ChannelDescriptionChangedEventPayloadBean(
|
||||
CommonChannelDescriptionField.STATE_OPTIONS, channelUID.getAsString(), linkedItemNames,
|
||||
stateOptionsPayload, oldStateOptionsPayload);
|
||||
String payload = serializePayload(bean);
|
||||
String topic = buildTopic(CHANNEL_DESCRIPTION_CHANGED_TOPIC, channelUID);
|
||||
return new ChannelDescriptionChangedEvent(topic, payload, CommonChannelDescriptionField.STATE_OPTIONS,
|
||||
channelUID, linkedItemNames, stateOptionsPayload, oldStateOptionsPayload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ChannelDescriptionChangedEvent} for change {@link CommandOption}s. New and optional old value
|
||||
* will be serialized to a JSON string from the {@link ChannelDescriptionCommandOptionsPayloadBean} object.
|
||||
*
|
||||
* @param channelUID the {@link ChannelUID}
|
||||
* @param linkedItemNames a {@link Set} of linked item names
|
||||
* @param options the new {@link CommandOption}s
|
||||
* @param oldOptions the old {@link CommandOption}s
|
||||
* @return Created {@link ChannelDescriptionChangedEvent}
|
||||
*/
|
||||
public static ChannelDescriptionChangedEvent createChannelDescriptionCommandOptionsChangedEvent(
|
||||
ChannelUID channelUID, Set<String> linkedItemNames, List<CommandOption> options,
|
||||
@Nullable List<CommandOption> oldOptions) {
|
||||
checkNotNull(linkedItemNames, "linkedItemNames");
|
||||
checkNotNull(channelUID, "channelUID");
|
||||
checkNotNull(options, "options");
|
||||
|
||||
String commandOptionsPayload = serializePayload(new ChannelDescriptionCommandOptionsPayloadBean(options));
|
||||
String oldCommandOptionsPayload = oldOptions != null
|
||||
? serializePayload(new ChannelDescriptionCommandOptionsPayloadBean(oldOptions))
|
||||
: null;
|
||||
ChannelDescriptionChangedEventPayloadBean bean = new ChannelDescriptionChangedEventPayloadBean(
|
||||
CommonChannelDescriptionField.COMMAND_OPTIONS, channelUID.getAsString(), linkedItemNames,
|
||||
commandOptionsPayload, oldCommandOptionsPayload);
|
||||
String payload = serializePayload(bean);
|
||||
String topic = buildTopic(CHANNEL_DESCRIPTION_CHANGED_TOPIC, channelUID);
|
||||
return new ChannelDescriptionChangedEvent(topic, payload, CommonChannelDescriptionField.COMMAND_OPTIONS,
|
||||
channelUID, linkedItemNames, commandOptionsPayload, oldCommandOptionsPayload);
|
||||
}
|
||||
|
||||
private ChannelDescriptionChangedEvent createChannelDescriptionChangedEvent(String topic, String payload) {
|
||||
String[] topicElements = getTopicElements(topic);
|
||||
if (topicElements.length != 4) {
|
||||
throw new IllegalArgumentException(
|
||||
"ChannelDescriptionChangedEvent creation failed, invalid topic: " + topic);
|
||||
}
|
||||
ChannelUID channelUID = new ChannelUID(topicElements[2]);
|
||||
ChannelDescriptionChangedEventPayloadBean bean = deserializePayload(payload,
|
||||
ChannelDescriptionChangedEventPayloadBean.class);
|
||||
return new ChannelDescriptionChangedEvent(topic, payload, bean.field, channelUID, bean.linkedItemNames,
|
||||
bean.value, bean.oldValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a java bean that is used to serialize/deserialize trigger event payload.
|
||||
*/
|
||||
@@ -108,11 +287,11 @@ public class ThingEventFactory extends AbstractEventFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a channel triggered event.
|
||||
* Creates a {@link ChannelTriggeredEvent}
|
||||
*
|
||||
* @param event The event
|
||||
* @param channelUID The channel UID
|
||||
* @return the created channel triggered event
|
||||
* @param event the event
|
||||
* @param channel the {@link ChannelUID}
|
||||
* @return Created {@link ChannelTriggeredEvent}
|
||||
*/
|
||||
public static ChannelTriggeredEvent createTriggerEvent(String event, ChannelUID channelUID) {
|
||||
checkNotNull(channelUID, "channelUID");
|
||||
@@ -218,7 +397,7 @@ public class ThingEventFactory extends AbstractEventFactory {
|
||||
* @throws IllegalArgumentException if thing is null
|
||||
*/
|
||||
public static ThingAddedEvent createAddedEvent(Thing thing) {
|
||||
assertValidArgument(thing);
|
||||
assertValidThing(thing);
|
||||
String topic = buildTopic(THING_ADDED_EVENT_TOPIC, thing.getUID());
|
||||
ThingDTO thingDTO = map(thing);
|
||||
String payload = serializePayload(thingDTO);
|
||||
@@ -233,7 +412,7 @@ public class ThingEventFactory extends AbstractEventFactory {
|
||||
* @throws IllegalArgumentException if thing is null
|
||||
*/
|
||||
public static ThingRemovedEvent createRemovedEvent(Thing thing) {
|
||||
assertValidArgument(thing);
|
||||
assertValidThing(thing);
|
||||
String topic = buildTopic(THING_REMOVED_EVENT_TOPIC, thing.getUID());
|
||||
ThingDTO thingDTO = map(thing);
|
||||
String payload = serializePayload(thingDTO);
|
||||
@@ -249,8 +428,8 @@ public class ThingEventFactory extends AbstractEventFactory {
|
||||
* @throws IllegalArgumentException if thing or oldThing is null
|
||||
*/
|
||||
public static ThingUpdatedEvent createUpdateEvent(Thing thing, Thing oldThing) {
|
||||
assertValidArgument(thing);
|
||||
assertValidArgument(oldThing);
|
||||
assertValidThing(thing);
|
||||
assertValidThing(oldThing);
|
||||
String topic = buildTopic(THING_UPDATED_EVENT_TOPIC, thing.getUID());
|
||||
ThingDTO thingDTO = map(thing);
|
||||
ThingDTO oldThingDTO = map(oldThing);
|
||||
@@ -261,7 +440,7 @@ public class ThingEventFactory extends AbstractEventFactory {
|
||||
return new ThingUpdatedEvent(topic, payload, thingDTO, oldThingDTO);
|
||||
}
|
||||
|
||||
private static void assertValidArgument(Thing thing) {
|
||||
private static void assertValidThing(Thing thing) {
|
||||
checkNotNull(thing, "thing");
|
||||
checkNotNull(thing.getUID(), "thingUID of the thing");
|
||||
}
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.binding;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventPublisher;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.events.ChannelDescriptionChangedEvent;
|
||||
import org.openhab.core.thing.events.ChannelDescriptionChangedEvent.CommonChannelDescriptionField;
|
||||
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
|
||||
import org.openhab.core.types.CommandOption;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
/**
|
||||
* Tests for {@link BaseDynamicCommandDescriptionProvider}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
class BaseDynamicCommandDescriptionProviderTest {
|
||||
|
||||
private static final ThingTypeUID THING_TYPE_UID = new ThingTypeUID("binding:type");
|
||||
private static final ThingUID THING_UID = new ThingUID(THING_TYPE_UID, "id");
|
||||
private static final ChannelUID CHANNEL_UID = new ChannelUID(THING_UID, "channel");
|
||||
|
||||
@Mock
|
||||
EventPublisher mockEventPublisher;
|
||||
|
||||
@Mock
|
||||
ItemChannelLinkRegistry mockItemChannelLinkRegistry;
|
||||
|
||||
class TestDynamicCommandDescriptionProvider extends BaseDynamicCommandDescriptionProvider {
|
||||
|
||||
public TestDynamicCommandDescriptionProvider() {
|
||||
this.bundleContext = mock(BundleContext.class);
|
||||
this.eventPublisher = mockEventPublisher;
|
||||
this.itemChannelLinkRegistry = mockItemChannelLinkRegistry;
|
||||
}
|
||||
};
|
||||
|
||||
private TestDynamicCommandDescriptionProvider subject;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
when(mockItemChannelLinkRegistry.getLinkedItemNames(CHANNEL_UID)).thenReturn(Set.of("item1", "item2"));
|
||||
|
||||
subject = new TestDynamicCommandDescriptionProvider();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCommandOptionsPublishesEvent() {
|
||||
subject.setCommandOptions(CHANNEL_UID, List.of(new CommandOption("reboot", "Reboot")));
|
||||
|
||||
ArgumentCaptor<Event> capture = ArgumentCaptor.forClass(Event.class);
|
||||
verify(mockEventPublisher, times(1)).post(capture.capture());
|
||||
|
||||
Event event = capture.getValue();
|
||||
assertTrue(event instanceof ChannelDescriptionChangedEvent);
|
||||
ChannelDescriptionChangedEvent cdce = (ChannelDescriptionChangedEvent) event;
|
||||
assertEquals(CommonChannelDescriptionField.COMMAND_OPTIONS, cdce.getField());
|
||||
|
||||
// check the event is not published again
|
||||
subject.setCommandOptions(CHANNEL_UID, List.of(new CommandOption("reboot", "Reboot")));
|
||||
|
||||
verify(mockEventPublisher, times(1)).post(capture.capture());
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.binding;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventPublisher;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.events.ChannelDescriptionChangedEvent;
|
||||
import org.openhab.core.thing.events.ChannelDescriptionChangedEvent.CommonChannelDescriptionField;
|
||||
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
|
||||
import org.openhab.core.types.StateOption;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
/**
|
||||
* Tests for {@link BaseDynamicStateDescriptionProvider}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
class BaseDynamicStateDescriptionProviderTest {
|
||||
|
||||
private static final ThingTypeUID THING_TYPE_UID = new ThingTypeUID("binding:type");
|
||||
private static final ThingUID THING_UID = new ThingUID(THING_TYPE_UID, "id");
|
||||
private static final ChannelUID CHANNEL_UID = new ChannelUID(THING_UID, "channel");
|
||||
|
||||
@Mock
|
||||
EventPublisher mockEventPublisher;
|
||||
|
||||
@Mock
|
||||
ItemChannelLinkRegistry mockItemChannelLinkRegistry;
|
||||
|
||||
class TestBaseDynamicStateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
|
||||
|
||||
public TestBaseDynamicStateDescriptionProvider() {
|
||||
this.bundleContext = mock(BundleContext.class);
|
||||
this.eventPublisher = mockEventPublisher;
|
||||
this.itemChannelLinkRegistry = mockItemChannelLinkRegistry;
|
||||
}
|
||||
};
|
||||
|
||||
private BaseDynamicStateDescriptionProvider subject;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
when(mockItemChannelLinkRegistry.getLinkedItemNames(CHANNEL_UID)).thenReturn(Set.of("item1", "item2"));
|
||||
|
||||
subject = new TestBaseDynamicStateDescriptionProvider();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setStatePatternPublishesEvent() {
|
||||
subject.setStatePattern(CHANNEL_UID, "%s");
|
||||
|
||||
ArgumentCaptor<Event> capture = ArgumentCaptor.forClass(Event.class);
|
||||
verify(mockEventPublisher, times(1)).post(capture.capture());
|
||||
|
||||
Event event = capture.getValue();
|
||||
assertTrue(event instanceof ChannelDescriptionChangedEvent);
|
||||
ChannelDescriptionChangedEvent cdce = (ChannelDescriptionChangedEvent) event;
|
||||
assertEquals(CommonChannelDescriptionField.PATTERN, cdce.getField());
|
||||
|
||||
// check the event is not published again
|
||||
subject.setStatePattern(CHANNEL_UID, "%s");
|
||||
|
||||
verify(mockEventPublisher, times(1)).post(capture.capture());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setStateOptionsPublishesEvent() {
|
||||
subject.setStateOptions(CHANNEL_UID, List.of(new StateOption("offline", "Offline")));
|
||||
|
||||
ArgumentCaptor<Event> capture = ArgumentCaptor.forClass(Event.class);
|
||||
verify(mockEventPublisher, times(1)).post(capture.capture());
|
||||
|
||||
Event event = capture.getValue();
|
||||
assertTrue(event instanceof ChannelDescriptionChangedEvent);
|
||||
ChannelDescriptionChangedEvent cdce = (ChannelDescriptionChangedEvent) event;
|
||||
assertEquals(CommonChannelDescriptionField.STATE_OPTIONS, cdce.getField());
|
||||
|
||||
// check the event is not published again
|
||||
subject.setStateOptions(CHANNEL_UID, List.of(new StateOption("offline", "Offline")));
|
||||
|
||||
verify(mockEventPublisher, times(1)).post(capture.capture());
|
||||
}
|
||||
}
|
||||
+206
-16
@@ -14,10 +14,14 @@ package org.openhab.core.thing.events;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
|
||||
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
@@ -31,7 +35,12 @@ import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
|
||||
import org.openhab.core.thing.dto.ThingDTOMapper;
|
||||
import org.openhab.core.thing.events.ChannelDescriptionChangedEvent.CommonChannelDescriptionField;
|
||||
import org.openhab.core.thing.events.ThingEventFactory.ChannelDescriptionChangedEventPayloadBean;
|
||||
import org.openhab.core.thing.events.ThingEventFactory.ChannelDescriptionPatternPayloadBean;
|
||||
import org.openhab.core.thing.events.ThingEventFactory.ChannelDescriptionStateOptionsPayloadBean;
|
||||
import org.openhab.core.thing.events.ThingEventFactory.TriggerEventPayloadBean;
|
||||
import org.openhab.core.types.StateOption;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
@@ -39,12 +48,18 @@ import com.google.gson.Gson;
|
||||
* {@link ThingEventFactoryTests} tests the {@link ThingEventFactory}.
|
||||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
* @author Christoph Weitkamp - Added ChannelStateDescriptionChangedEvent
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ThingEventFactoryTest {
|
||||
private static final Gson JSONCONVERTER = new Gson();
|
||||
|
||||
private static final ThingStatusInfo THING_STATUS_INFO = ThingStatusInfoBuilder
|
||||
.create(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR).withDescription("Some description")
|
||||
.build();
|
||||
|
||||
private final ThingEventFactory factory = new ThingEventFactory();
|
||||
|
||||
private static final ThingTypeUID THING_TYPE_UID = new ThingTypeUID("binding:type");
|
||||
private static final ThingUID THING_UID = new ThingUID(THING_TYPE_UID, "id");
|
||||
private static final Thing THING = ThingBuilder.create(THING_TYPE_UID, THING_UID).build();
|
||||
@@ -54,10 +69,35 @@ public class ThingEventFactoryTest {
|
||||
private static final String THING_ADDED_EVENT_TOPIC = ThingEventFactory.THING_ADDED_EVENT_TOPIC
|
||||
.replace("{thingUID}", THING_UID.getAsString());
|
||||
|
||||
private static final String THING_STATUS_EVENT_PAYLOAD = new Gson().toJson(THING_STATUS_INFO);
|
||||
private static final String THING_ADDED_EVENT_PAYLOAD = new Gson().toJson(ThingDTOMapper.map(THING));
|
||||
private static final String THING_STATUS_EVENT_PAYLOAD = JSONCONVERTER.toJson(THING_STATUS_INFO);
|
||||
private static final String THING_ADDED_EVENT_PAYLOAD = JSONCONVERTER.toJson(ThingDTOMapper.map(THING));
|
||||
|
||||
private static final ChannelUID CHANNEL_UID = new ChannelUID(THING_UID, "channel");
|
||||
private static final String CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC = ThingEventFactory.CHANNEL_DESCRIPTION_CHANGED_TOPIC
|
||||
.replace("{channelUID}", CHANNEL_UID.getAsString());
|
||||
private static final String CHANNEL_DESCRIPTION_PATTERN_PAYLOAD = JSONCONVERTER
|
||||
.toJson(new ChannelDescriptionPatternPayloadBean("%s"));
|
||||
private static final String CHANNEL_DESCRIPTION_OLD_PATTERN_PAYLOAD = JSONCONVERTER
|
||||
.toJson(new ChannelDescriptionPatternPayloadBean("%unit%"));
|
||||
private static final String CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_ONLY_NEW_VALUE = JSONCONVERTER
|
||||
.toJson(new ChannelDescriptionChangedEventPayloadBean(CommonChannelDescriptionField.PATTERN,
|
||||
CHANNEL_UID.getAsString(), Set.of("item1", "item2"), CHANNEL_DESCRIPTION_PATTERN_PAYLOAD, null));
|
||||
private static final String CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_NEW_AND_OLD_VALUE = JSONCONVERTER
|
||||
.toJson(new ChannelDescriptionChangedEventPayloadBean(CommonChannelDescriptionField.PATTERN,
|
||||
CHANNEL_UID.getAsString(), Set.of("item1", "item2"), CHANNEL_DESCRIPTION_PATTERN_PAYLOAD,
|
||||
CHANNEL_DESCRIPTION_OLD_PATTERN_PAYLOAD));
|
||||
private static final String CHANNEL_DESCRIPTION_STATE_OPTIONS_PAYLOAD = JSONCONVERTER
|
||||
.toJson(new ChannelDescriptionStateOptionsPayloadBean(List.of(new StateOption("offline", "Offline"))));
|
||||
private static final String CHANNEL_DESCRIPTION_OLD_STATE_OPTIONS_PAYLOAD = JSONCONVERTER
|
||||
.toJson(new ChannelDescriptionStateOptionsPayloadBean(List.of(new StateOption("online", "Online"))));
|
||||
private static final String CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_ONLY_NEW_OPTIONS = JSONCONVERTER
|
||||
.toJson(new ChannelDescriptionChangedEventPayloadBean(CommonChannelDescriptionField.STATE_OPTIONS,
|
||||
CHANNEL_UID.getAsString(), Set.of("item1", "item2"), CHANNEL_DESCRIPTION_STATE_OPTIONS_PAYLOAD,
|
||||
null));
|
||||
private static final String CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_NEW_AND_OLD_OPTIONS = JSONCONVERTER
|
||||
.toJson(new ChannelDescriptionChangedEventPayloadBean(CommonChannelDescriptionField.STATE_OPTIONS,
|
||||
CHANNEL_UID.getAsString(), Set.of("item1", "item2"), CHANNEL_DESCRIPTION_STATE_OPTIONS_PAYLOAD,
|
||||
CHANNEL_DESCRIPTION_OLD_STATE_OPTIONS_PAYLOAD));
|
||||
private static final String CHANNEL_TRIGGERED_EVENT_TOPIC = ThingEventFactory.CHANNEL_TRIGGERED_EVENT_TOPIC
|
||||
.replace("{channelUID}", CHANNEL_UID.getAsString());
|
||||
private static final String CHANNEL_TRIGGERED_PRESSED_EVENT_PAYLOAD = new Gson()
|
||||
@@ -65,23 +105,17 @@ public class ThingEventFactoryTest {
|
||||
private static final String CHANNEL_TRIGGERED_EMPTY_EVENT_PAYLOAD = new Gson()
|
||||
.toJson(new TriggerEventPayloadBean("", CHANNEL_UID.getAsString()));
|
||||
|
||||
private ThingEventFactory eventFactory;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
eventFactory = new ThingEventFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSupportedEventTypes() {
|
||||
assertThat(eventFactory.getSupportedEventTypes(),
|
||||
assertThat(factory.getSupportedEventTypes(),
|
||||
containsInAnyOrder(ThingStatusInfoEvent.TYPE, ThingStatusInfoChangedEvent.TYPE, ThingAddedEvent.TYPE,
|
||||
ThingRemovedEvent.TYPE, ThingUpdatedEvent.TYPE, ChannelTriggeredEvent.TYPE));
|
||||
ThingRemovedEvent.TYPE, ThingUpdatedEvent.TYPE, ChannelDescriptionChangedEvent.TYPE,
|
||||
ChannelTriggeredEvent.TYPE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEventThingStatusInfoEvent() throws Exception {
|
||||
Event event = eventFactory.createEvent(ThingStatusInfoEvent.TYPE, THING_STATUS_EVENT_TOPIC,
|
||||
Event event = factory.createEvent(ThingStatusInfoEvent.TYPE, THING_STATUS_EVENT_TOPIC,
|
||||
THING_STATUS_EVENT_PAYLOAD, null);
|
||||
|
||||
assertThat(event, is(instanceOf(ThingStatusInfoEvent.class)));
|
||||
@@ -106,7 +140,7 @@ public class ThingEventFactoryTest {
|
||||
|
||||
@Test
|
||||
public void testCreateEventThingAddedEvent() throws Exception {
|
||||
Event event = eventFactory.createEvent(ThingAddedEvent.TYPE, THING_ADDED_EVENT_TOPIC, THING_ADDED_EVENT_PAYLOAD,
|
||||
Event event = factory.createEvent(ThingAddedEvent.TYPE, THING_ADDED_EVENT_TOPIC, THING_ADDED_EVENT_PAYLOAD,
|
||||
null);
|
||||
|
||||
assertThat(event, is(instanceOf(ThingAddedEvent.class)));
|
||||
@@ -129,6 +163,158 @@ public class ThingEventFactoryTest {
|
||||
assertEquals(THING_UID.getAsString(), event.getThing().UID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateChannelDescriptionChangedEventOnlyNewValue() {
|
||||
ChannelDescriptionChangedEvent event = ThingEventFactory
|
||||
.createChannelDescriptionPatternChangedEvent(CHANNEL_UID, Set.of("item1", "item2"), "%s", null);
|
||||
|
||||
assertEquals(ChannelDescriptionChangedEvent.TYPE, event.getType());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC, event.getTopic());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_ONLY_NEW_VALUE, event.getPayload());
|
||||
assertEquals(CommonChannelDescriptionField.PATTERN, event.getField());
|
||||
assertEquals(CHANNEL_UID, event.getChannelUID());
|
||||
assertThat(event.getLinkedItemNames(), hasSize(2));
|
||||
assertEquals(CHANNEL_DESCRIPTION_PATTERN_PAYLOAD, event.getValue());
|
||||
assertNull(event.getOldValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateChannelDescriptionChangedEventNewAndOldValue() {
|
||||
ChannelDescriptionChangedEvent event = ThingEventFactory
|
||||
.createChannelDescriptionPatternChangedEvent(CHANNEL_UID, Set.of("item1", "item2"), "%s", "%unit%");
|
||||
|
||||
assertEquals(ChannelDescriptionChangedEvent.TYPE, event.getType());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC, event.getTopic());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_NEW_AND_OLD_VALUE, event.getPayload());
|
||||
assertEquals(CommonChannelDescriptionField.PATTERN, event.getField());
|
||||
assertEquals(CHANNEL_UID, event.getChannelUID());
|
||||
assertThat(event.getLinkedItemNames(), hasSize(2));
|
||||
assertEquals(CHANNEL_DESCRIPTION_PATTERN_PAYLOAD, event.getValue());
|
||||
assertEquals(CHANNEL_DESCRIPTION_OLD_PATTERN_PAYLOAD, event.getOldValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEventChannelDescriptionChangedEventOnlyNewValue() throws Exception {
|
||||
Event event = factory.createEvent(ChannelDescriptionChangedEvent.TYPE, CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC,
|
||||
CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_ONLY_NEW_VALUE, null);
|
||||
|
||||
assertThat(event, is(instanceOf(ChannelDescriptionChangedEvent.class)));
|
||||
ChannelDescriptionChangedEvent triggeredEvent = (ChannelDescriptionChangedEvent) event;
|
||||
assertEquals(ChannelDescriptionChangedEvent.TYPE, triggeredEvent.getType());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC, triggeredEvent.getTopic());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_ONLY_NEW_VALUE, triggeredEvent.getPayload());
|
||||
assertEquals(CommonChannelDescriptionField.PATTERN, triggeredEvent.getField());
|
||||
assertEquals(CHANNEL_UID, triggeredEvent.getChannelUID());
|
||||
assertThat(triggeredEvent.getLinkedItemNames(), hasSize(2));
|
||||
assertEquals(CHANNEL_DESCRIPTION_PATTERN_PAYLOAD, triggeredEvent.getValue());
|
||||
assertNull(triggeredEvent.getOldValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEventChannelDescriptionChangedEventNewAndOldValue() throws Exception {
|
||||
Event event = factory.createEvent(ChannelDescriptionChangedEvent.TYPE, CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC,
|
||||
CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_NEW_AND_OLD_VALUE, null);
|
||||
|
||||
assertThat(event, is(instanceOf(ChannelDescriptionChangedEvent.class)));
|
||||
ChannelDescriptionChangedEvent triggeredEvent = (ChannelDescriptionChangedEvent) event;
|
||||
assertEquals(ChannelDescriptionChangedEvent.TYPE, triggeredEvent.getType());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC, triggeredEvent.getTopic());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_NEW_AND_OLD_VALUE, triggeredEvent.getPayload());
|
||||
assertEquals(CommonChannelDescriptionField.PATTERN, triggeredEvent.getField());
|
||||
assertEquals(CHANNEL_UID, triggeredEvent.getChannelUID());
|
||||
assertThat(triggeredEvent.getLinkedItemNames(), hasSize(2));
|
||||
assertEquals(CHANNEL_DESCRIPTION_PATTERN_PAYLOAD, triggeredEvent.getValue());
|
||||
assertEquals(CHANNEL_DESCRIPTION_OLD_PATTERN_PAYLOAD, triggeredEvent.getOldValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Test
|
||||
public void testCreateChannelDescriptionChangedEventOnlyNewOptions() {
|
||||
Set<String> itemNames = Set.of("item1", "item2");
|
||||
List<StateOption> options = List.of(new StateOption("offline", "Offline"));
|
||||
ChannelDescriptionChangedEvent event = ThingEventFactory
|
||||
.createChannelDescriptionStateOptionsChangedEvent(CHANNEL_UID, itemNames, options, null);
|
||||
|
||||
assertEquals(ChannelDescriptionChangedEvent.TYPE, event.getType());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC, event.getTopic());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_ONLY_NEW_OPTIONS, event.getPayload());
|
||||
assertEquals(CommonChannelDescriptionField.STATE_OPTIONS, event.getField());
|
||||
assertEquals(CHANNEL_UID, event.getChannelUID());
|
||||
assertEquals(itemNames, event.getLinkedItemNames());
|
||||
assertEquals(CHANNEL_DESCRIPTION_STATE_OPTIONS_PAYLOAD, event.getValue());
|
||||
assertEquals(options,
|
||||
JSONCONVERTER.fromJson(event.getValue(), ChannelDescriptionStateOptionsPayloadBean.class).options);
|
||||
assertNull(event.getOldValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Test
|
||||
public void testCreateEventChannelDescriptionChangedEventOnlyNewOptions() throws Exception {
|
||||
List<StateOption> options = List.of(new StateOption("offline", "Offline"));
|
||||
Event event = factory.createEvent(ChannelDescriptionChangedEvent.TYPE, CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC,
|
||||
CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_ONLY_NEW_OPTIONS, null);
|
||||
|
||||
assertThat(event, is(instanceOf(ChannelDescriptionChangedEvent.class)));
|
||||
ChannelDescriptionChangedEvent triggeredEvent = (ChannelDescriptionChangedEvent) event;
|
||||
assertEquals(ChannelDescriptionChangedEvent.TYPE, triggeredEvent.getType());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC, triggeredEvent.getTopic());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_ONLY_NEW_OPTIONS, triggeredEvent.getPayload());
|
||||
assertEquals(CommonChannelDescriptionField.STATE_OPTIONS, triggeredEvent.getField());
|
||||
assertEquals(CHANNEL_UID, triggeredEvent.getChannelUID());
|
||||
assertEquals(Set.of("item1", "item2"), triggeredEvent.getLinkedItemNames());
|
||||
assertEquals(CHANNEL_DESCRIPTION_STATE_OPTIONS_PAYLOAD, triggeredEvent.getValue());
|
||||
assertEquals(options, JSONCONVERTER.fromJson(triggeredEvent.getValue(),
|
||||
ChannelDescriptionStateOptionsPayloadBean.class).options);
|
||||
assertNull(triggeredEvent.getOldValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Test
|
||||
public void testCreateChannelDescriptionChangedEventOldAndNewOptions() {
|
||||
Set<String> itemNames = Set.of("item1", "item2");
|
||||
List<StateOption> options = List.of(new StateOption("offline", "Offline"));
|
||||
List<StateOption> oldOptions = List.of(new StateOption("online", "Online"));
|
||||
ChannelDescriptionChangedEvent event = ThingEventFactory
|
||||
.createChannelDescriptionStateOptionsChangedEvent(CHANNEL_UID, itemNames, options, oldOptions);
|
||||
|
||||
assertEquals(ChannelDescriptionChangedEvent.TYPE, event.getType());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC, event.getTopic());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_NEW_AND_OLD_OPTIONS, event.getPayload());
|
||||
assertEquals(CommonChannelDescriptionField.STATE_OPTIONS, event.getField());
|
||||
assertEquals(CHANNEL_UID, event.getChannelUID());
|
||||
assertEquals(itemNames, event.getLinkedItemNames());
|
||||
assertEquals(CHANNEL_DESCRIPTION_STATE_OPTIONS_PAYLOAD, event.getValue());
|
||||
assertEquals(options,
|
||||
JSONCONVERTER.fromJson(event.getValue(), ChannelDescriptionStateOptionsPayloadBean.class).options);
|
||||
assertEquals(CHANNEL_DESCRIPTION_OLD_STATE_OPTIONS_PAYLOAD, event.getOldValue());
|
||||
assertEquals(oldOptions,
|
||||
JSONCONVERTER.fromJson(event.getOldValue(), ChannelDescriptionStateOptionsPayloadBean.class).options);
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@Test
|
||||
public void testCreateEventChannelDescriptionChangedEventOldAndNewOptions() throws Exception {
|
||||
List<StateOption> options = List.of(new StateOption("offline", "Offline"));
|
||||
List<StateOption> oldOptions = List.of(new StateOption("online", "Online"));
|
||||
Event event = factory.createEvent(ChannelDescriptionChangedEvent.TYPE, CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC,
|
||||
CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_NEW_AND_OLD_OPTIONS, null);
|
||||
|
||||
assertThat(event, is(instanceOf(ChannelDescriptionChangedEvent.class)));
|
||||
ChannelDescriptionChangedEvent triggeredEvent = (ChannelDescriptionChangedEvent) event;
|
||||
assertEquals(ChannelDescriptionChangedEvent.TYPE, triggeredEvent.getType());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_TOPIC, triggeredEvent.getTopic());
|
||||
assertEquals(CHANNEL_DESCRIPTION_CHANGED_EVENT_PAYLOAD_NEW_AND_OLD_OPTIONS, triggeredEvent.getPayload());
|
||||
assertEquals(CommonChannelDescriptionField.STATE_OPTIONS, triggeredEvent.getField());
|
||||
assertEquals(CHANNEL_UID, triggeredEvent.getChannelUID());
|
||||
assertEquals(Set.of("item1", "item2"), triggeredEvent.getLinkedItemNames());
|
||||
assertEquals(CHANNEL_DESCRIPTION_STATE_OPTIONS_PAYLOAD, triggeredEvent.getValue());
|
||||
assertEquals(options, JSONCONVERTER.fromJson(triggeredEvent.getValue(),
|
||||
ChannelDescriptionStateOptionsPayloadBean.class).options);
|
||||
assertEquals(CHANNEL_DESCRIPTION_OLD_STATE_OPTIONS_PAYLOAD, triggeredEvent.getOldValue());
|
||||
assertEquals(oldOptions, JSONCONVERTER.fromJson(triggeredEvent.getOldValue(),
|
||||
ChannelDescriptionStateOptionsPayloadBean.class).options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTriggerPressedEvent() {
|
||||
ChannelTriggeredEvent event = ThingEventFactory.createTriggerEvent(CommonTriggerEvents.PRESSED, CHANNEL_UID);
|
||||
@@ -138,11 +324,12 @@ public class ThingEventFactoryTest {
|
||||
assertEquals(CHANNEL_TRIGGERED_PRESSED_EVENT_PAYLOAD, event.getPayload());
|
||||
assertNotNull(event.getEvent());
|
||||
assertEquals(CommonTriggerEvents.PRESSED, event.getEvent());
|
||||
assertEquals(CHANNEL_UID, event.getChannel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEventChannelTriggeredPressedEvent() throws Exception {
|
||||
Event event = eventFactory.createEvent(ChannelTriggeredEvent.TYPE, CHANNEL_TRIGGERED_EVENT_TOPIC,
|
||||
Event event = factory.createEvent(ChannelTriggeredEvent.TYPE, CHANNEL_TRIGGERED_EVENT_TOPIC,
|
||||
CHANNEL_TRIGGERED_PRESSED_EVENT_PAYLOAD, null);
|
||||
|
||||
assertThat(event, is(instanceOf(ChannelTriggeredEvent.class)));
|
||||
@@ -152,6 +339,7 @@ public class ThingEventFactoryTest {
|
||||
assertEquals(CHANNEL_TRIGGERED_PRESSED_EVENT_PAYLOAD, triggeredEvent.getPayload());
|
||||
assertNotNull(triggeredEvent.getEvent());
|
||||
assertEquals(CommonTriggerEvents.PRESSED, triggeredEvent.getEvent());
|
||||
assertEquals(CHANNEL_UID, triggeredEvent.getChannel());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -163,11 +351,12 @@ public class ThingEventFactoryTest {
|
||||
assertEquals(CHANNEL_TRIGGERED_EMPTY_EVENT_PAYLOAD, event.getPayload());
|
||||
assertNotNull(event.getEvent());
|
||||
assertEquals("", event.getEvent());
|
||||
assertEquals(CHANNEL_UID, event.getChannel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEventChannelTriggeredEmptyEvent() throws Exception {
|
||||
Event event = eventFactory.createEvent(ChannelTriggeredEvent.TYPE, CHANNEL_TRIGGERED_EVENT_TOPIC,
|
||||
Event event = factory.createEvent(ChannelTriggeredEvent.TYPE, CHANNEL_TRIGGERED_EVENT_TOPIC,
|
||||
CHANNEL_TRIGGERED_EMPTY_EVENT_PAYLOAD, null);
|
||||
|
||||
assertThat(event, is(instanceOf(ChannelTriggeredEvent.class)));
|
||||
@@ -177,5 +366,6 @@ public class ThingEventFactoryTest {
|
||||
assertEquals(CHANNEL_TRIGGERED_EMPTY_EVENT_PAYLOAD, triggeredEvent.getPayload());
|
||||
assertNotNull(triggeredEvent.getEvent());
|
||||
assertEquals("", triggeredEvent.getEvent());
|
||||
assertEquals(CHANNEL_UID, triggeredEvent.getChannel());
|
||||
}
|
||||
}
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.link.events;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.link.ItemChannelLink;
|
||||
import org.openhab.core.thing.link.dto.ItemChannelLinkDTO;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* {@link LinkEventFactoryTests} tests the {@link LinkEventFactory}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LinkEventFactoryTest {
|
||||
private static final Gson JSONCONVERTER = new Gson();
|
||||
|
||||
private final LinkEventFactory factory = new LinkEventFactory();
|
||||
|
||||
private static final ItemChannelLink LINK = new ItemChannelLink("item", new ChannelUID("a:b:c:d"));
|
||||
private static final ItemChannelLinkDTO LINK_DTO = new ItemChannelLinkDTO(LINK.getItemName(),
|
||||
LINK.getLinkedUID().toString(), LINK.getConfiguration().getProperties());
|
||||
|
||||
private static final String LINK_EVENT_PAYLOAD = JSONCONVERTER.toJson(LINK_DTO);
|
||||
private static final String LINK_ADDED_EVENT_TOPIC = LinkEventFactory.LINK_ADDED_EVENT_TOPIC.replace("{linkID}",
|
||||
LINK.getItemName() + "-" + LINK.getLinkedUID().toString());
|
||||
private static final String LINK_REMOVED_EVENT_TOPIC = LinkEventFactory.LINK_REMOVED_EVENT_TOPIC.replace("{linkID}",
|
||||
LINK.getItemName() + "-" + LINK.getLinkedUID().toString());
|
||||
|
||||
@Test
|
||||
public void testCreateItemChannelLinkAddedEvent() {
|
||||
ItemChannelLinkAddedEvent event = LinkEventFactory.createItemChannelLinkAddedEvent(LINK);
|
||||
|
||||
assertEquals(ItemChannelLinkAddedEvent.TYPE, event.getType());
|
||||
assertEquals(LINK_ADDED_EVENT_TOPIC, event.getTopic());
|
||||
assertEquals(LINK_EVENT_PAYLOAD, event.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEventItemChannelLinkAddedEvent() throws Exception {
|
||||
Event event = factory.createEvent(ItemChannelLinkAddedEvent.TYPE, LINK_ADDED_EVENT_TOPIC, LINK_EVENT_PAYLOAD,
|
||||
null);
|
||||
|
||||
assertThat(event, is(instanceOf(ItemChannelLinkAddedEvent.class)));
|
||||
ItemChannelLinkAddedEvent triggeredEvent = (ItemChannelLinkAddedEvent) event;
|
||||
assertEquals(ItemChannelLinkAddedEvent.TYPE, triggeredEvent.getType());
|
||||
assertEquals(LINK_ADDED_EVENT_TOPIC, triggeredEvent.getTopic());
|
||||
assertEquals(LINK_EVENT_PAYLOAD, triggeredEvent.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateItemChannelLinkRemovedEvent() {
|
||||
ItemChannelLinkRemovedEvent event = LinkEventFactory.createItemChannelLinkRemovedEvent(LINK);
|
||||
|
||||
assertEquals(ItemChannelLinkRemovedEvent.TYPE, event.getType());
|
||||
assertEquals(LINK_REMOVED_EVENT_TOPIC, event.getTopic());
|
||||
assertEquals(LINK_EVENT_PAYLOAD, event.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEventItemChannelLinkRemovedEvent() throws Exception {
|
||||
Event event = factory.createEvent(ItemChannelLinkRemovedEvent.TYPE, LINK_REMOVED_EVENT_TOPIC,
|
||||
LINK_EVENT_PAYLOAD, null);
|
||||
|
||||
assertThat(event, is(instanceOf(ItemChannelLinkRemovedEvent.class)));
|
||||
ItemChannelLinkRemovedEvent triggeredEvent = (ItemChannelLinkRemovedEvent) event;
|
||||
assertEquals(ItemChannelLinkRemovedEvent.TYPE, triggeredEvent.getType());
|
||||
assertEquals(LINK_REMOVED_EVENT_TOPIC, triggeredEvent.getTopic());
|
||||
assertEquals(LINK_EVENT_PAYLOAD, triggeredEvent.getPayload());
|
||||
}
|
||||
}
|
||||
@@ -89,6 +89,6 @@ public class CommandOption {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CommandOption [command=" + command + ", label=" + label + "]";
|
||||
return String.format("CommandOption [command=%s, label=%s]", command, label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,6 @@ public final class StateOption {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StateOption [value=" + value + ", label=" + label + "]";
|
||||
return String.format("StateOption [value=%s, label=%s]", value, label);
|
||||
}
|
||||
}
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.events;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventFilter;
|
||||
import org.openhab.core.events.EventSubscriber;
|
||||
import org.openhab.core.test.java.JavaOSGiTest;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingFactory;
|
||||
import org.openhab.core.thing.type.ThingType;
|
||||
import org.openhab.core.thing.type.ThingTypeBuilder;
|
||||
|
||||
/**
|
||||
* Event Tests for {@link ThingRegistry}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ThingEventOSGiTest extends JavaOSGiTest {
|
||||
|
||||
class ThingEventSubscriber implements EventSubscriber {
|
||||
|
||||
private @Nullable Event lastReceivedEvent;
|
||||
|
||||
@Override
|
||||
public Set<String> getSubscribedEventTypes() {
|
||||
return Set.of(ThingAddedEvent.TYPE, ThingUpdatedEvent.TYPE, ThingRemovedEvent.TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable EventFilter getEventFilter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(Event event) {
|
||||
lastReceivedEvent = event;
|
||||
}
|
||||
|
||||
public @Nullable Event getLastReceivedEvent() {
|
||||
return lastReceivedEvent;
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
registerVolatileStorageService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThingEventsAreSent() {
|
||||
ThingRegistry thingRegistry = getService(ThingRegistry.class);
|
||||
|
||||
ThingEventSubscriber eventSubscriber = new ThingEventSubscriber();
|
||||
registerService(eventSubscriber);
|
||||
|
||||
ThingType thingType = ThingTypeBuilder.instance("bindingId", "thingTypeId", "label").build();
|
||||
ThingUID thingUID = new ThingUID(thingType.getUID(), "thingId");
|
||||
Configuration configuration = new Configuration();
|
||||
Thing thing = ThingFactory.createThing(thingType, thingUID, configuration);
|
||||
|
||||
thingRegistry.add(thing);
|
||||
waitFor(() -> eventSubscriber.getLastReceivedEvent() != null);
|
||||
waitForAssert(() -> assertThat(eventSubscriber.getLastReceivedEvent().getType(), is(ThingAddedEvent.TYPE)));
|
||||
assertThat(eventSubscriber.getLastReceivedEvent().getTopic(),
|
||||
is(ThingEventFactory.THING_ADDED_EVENT_TOPIC.replace("{thingUID}", thingUID.getAsString())));
|
||||
|
||||
thingRegistry.update(thing);
|
||||
waitForAssert(() -> assertThat(eventSubscriber.getLastReceivedEvent().getType(), is(ThingUpdatedEvent.TYPE)));
|
||||
assertThat(eventSubscriber.getLastReceivedEvent().getTopic(),
|
||||
is(ThingEventFactory.THING_UPDATED_EVENT_TOPIC.replace("{thingUID}", thingUID.getAsString())));
|
||||
|
||||
thingRegistry.forceRemove(thing.getUID());
|
||||
waitForAssert(() -> assertThat(eventSubscriber.getLastReceivedEvent().getType(), is(ThingRemovedEvent.TYPE)));
|
||||
assertThat(eventSubscriber.getLastReceivedEvent().getTopic(),
|
||||
is(ThingEventFactory.THING_REMOVED_EVENT_TOPIC.replace("{thingUID}", thingUID.getAsString())));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user