Add null annotations to providers and ThingManager (#1412)

* Add null annotations to providers and ThingManager

Signed-off-by: Wouter Born <github@maindrain.net>
pull/1421/head
Wouter Born 2020-04-11 08:29:12 +02:00 committed by GitHub
parent 017532e2d4
commit fb7a7ac421
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 561 additions and 585 deletions

View File

@ -17,6 +17,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.automation.Rule; import org.openhab.core.automation.Rule;
import org.openhab.core.automation.RuleProvider; import org.openhab.core.automation.RuleProvider;
import org.openhab.core.common.registry.ProviderChangeListener; import org.openhab.core.common.registry.ProviderChangeListener;
@ -28,6 +29,7 @@ import org.osgi.service.component.annotations.Component;
* *
* @author Simon Merschjohann - Initial contribution * @author Simon Merschjohann - Initial contribution
*/ */
@NonNullByDefault
@Component(immediate = true, service = { ScriptedRuleProvider.class, RuleProvider.class }) @Component(immediate = true, service = { ScriptedRuleProvider.class, RuleProvider.class })
public class ScriptedRuleProvider implements RuleProvider { public class ScriptedRuleProvider implements RuleProvider {
private final Collection<ProviderChangeListener<Rule>> listeners = new ArrayList<>(); private final Collection<ProviderChangeListener<Rule>> listeners = new ArrayList<>();

View File

@ -23,6 +23,8 @@ import java.util.stream.Stream;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.Visibility; import org.openhab.core.automation.Visibility;
import org.openhab.core.automation.module.script.ScriptEngineFactory; import org.openhab.core.automation.module.script.ScriptEngineFactory;
import org.openhab.core.automation.module.script.internal.handler.AbstractScriptModuleHandler; import org.openhab.core.automation.module.script.internal.handler.AbstractScriptModuleHandler;
@ -51,6 +53,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Scott Rushworth - Initial contribution * @author Scott Rushworth - Initial contribution
*/ */
@NonNullByDefault
@Component @Component
public class ScriptModuleTypeProvider implements ModuleTypeProvider { public class ScriptModuleTypeProvider implements ModuleTypeProvider {
@ -59,7 +62,7 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public ModuleType getModuleType(String UID, Locale locale) { public @Nullable ModuleType getModuleType(String UID, @Nullable Locale locale) {
if (ScriptActionHandler.TYPE_ID.equals(UID)) { if (ScriptActionHandler.TYPE_ID.equals(UID)) {
return getScriptActionType(locale); return getScriptActionType(locale);
} else if (ScriptConditionHandler.TYPE_ID.equals(UID)) { } else if (ScriptConditionHandler.TYPE_ID.equals(UID)) {
@ -69,7 +72,7 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
} }
} }
private ModuleType getScriptActionType(Locale locale) { private @Nullable ModuleType getScriptActionType(@Nullable Locale locale) {
if (parameterOptions.isEmpty()) { if (parameterOptions.isEmpty()) {
return null; return null;
} else { } else {
@ -82,7 +85,7 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
} }
} }
private ModuleType getScriptConditionType(Locale locale) { private @Nullable ModuleType getScriptConditionType(@Nullable Locale locale) {
if (parameterOptions.isEmpty()) { if (parameterOptions.isEmpty()) {
return null; return null;
} else { } else {
@ -98,7 +101,7 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
* *
* @return a list of {#link ConfigurationDescriptionParameter}s * @return a list of {#link ConfigurationDescriptionParameter}s
*/ */
private List<ConfigDescriptionParameter> getConfigDescriptions(Locale locale) { private List<ConfigDescriptionParameter> getConfigDescriptions(@Nullable Locale locale) {
List<ParameterOption> parameterOptionsList = new ArrayList<>(); List<ParameterOption> parameterOptionsList = new ArrayList<>();
for (Map.Entry<String, String> entry : parameterOptions.entrySet()) { for (Map.Entry<String, String> entry : parameterOptions.entrySet()) {
parameterOptionsList.add(new ParameterOption(entry.getKey(), entry.getValue())); parameterOptionsList.add(new ParameterOption(entry.getKey(), entry.getValue()));
@ -114,8 +117,9 @@ public class ScriptModuleTypeProvider implements ModuleTypeProvider {
} }
@Override @Override
public Collection<ModuleType> getModuleTypes(Locale locale) { public Collection<ModuleType> getModuleTypes(@Nullable Locale locale) {
return Stream.of(getScriptActionType(locale), getScriptConditionType(locale)).collect(Collectors.toList()); return (Collection<ModuleType>) Stream.of(getScriptActionType(locale), getScriptConditionType(locale))
.collect(Collectors.toList());
} }
@Override @Override

View File

@ -12,6 +12,8 @@
*/ */
package org.openhab.core.automation; package org.openhab.core.automation;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.dto.RuleDTO; import org.openhab.core.automation.dto.RuleDTO;
import org.openhab.core.automation.dto.RuleDTOMapper; import org.openhab.core.automation.dto.RuleDTOMapper;
import org.openhab.core.common.registry.AbstractManagedProvider; import org.openhab.core.common.registry.AbstractManagedProvider;
@ -28,6 +30,7 @@ import org.osgi.service.component.annotations.Reference;
* @author Kai Kreuzer - refactored (managed) provider and registry implementation * @author Kai Kreuzer - refactored (managed) provider and registry implementation
* @author Markus Rathgeb - fix mapping between element and persistable element * @author Markus Rathgeb - fix mapping between element and persistable element
*/ */
@NonNullByDefault
@Component(service = { RuleProvider.class, ManagedRuleProvider.class }) @Component(service = { RuleProvider.class, ManagedRuleProvider.class })
public class ManagedRuleProvider extends AbstractManagedProvider<Rule, String, RuleDTO> implements RuleProvider { public class ManagedRuleProvider extends AbstractManagedProvider<Rule, String, RuleDTO> implements RuleProvider {
@ -47,7 +50,7 @@ public class ManagedRuleProvider extends AbstractManagedProvider<Rule, String, R
} }
@Override @Override
protected Rule toElement(String key, RuleDTO persistableElement) { protected @Nullable Rule toElement(String key, RuleDTO persistableElement) {
return RuleDTOMapper.map(persistableElement); return RuleDTOMapper.map(persistableElement);
} }

View File

@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.parser.Parser; import org.openhab.core.automation.parser.Parser;
@ -49,7 +50,7 @@ import org.slf4j.LoggerFactory;
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@NonNullByDefault @NonNullByDefault
public abstract class AbstractCommandProvider<E> implements ServiceTrackerCustomizer { public abstract class AbstractCommandProvider<@NonNull E> implements ServiceTrackerCustomizer {
protected final Logger logger = LoggerFactory.getLogger(AbstractCommandProvider.class); protected final Logger logger = LoggerFactory.getLogger(AbstractCommandProvider.class);

View File

@ -20,6 +20,8 @@ import java.net.URL;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.Rule; import org.openhab.core.automation.Rule;
import org.openhab.core.automation.RuleRegistry; import org.openhab.core.automation.RuleRegistry;
import org.openhab.core.automation.parser.Parser; import org.openhab.core.automation.parser.Parser;
@ -42,6 +44,7 @@ import org.osgi.framework.ServiceReference;
* @author Ana Dimova - Initial contribution * @author Ana Dimova - Initial contribution
* @author Kai Kreuzer - refactored (managed) provider and registry implementation * @author Kai Kreuzer - refactored (managed) provider and registry implementation
*/ */
@NonNullByDefault
public class CommandlineRuleImporter extends AbstractCommandProvider<Rule> { public class CommandlineRuleImporter extends AbstractCommandProvider<Rule> {
private final RuleRegistry ruleRegistry; private final RuleRegistry ruleRegistry;
@ -66,8 +69,8 @@ public class CommandlineRuleImporter extends AbstractCommandProvider<Rule> {
* @see AbstractCommandProvider#addingService(org.osgi.framework.ServiceReference) * @see AbstractCommandProvider#addingService(org.osgi.framework.ServiceReference)
*/ */
@Override @Override
public Object addingService(@SuppressWarnings("rawtypes") ServiceReference reference) { public @Nullable Object addingService(@SuppressWarnings("rawtypes") @Nullable ServiceReference reference) {
if (reference.getProperty(Parser.PARSER_TYPE).equals(Parser.PARSER_RULE)) { if (reference != null && Parser.PARSER_RULE.equals(reference.getProperty(Parser.PARSER_TYPE))) {
return super.addingService(reference); return super.addingService(reference);
} }
return null; return null;

View File

@ -32,6 +32,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.Rule; import org.openhab.core.automation.Rule;
@ -69,7 +70,7 @@ import org.slf4j.LoggerFactory;
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@NonNullByDefault @NonNullByDefault
public abstract class AbstractResourceBundleProvider<E> { public abstract class AbstractResourceBundleProvider<@NonNull E> {
public AbstractResourceBundleProvider(String path) { public AbstractResourceBundleProvider(String path) {
this.path = path; this.path = path;
@ -459,7 +460,7 @@ public abstract class AbstractResourceBundleProvider<E> {
} }
} }
protected void updateWaitingProviders(Parser<E> parser, Bundle bundle, URL url) { protected void updateWaitingProviders(@Nullable Parser<E> parser, Bundle bundle, URL url) {
List<URL> urlList = waitingProviders.get(bundle); List<URL> urlList = waitingProviders.get(bundle);
if (parser == null) { if (parser == null) {
if (urlList == null) { if (urlList == null) {

View File

@ -17,6 +17,7 @@ import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.core.automation.Rule; import org.openhab.core.automation.Rule;
import org.openhab.core.automation.template.TemplateProvider; import org.openhab.core.automation.template.TemplateProvider;
import org.openhab.core.automation.type.ModuleTypeProvider; import org.openhab.core.automation.type.ModuleTypeProvider;
@ -33,7 +34,7 @@ import org.slf4j.LoggerFactory;
* @author Kai Kreuzer - refactored (managed) provider and registry implementation * @author Kai Kreuzer - refactored (managed) provider and registry implementation
* @param <E> * @param <E>
*/ */
public class AutomationResourceBundlesEventQueue<E> implements Runnable { public class AutomationResourceBundlesEventQueue<@NonNull E> implements Runnable {
/** /**
* This field keeps instance of {@link Logger} that is used for logging. * This field keeps instance of {@link Logger} that is used for logging.

View File

@ -20,6 +20,8 @@ import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.ManagedRuleProvider; import org.openhab.core.automation.ManagedRuleProvider;
import org.openhab.core.automation.Rule; import org.openhab.core.automation.Rule;
import org.openhab.core.automation.parser.Parser; import org.openhab.core.automation.parser.Parser;
@ -40,12 +42,13 @@ import org.osgi.framework.Bundle;
* @author Ana Dimova - Initial contribution * @author Ana Dimova - Initial contribution
* @author Kai Kreuzer - refactored (managed) provider and registry implementation * @author Kai Kreuzer - refactored (managed) provider and registry implementation
*/ */
@NonNullByDefault
public class RuleResourceBundleImporter extends AbstractResourceBundleProvider<Rule> { public class RuleResourceBundleImporter extends AbstractResourceBundleProvider<Rule> {
/** /**
* This field holds the reference to the Rule Registry. * This field holds the reference to the Rule Registry.
*/ */
protected ManagedRuleProvider mProvider; protected @Nullable ManagedRuleProvider mProvider;
/** /**
* This constructor is responsible for initializing the path to resources and tracking the managing service of the * This constructor is responsible for initializing the path to resources and tracking the managing service of the

View File

@ -26,6 +26,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.automation.parser.Parser; import org.openhab.core.automation.parser.Parser;
import org.openhab.core.automation.parser.ParsingException; import org.openhab.core.automation.parser.ParsingException;
@ -49,7 +50,7 @@ import org.slf4j.LoggerFactory;
* @author Ana Dimova - Initial contribution * @author Ana Dimova - Initial contribution
*/ */
@NonNullByDefault @NonNullByDefault
public abstract class AbstractFileProvider<E> implements Provider<E> { public abstract class AbstractFileProvider<@NonNull E> implements Provider<E> {
protected static final String CONFIG_PROPERTY_ROOTS = "roots"; protected static final String CONFIG_PROPERTY_ROOTS = "roots";
protected final Logger logger = LoggerFactory.getLogger(AbstractFileProvider.class); protected final Logger logger = LoggerFactory.getLogger(AbstractFileProvider.class);

View File

@ -26,9 +26,10 @@ import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.common.registry.AbstractProvider; import org.openhab.core.common.registry.AbstractProvider;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.items.ActiveItem; import org.openhab.core.items.ActiveItem;
import org.openhab.core.items.GenericItem; import org.openhab.core.items.GenericItem;
import org.openhab.core.items.GroupFunction; import org.openhab.core.items.GroupFunction;
@ -38,9 +39,6 @@ import org.openhab.core.items.ItemFactory;
import org.openhab.core.items.ItemProvider; import org.openhab.core.items.ItemProvider;
import org.openhab.core.items.dto.GroupFunctionDTO; import org.openhab.core.items.dto.GroupFunctionDTO;
import org.openhab.core.items.dto.ItemDTOMapper; import org.openhab.core.items.dto.ItemDTOMapper;
import org.openhab.core.types.StateDescriptionFragment;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.openhab.core.types.StateDescriptionFragmentProvider;
import org.openhab.core.model.core.EventType; import org.openhab.core.model.core.EventType;
import org.openhab.core.model.core.ModelRepository; import org.openhab.core.model.core.ModelRepository;
import org.openhab.core.model.core.ModelRepositoryChangeListener; import org.openhab.core.model.core.ModelRepositoryChangeListener;
@ -52,6 +50,9 @@ import org.openhab.core.model.items.ModelGroupFunction;
import org.openhab.core.model.items.ModelGroupItem; import org.openhab.core.model.items.ModelGroupItem;
import org.openhab.core.model.items.ModelItem; import org.openhab.core.model.items.ModelItem;
import org.openhab.core.model.items.ModelNormalItem; import org.openhab.core.model.items.ModelNormalItem;
import org.openhab.core.types.StateDescriptionFragment;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.openhab.core.types.StateDescriptionFragmentProvider;
import org.osgi.framework.Constants; import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
@ -68,6 +69,7 @@ import org.slf4j.LoggerFactory;
* @author Kai Kreuzer - Initial contribution * @author Kai Kreuzer - Initial contribution
* @author Thomas Eichstaedt-Engelen - Initial contribution * @author Thomas Eichstaedt-Engelen - Initial contribution
*/ */
@NonNullByDefault
@Component(service = { ItemProvider.class, StateDescriptionFragmentProvider.class }, immediate = true) @Component(service = { ItemProvider.class, StateDescriptionFragmentProvider.class }, immediate = true)
public class GenericItemProvider extends AbstractProvider<Item> public class GenericItemProvider extends AbstractProvider<Item>
implements ModelRepositoryChangeListener, ItemProvider, StateDescriptionFragmentProvider { implements ModelRepositoryChangeListener, ItemProvider, StateDescriptionFragmentProvider {
@ -218,7 +220,7 @@ public class GenericItemProvider extends AbstractProvider<Item>
} }
} }
private Item createItemFromModelItem(ModelItem modelItem) { private @Nullable Item createItemFromModelItem(ModelItem modelItem) {
Item item = null; Item item = null;
if (modelItem instanceof ModelGroupItem) { if (modelItem instanceof ModelGroupItem) {
ModelGroupItem modelGroupItem = (ModelGroupItem) modelItem; ModelGroupItem modelGroupItem = (ModelGroupItem) modelItem;
@ -264,7 +266,7 @@ public class GenericItemProvider extends AbstractProvider<Item>
} }
} }
private String extractFormat(String label) { private @Nullable String extractFormat(@Nullable String label) {
if (label == null) { if (label == null) {
return null; return null;
} }
@ -292,7 +294,7 @@ public class GenericItemProvider extends AbstractProvider<Item>
return new GroupItem(modelGroupItem.getName(), baseItem, groupFunction); return new GroupItem(modelGroupItem.getName(), baseItem, groupFunction);
} }
private void dispatchBindingsPerItemType(BindingConfigReader reader, String[] itemTypes) { private void dispatchBindingsPerItemType(@Nullable BindingConfigReader reader, String[] itemTypes) {
for (String modelName : modelRepository.getAllModelNamesOfType("items")) { for (String modelName : modelRepository.getAllModelNamesOfType("items")) {
ItemModel model = (ItemModel) modelRepository.getModel(modelName); ItemModel model = (ItemModel) modelRepository.getModel(modelName);
if (model != null) { if (model != null) {
@ -338,7 +340,7 @@ public class GenericItemProvider extends AbstractProvider<Item>
internalDispatchBindings(null, modelName, item, bindings); internalDispatchBindings(null, modelName, item, bindings);
} }
private void internalDispatchBindings(BindingConfigReader reader, String modelName, Item item, private void internalDispatchBindings(@Nullable BindingConfigReader reader, String modelName, Item item,
EList<ModelBinding> bindings) { EList<ModelBinding> bindings) {
for (ModelBinding binding : bindings) { for (ModelBinding binding : bindings) {
String bindingType = binding.getType(); String bindingType = binding.getType();
@ -492,7 +494,7 @@ public class GenericItemProvider extends AbstractProvider<Item>
* *
* @return An Item instance of type {@code itemType} or null if no item factory for it was found. * @return An Item instance of type {@code itemType} or null if no item factory for it was found.
*/ */
private Item createItemOfType(String itemType, String itemName) { private @Nullable Item createItemOfType(@Nullable String itemType, String itemName) {
if (itemType == null) { if (itemType == null) {
return null; return null;
} }

View File

@ -28,6 +28,24 @@
</dependencies> </dependencies>
<build> <build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerId>eclipse</compilerId>
<compilerArgs>
<!-- Xtend doesn't support type annotations so warn on null analysis issues -->
<!-- See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=506374 -->
<arg>-warn:+nullAnnot(org.eclipse.jdt.annotation.Nullable|org.eclipse.jdt.annotation.NonNull|org.eclipse.jdt.annotation.NonNullByDefault),+inheritNullAnnot,-nullUncheckedConversion,+null,+inheritNullAnnot,+nullAnnotConflict,-nullUncheckedConversion,+nullAnnotRedundant,+nullDereference</arg>
</compilerArgs>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>

View File

@ -20,13 +20,15 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.openhab.core.config.core.Configuration; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.common.registry.AbstractProvider; import org.openhab.core.common.registry.AbstractProvider;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.model.item.BindingConfigParseException;
import org.openhab.core.model.item.BindingConfigReader;
import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.link.ItemChannelLink; import org.openhab.core.thing.link.ItemChannelLink;
import org.openhab.core.thing.link.ItemChannelLinkProvider; import org.openhab.core.thing.link.ItemChannelLinkProvider;
import org.openhab.core.model.item.BindingConfigParseException;
import org.openhab.core.model.item.BindingConfigReader;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
/** /**
@ -35,6 +37,7 @@ import org.osgi.service.component.annotations.Component;
* @author Oliver Libutzki - Initial contribution * @author Oliver Libutzki - Initial contribution
* @author Alex Tugarev - Added parsing of multiple Channel UIDs * @author Alex Tugarev - Added parsing of multiple Channel UIDs
*/ */
@NonNullByDefault
@Component(immediate = true, service = { ItemChannelLinkProvider.class, BindingConfigReader.class }) @Component(immediate = true, service = { ItemChannelLinkProvider.class, BindingConfigReader.class })
public class GenericItemChannelLinkProvider extends AbstractProvider<ItemChannelLink> public class GenericItemChannelLinkProvider extends AbstractProvider<ItemChannelLink>
implements BindingConfigReader, ItemChannelLinkProvider { implements BindingConfigReader, ItemChannelLinkProvider {
@ -48,7 +51,7 @@ public class GenericItemChannelLinkProvider extends AbstractProvider<ItemChannel
*/ */
protected Map<String, Set<String>> contextMap = new ConcurrentHashMap<>(); protected Map<String, Set<String>> contextMap = new ConcurrentHashMap<>();
private Set<String> previousItemNames; private @Nullable Set<String> previousItemNames;
@Override @Override
public String getBindingType() { public String getBindingType() {

View File

@ -12,6 +12,7 @@
*/ */
package org.openhab.core.thing; package org.openhab.core.thing;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.common.registry.DefaultAbstractManagedProvider; import org.openhab.core.common.registry.DefaultAbstractManagedProvider;
import org.openhab.core.storage.StorageService; import org.openhab.core.storage.StorageService;
import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Activate;
@ -28,6 +29,7 @@ import org.osgi.service.component.annotations.Reference;
* @author Dennis Nobel - Integrated Storage * @author Dennis Nobel - Integrated Storage
* @author Michael Grammling - Added dynamic configuration update * @author Michael Grammling - Added dynamic configuration update
*/ */
@NonNullByDefault
@Component(immediate = true, service = { ThingProvider.class, ManagedThingProvider.class }) @Component(immediate = true, service = { ThingProvider.class, ManagedThingProvider.class })
public class ManagedThingProvider extends DefaultAbstractManagedProvider<Thing, ThingUID> implements ThingProvider { public class ManagedThingProvider extends DefaultAbstractManagedProvider<Thing, ThingUID> implements ThingProvider {

View File

@ -12,11 +12,14 @@
*/ */
package org.openhab.core.thing; package org.openhab.core.thing;
import org.eclipse.jdt.annotation.NonNullByDefault;
/** /**
* {@link ThingManager} interface defines methods for managing a {@link Thing}. * {@link ThingManager} interface defines methods for managing a {@link Thing}.
* *
* @author Yordan Zhelev - Initial contribution * @author Yordan Zhelev - Initial contribution
*/ */
@NonNullByDefault
public interface ThingManager { public interface ThingManager {
/** /**

View File

@ -34,6 +34,7 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function; import java.util.function.Function;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.common.SafeCaller; import org.openhab.core.common.SafeCaller;
import org.openhab.core.common.ThreadPoolManager; import org.openhab.core.common.ThreadPoolManager;
@ -120,6 +121,7 @@ import org.slf4j.LoggerFactory;
* @author Christoph Weitkamp - Added preconfigured ChannelGroupBuilder * @author Christoph Weitkamp - Added preconfigured ChannelGroupBuilder
* @author Yordan Zhelev - Added thing disabling mechanism * @author Yordan Zhelev - Added thing disabling mechanism
*/ */
@NonNullByDefault
@Component(immediate = true, service = { ThingTypeMigrationService.class, ThingManager.class }) @Component(immediate = true, service = { ThingTypeMigrationService.class, ThingManager.class })
public class ThingManagerImpl public class ThingManagerImpl
implements ThingManager, ThingTracker, ThingTypeMigrationService, ReadyService.ReadyTracker { implements ThingManager, ThingTracker, ThingTypeMigrationService, ReadyService.ReadyTracker {
@ -135,31 +137,30 @@ public class ThingManagerImpl
private final ScheduledExecutorService scheduler = ThreadPoolManager private final ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(THING_MANAGER_THREADPOOL_NAME); .getScheduledPool(THING_MANAGER_THREADPOOL_NAME);
private EventPublisher eventPublisher;
private CommunicationManager communicationManager;
private ReadyService readyService;
private final List<ThingHandlerFactory> thingHandlerFactories = new CopyOnWriteArrayList<>(); private final List<ThingHandlerFactory> thingHandlerFactories = new CopyOnWriteArrayList<>();
private final Map<ThingUID, ThingHandler> thingHandlers = new ConcurrentHashMap<>(); private final Map<ThingUID, ThingHandler> thingHandlers = new ConcurrentHashMap<>();
private final Map<ThingHandlerFactory, Set<ThingHandler>> thingHandlersByFactory = new HashMap<>(); private final Map<ThingHandlerFactory, Set<ThingHandler>> thingHandlersByFactory = new HashMap<>();
private ThingTypeRegistry thingTypeRegistry; private final Set<Thing> things = new CopyOnWriteArraySet<>();
private ChannelTypeRegistry channelTypeRegistry;
private ChannelGroupTypeRegistry channelGroupTypeRegistry;
private ItemChannelLinkRegistry itemChannelLinkRegistry;
private ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService;
private final Map<ThingUID, Lock> thingLocks = new HashMap<>(); private final Map<ThingUID, Lock> thingLocks = new HashMap<>();
private final Set<ThingUID> thingUpdatedLock = new HashSet<>();
private final Set<String> loadedXmlThingTypes = new CopyOnWriteArraySet<>(); private final Set<String> loadedXmlThingTypes = new CopyOnWriteArraySet<>();
private SafeCaller safeCaller;
private volatile boolean active = false; private BundleResolver bundleResolver;
private StorageService storageService;
private Storage<String> storage; private final ChannelGroupTypeRegistry channelGroupTypeRegistry;
private final ChannelTypeRegistry channelTypeRegistry;
private final CommunicationManager communicationManager;
private final ConfigDescriptionRegistry configDescriptionRegistry;
private final ConfigDescriptionValidator configDescriptionValidator;
private final EventPublisher eventPublisher;
private final ThingTypeRegistry thingTypeRegistry;
private final ItemChannelLinkRegistry itemChannelLinkRegistry;
private final ReadyService readyService;
private final SafeCaller safeCaller;
private final Storage<String> storage;
private final ThingRegistryImpl thingRegistry;
private final ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService;
private final ThingHandlerCallback thingHandlerCallback = new ThingHandlerCallback() { private final ThingHandlerCallback thingHandlerCallback = new ThingHandlerCallback() {
@ -246,9 +247,9 @@ public class ThingManagerImpl
@Override @Override
public void thingUpdated(final Thing thing) { public void thingUpdated(final Thing thing) {
thingUpdatedLock.add(thing.getUID()); thingUpdatedLock.add(thing.getUID());
AccessController.doPrivileged(new PrivilegedAction<Void>() { AccessController.doPrivileged(new PrivilegedAction<@Nullable Void>() {
@Override @Override
public Void run() { public @Nullable Void run() {
Provider<Thing> provider = thingRegistry.getProvider(thing); Provider<Thing> provider = thingRegistry.getProvider(thing);
if (provider == null) { if (provider == null) {
throw new IllegalArgumentException(MessageFormat.format( throw new IllegalArgumentException(MessageFormat.format(
@ -347,20 +348,53 @@ public class ThingManagerImpl
} }
}; };
private ThingRegistryImpl thingRegistry; @Activate
public ThingManagerImpl( //
final @Reference BundleResolver bundleResolver,
final @Reference ChannelGroupTypeRegistry channelGroupTypeRegistry,
final @Reference ChannelTypeRegistry channelTypeRegistry,
final @Reference CommunicationManager communicationManager,
final @Reference ConfigDescriptionRegistry configDescriptionRegistry,
final @Reference ConfigDescriptionValidator configDescriptionValidator,
final @Reference EventPublisher eventPublisher,
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry,
final @Reference ReadyService readyService, //
final @Reference SafeCaller safeCaller, //
final @Reference StorageService storageService, //
final @Reference ThingRegistry thingRegistry,
final @Reference ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService,
final @Reference ThingTypeRegistry thingTypeRegistry) {
this.bundleResolver = bundleResolver;
this.channelGroupTypeRegistry = channelGroupTypeRegistry;
this.channelTypeRegistry = channelTypeRegistry;
this.communicationManager = communicationManager;
this.configDescriptionRegistry = configDescriptionRegistry;
this.configDescriptionValidator = configDescriptionValidator;
this.eventPublisher = eventPublisher;
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
this.readyService = readyService;
this.safeCaller = safeCaller;
this.thingRegistry = (ThingRegistryImpl) thingRegistry;
this.thingStatusInfoI18nLocalizationService = thingStatusInfoI18nLocalizationService;
this.thingTypeRegistry = thingTypeRegistry;
private BundleResolver bundleResolver; readyService.registerTracker(this, new ReadyMarkerFilter().withType(XML_THING_TYPE));
this.thingRegistry.addThingTracker(this);
storage = storageService.getStorage(THING_STATUS_STORAGE_NAME, this.getClass().getClassLoader());
}
private ConfigDescriptionRegistry configDescriptionRegistry; @Deactivate
private ConfigDescriptionValidator configDescriptionValidator; protected synchronized void deactivate(ComponentContext componentContext) {
thingRegistry.removeThingTracker(this);
private final Set<Thing> things = new CopyOnWriteArraySet<>(); for (ThingHandlerFactory factory : thingHandlerFactories) {
removeThingHandlerFactory(factory);
private final Set<ThingUID> thingUpdatedLock = new HashSet<>(); }
readyService.unregisterTracker(this);
}
@Override @Override
public void migrateThingType(final Thing thing, final ThingTypeUID thingTypeUID, public void migrateThingType(final Thing thing, final ThingTypeUID thingTypeUID,
final Configuration configuration) { final @Nullable Configuration configuration) {
final ThingType thingType = thingTypeRegistry.getThingType(thingTypeUID); final ThingType thingType = thingTypeRegistry.getThingType(thingTypeUID);
if (thingType == null) { if (thingType == null) {
throw new IllegalStateException( throw new IllegalStateException(
@ -379,8 +413,12 @@ public class ThingManagerImpl
final ThingHandlerFactory oldThingHandlerFactory = findThingHandlerFactory(thing.getThingTypeUID()); final ThingHandlerFactory oldThingHandlerFactory = findThingHandlerFactory(thing.getThingTypeUID());
if (oldThingHandlerFactory != null) { if (oldThingHandlerFactory != null) {
ThingHandler thingHandler = thing.getHandler(); ThingHandler thingHandler = thing.getHandler();
if (thingHandler != null) {
unregisterAndDisposeHandler(oldThingHandlerFactory, thing, thingHandler); unregisterAndDisposeHandler(oldThingHandlerFactory, thing, thingHandler);
waitUntilHandlerUnregistered(thing, 60 * 1000); waitUntilHandlerUnregistered(thing, 60 * 1000);
} else {
logger.debug("No ThingHandler to dispose for {}", thing.getUID());
}
} else { } else {
logger.debug("No ThingHandlerFactory available that can handle {}", thing.getThingTypeUID()); logger.debug("No ThingHandlerFactory available that can handle {}", thing.getThingTypeUID());
} }
@ -511,7 +549,12 @@ public class ThingManagerImpl
logger.debug("Replacing uninitialized handler for updated thing '{}'", logger.debug("Replacing uninitialized handler for updated thing '{}'",
thing.getThingTypeUID()); thing.getThingTypeUID());
ThingHandlerFactory thingHandlerFactory = getThingHandlerFactory(thing); ThingHandlerFactory thingHandlerFactory = getThingHandlerFactory(thing);
if (thingHandlerFactory != null) {
unregisterHandler(thingHandler.getThing(), thingHandlerFactory); unregisterHandler(thingHandler.getThing(), thingHandlerFactory);
} else {
logger.debug("No ThingHandlerFactory available that can handle {}",
thing.getThingTypeUID());
}
registerAndInitializeHandler(thing, thingHandlerFactory); registerAndInitializeHandler(thing, thingHandlerFactory);
} }
} }
@ -524,16 +567,18 @@ public class ThingManagerImpl
} }
} }
private ThingHandler replaceThing(Thing oldThing, Thing newThing) { private @Nullable ThingHandler replaceThing(@Nullable Thing oldThing, Thing newThing) {
final ThingHandler thingHandler = thingHandlers.get(newThing.getUID()); final ThingHandler thingHandler = thingHandlers.get(newThing.getUID());
if (oldThing != newThing) { if (oldThing != newThing) {
if (oldThing != null) {
this.things.remove(oldThing); this.things.remove(oldThing);
}
this.things.add(newThing); this.things.add(newThing);
} }
return thingHandler; return thingHandler;
} }
private Thing getThing(ThingUID id) { private @Nullable Thing getThing(ThingUID id) {
for (Thing thing : this.things) { for (Thing thing : this.things) {
if (thing.getUID().equals(id)) { if (thing.getUID().equals(id)) {
return thing; return thing;
@ -546,7 +591,7 @@ public class ThingManagerImpl
return thingTypeRegistry.getThingType(thing.getThingTypeUID()); return thingTypeRegistry.getThingType(thing.getThingTypeUID());
} }
private ThingHandlerFactory findThingHandlerFactory(ThingTypeUID thingTypeUID) { private @Nullable ThingHandlerFactory findThingHandlerFactory(ThingTypeUID thingTypeUID) {
for (ThingHandlerFactory factory : thingHandlerFactories) { for (ThingHandlerFactory factory : thingHandlerFactories) {
if (factory.supportsThingType(thingTypeUID)) { if (factory.supportsThingType(thingTypeUID)) {
return factory; return factory;
@ -645,11 +690,9 @@ public class ThingManagerImpl
ThingHandler handler = thing.getHandler(); ThingHandler handler = thing.getHandler();
if (handler == null) { if (handler == null) {
throw new IllegalStateException("Handler should not be null here"); throw new IllegalStateException("Handler should not be null here");
} else {
if (handler.getThing() != thing) {
logger.warn("The model of {} is inconsistent [thing.getHandler().getThing() != thing]",
thing.getUID());
} }
if (handler.getThing() != thing) {
logger.warn("The model of {} is inconsistent [thing.getHandler().getThing() != thing]", thing.getUID());
} }
ThingType thingType = getThingType(thing); ThingType thingType = getThingType(thing);
if (thingType != null) { if (thingType != null) {
@ -659,7 +702,7 @@ public class ThingManagerImpl
if (isInitializable(thing, thingType)) { if (isInitializable(thing, thingType)) {
setThingStatus(thing, buildStatusInfo(ThingStatus.INITIALIZING, ThingStatusDetail.NONE)); setThingStatus(thing, buildStatusInfo(ThingStatus.INITIALIZING, ThingStatusDetail.NONE));
doInitializeHandler(thing.getHandler()); doInitializeHandler(handler);
} else { } else {
logger.debug("Thing '{}' not initializable, check required configuration parameters.", thing.getUID()); logger.debug("Thing '{}' not initializable, check required configuration parameters.", thing.getUID());
setThingStatus(thing, setThingStatus(thing,
@ -670,7 +713,7 @@ public class ThingManagerImpl
} }
} }
private boolean isInitializable(Thing thing, ThingType thingType) { private boolean isInitializable(Thing thing, @Nullable ThingType thingType) {
if (!isComplete(thingType, thing.getUID(), tt -> tt.getConfigDescriptionURI(), thing.getConfiguration())) { if (!isComplete(thingType, thing.getUID(), tt -> tt.getConfigDescriptionURI(), thing.getConfiguration())) {
return false; return false;
} }
@ -696,8 +739,8 @@ public class ThingManagerImpl
* @param configuration the current configuration * @param configuration the current configuration
* @return true if all required configuration parameters are given, false otherwise * @return true if all required configuration parameters are given, false otherwise
*/ */
private <T extends Identifiable<?>> boolean isComplete(T prototype, UID targetUID, private <T extends Identifiable<?>> boolean isComplete(@Nullable T prototype, UID targetUID,
Function<T, URI> configDescriptionURIFunction, Configuration configuration) { Function<T, @Nullable URI> configDescriptionURIFunction, Configuration configuration) {
if (prototype == null) { if (prototype == null) {
logger.debug("Prototype for '{}' is not known, assuming it is initializable", targetUID); logger.debug("Prototype for '{}' is not known, assuming it is initializable", targetUID);
return true; return true;
@ -718,12 +761,8 @@ public class ThingManagerImpl
return propertyKeys.containsAll(requiredParameters); return propertyKeys.containsAll(requiredParameters);
} }
private ConfigDescription resolve(URI configDescriptionURI, Locale locale) { private @Nullable ConfigDescription resolve(@Nullable URI configDescriptionURI, @Nullable Locale locale) {
if (configDescriptionURI == null) { return configDescriptionURI != null
return null;
}
return configDescriptionRegistry != null
? configDescriptionRegistry.getConfigDescription(configDescriptionURI, locale) ? configDescriptionRegistry.getConfigDescription(configDescriptionURI, locale)
: null; : null;
} }
@ -770,9 +809,12 @@ public class ThingManagerImpl
return thing.getBridgeUID() != null; return thing.getBridgeUID() != null;
} }
private Bridge getBridge(ThingUID bridgeUID) { private @Nullable Bridge getBridge(@Nullable ThingUID bridgeUID) {
if (bridgeUID == null) {
return null;
}
Thing bridge = thingRegistry.get(bridgeUID); Thing bridge = thingRegistry.get(bridgeUID);
return isBridge(bridge) ? (Bridge) bridge : null; return bridge instanceof Bridge ? (Bridge) bridge : null;
} }
private void unregisterHandler(Thing thing, ThingHandlerFactory thingHandlerFactory) { private void unregisterHandler(Thing thing, ThingHandlerFactory thingHandlerFactory) {
@ -969,9 +1011,9 @@ public class ThingManagerImpl
@Override @Override
public void run() { public void run() {
try { try {
AccessController.doPrivileged(new PrivilegedAction<Void>() { AccessController.doPrivileged(new PrivilegedAction<@Nullable Void>() {
@Override @Override
public Void run() { public @Nullable Void run() {
thingRegistry.forceRemove(thing.getUID()); thingRegistry.forceRemove(thing.getUID());
return null; return null;
} }
@ -988,33 +1030,12 @@ public class ThingManagerImpl
}); });
} }
@Activate
protected synchronized void activate(ComponentContext componentContext) {
readyService.registerTracker(this, new ReadyMarkerFilter().withType(XML_THING_TYPE));
for (ThingHandlerFactory factory : thingHandlerFactories) {
handleThingHandlerFactoryAddition(getBundleIdentifier(factory));
}
thingRegistry.addThingTracker(this);
active = true;
}
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
protected synchronized void addThingHandlerFactory(ThingHandlerFactory thingHandlerFactory) { protected synchronized void addThingHandlerFactory(ThingHandlerFactory thingHandlerFactory) {
logger.debug("Thing handler factory '{}' added", thingHandlerFactory.getClass().getSimpleName()); logger.debug("Thing handler factory '{}' added", thingHandlerFactory.getClass().getSimpleName());
thingHandlerFactories.add(thingHandlerFactory); thingHandlerFactories.add(thingHandlerFactory);
if (active) {
handleThingHandlerFactoryAddition(getBundleIdentifier(thingHandlerFactory)); handleThingHandlerFactoryAddition(getBundleIdentifier(thingHandlerFactory));
} }
}
@Reference
public void setReadyService(ReadyService readyService) {
this.readyService = readyService;
}
public void unsetReadyService(ReadyService readyService) {
this.readyService = null;
}
@Override @Override
public void onReadyMarkerAdded(ReadyMarker readyMarker) { public void onReadyMarkerAdded(ReadyMarker readyMarker) {
@ -1049,7 +1070,8 @@ public class ThingManagerImpl
return ReadyMarkerUtils.getIdentifier(bundleResolver.resolveBundle(thingHandlerFactory.getClass())); return ReadyMarkerUtils.getIdentifier(bundleResolver.resolveBundle(thingHandlerFactory.getClass()));
} }
private void registerAndInitializeHandler(final Thing thing, final ThingHandlerFactory thingHandlerFactory) { private void registerAndInitializeHandler(final Thing thing,
final @Nullable ThingHandlerFactory thingHandlerFactory) {
if (thingHandlerFactory != null) { if (thingHandlerFactory != null) {
final String identifier = getBundleIdentifier(thingHandlerFactory); final String identifier = getBundleIdentifier(thingHandlerFactory);
if (loadedXmlThingTypes.contains(identifier)) { if (loadedXmlThingTypes.contains(identifier)) {
@ -1066,7 +1088,7 @@ public class ThingManagerImpl
} }
} }
private ThingHandlerFactory getThingHandlerFactory(Thing thing) { private @Nullable ThingHandlerFactory getThingHandlerFactory(Thing thing) {
ThingHandlerFactory thingHandlerFactory = findThingHandlerFactory(thing.getThingTypeUID()); ThingHandlerFactory thingHandlerFactory = findThingHandlerFactory(thing.getThingTypeUID());
if (thingHandlerFactory != null) { if (thingHandlerFactory != null) {
return thingHandlerFactory; return thingHandlerFactory;
@ -1076,23 +1098,11 @@ public class ThingManagerImpl
return null; return null;
} }
@Deactivate
protected synchronized void deactivate(ComponentContext componentContext) {
active = false;
thingRegistry.removeThingTracker(this);
for (ThingHandlerFactory factory : thingHandlerFactories) {
removeThingHandlerFactory(factory);
}
readyService.unregisterTracker(this);
}
protected synchronized void removeThingHandlerFactory(ThingHandlerFactory thingHandlerFactory) { protected synchronized void removeThingHandlerFactory(ThingHandlerFactory thingHandlerFactory) {
logger.debug("Thing handler factory '{}' removed", thingHandlerFactory.getClass().getSimpleName()); logger.debug("Thing handler factory '{}' removed", thingHandlerFactory.getClass().getSimpleName());
thingHandlerFactories.remove(thingHandlerFactory); thingHandlerFactories.remove(thingHandlerFactory);
if (active) {
handleThingHandlerFactoryRemoval(thingHandlerFactory); handleThingHandlerFactoryRemoval(thingHandlerFactory);
} }
}
private void handleThingHandlerFactoryRemoval(ThingHandlerFactory thingHandlerFactory) { private void handleThingHandlerFactoryRemoval(ThingHandlerFactory thingHandlerFactory) {
final Set<ThingHandler> handlers; final Set<ThingHandler> handlers;
@ -1117,53 +1127,8 @@ public class ThingManagerImpl
return thingLocks.get(thingUID); return thingLocks.get(thingUID);
} }
@Reference
protected void setEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
@Reference
protected void setThingRegistry(ThingRegistry thingRegistry) {
this.thingRegistry = (ThingRegistryImpl) thingRegistry;
}
protected void unsetEventPublisher(EventPublisher eventPublisher) {
this.eventPublisher = null;
}
protected void unsetThingRegistry(ThingRegistry thingRegistry) {
this.thingRegistry = null;
}
@Reference
protected void setConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescriptionRegistry = configDescriptionRegistry;
}
protected void unsetConfigDescriptionRegistry(ConfigDescriptionRegistry configDescriptionRegistry) {
this.configDescriptionRegistry = null;
}
@Reference
protected void setConfigDescriptionValidator(ConfigDescriptionValidator configDescriptionValidator) {
this.configDescriptionValidator = configDescriptionValidator;
}
protected void unsetConfigDescriptionValidator(ConfigDescriptionValidator configDescriptionValidator) {
this.configDescriptionValidator = null;
}
@Reference
protected void setBundleResolver(BundleResolver bundleResolver) {
this.bundleResolver = bundleResolver;
}
protected void unsetBundleResolver(BundleResolver bundleResolver) {
this.bundleResolver = bundleResolver;
}
private ThingStatusInfo buildStatusInfo(ThingStatus thingStatus, ThingStatusDetail thingStatusDetail, private ThingStatusInfo buildStatusInfo(ThingStatus thingStatus, ThingStatusDetail thingStatusDetail,
String description) { @Nullable String description) {
ThingStatusInfoBuilder statusInfoBuilder = ThingStatusInfoBuilder.create(thingStatus, thingStatusDetail); ThingStatusInfoBuilder statusInfoBuilder = ThingStatusInfoBuilder.create(thingStatus, thingStatusDetail);
statusInfoBuilder.withDescription(description); statusInfoBuilder.withDescription(description);
return statusInfoBuilder.build(); return statusInfoBuilder.build();
@ -1228,11 +1193,19 @@ public class ThingManagerImpl
logger.debug("Thing {} will be disabled.", thingUID); logger.debug("Thing {} will be disabled.", thingUID);
boolean disposed = false;
if (isHandlerRegistered(thing)) { if (isHandlerRegistered(thing)) {
// Dispose handler if registered. // Dispose handler if registered.
ThingHandler thingHandler = thing.getHandler();
ThingHandlerFactory thingHandlerFactory = findThingHandlerFactory(thing.getThingTypeUID()); ThingHandlerFactory thingHandlerFactory = findThingHandlerFactory(thing.getThingTypeUID());
unregisterAndDisposeHandler(thingHandlerFactory, thing, thing.getHandler()); if (thingHandler != null && thingHandlerFactory != null) {
} else { unregisterAndDisposeHandler(thingHandlerFactory, thing, thingHandler);
disposed = true;
}
}
if (!disposed) {
// Only set the correct status to the thing. There is no handler to be disposed // Only set the correct status to the thing. There is no handler to be disposed
setThingStatus(thing, buildStatusInfo(ThingStatus.UNINITIALIZED, ThingStatusDetail.DISABLED)); setThingStatus(thing, buildStatusInfo(ThingStatus.UNINITIALIZED, ThingStatusDetail.DISABLED));
} }
@ -1254,12 +1227,6 @@ public class ThingManagerImpl
} }
private void persistThingEnableStatus(ThingUID thingUID, boolean enabled) { private void persistThingEnableStatus(ThingUID thingUID, boolean enabled) {
if (storage == null) {
logger.debug("Cannot persist enable status of thing with UID {}. Persistent storage unavailable.",
thingUID);
return;
}
logger.debug("Thing with UID {} will be persisted as {}.", thingUID, enabled ? "enabled." : "disabled."); logger.debug("Thing with UID {} will be persisted as {}.", thingUID, enabled ? "enabled." : "disabled.");
if (enabled) { if (enabled) {
// Clear the disabled thing storage. Otherwise the handler will NOT be initialized later. // Clear the disabled thing storage. Otherwise the handler will NOT be initialized later.
@ -1283,86 +1250,11 @@ public class ThingManagerImpl
} }
private boolean isDisabledByStorage(ThingUID thingUID) { private boolean isDisabledByStorage(ThingUID thingUID) {
return storage != null && storage.containsKey(thingUID.getAsString()); return storage.containsKey(thingUID.getAsString());
} }
@Reference void setBundleResolver(BundleResolver bundleResolver) {
protected void setThingTypeRegistry(ThingTypeRegistry thingTypeRegistry) { this.bundleResolver = bundleResolver;
this.thingTypeRegistry = thingTypeRegistry;
} }
protected void unsetThingTypeRegistry(ThingTypeRegistry thingTypeRegistry) {
this.thingTypeRegistry = null;
}
@Reference
protected void setChannelTypeRegistry(ChannelTypeRegistry channelTypeRegistry) {
this.channelTypeRegistry = channelTypeRegistry;
}
protected void unsetChannelTypeRegistry(ChannelTypeRegistry channelTypeRegistry) {
this.channelTypeRegistry = null;
}
@Reference
protected void setChannelGroupTypeRegistry(ChannelGroupTypeRegistry channelGroupTypeRegistry) {
this.channelGroupTypeRegistry = channelGroupTypeRegistry;
}
protected void unsetChannelGroupTypeRegistry(ChannelGroupTypeRegistry channelGroupTypeRegistry) {
this.channelGroupTypeRegistry = null;
}
@Reference
protected void setItemChannelLinkRegistry(ItemChannelLinkRegistry itemChannelLinkRegistry) {
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
}
protected void unsetItemChannelLinkRegistry(ItemChannelLinkRegistry itemChannelLinkRegistry) {
this.itemChannelLinkRegistry = null;
}
@Reference
protected void setThingStatusInfoI18nLocalizationService(
ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService) {
this.thingStatusInfoI18nLocalizationService = thingStatusInfoI18nLocalizationService;
}
protected void unsetThingStatusInfoI18nLocalizationService(
ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService) {
this.thingStatusInfoI18nLocalizationService = null;
}
@Reference
protected void setInboundCommunication(CommunicationManager communicationManager) {
this.communicationManager = communicationManager;
}
protected void unsetInboundCommunication(CommunicationManager communicationManager) {
this.communicationManager = null;
}
@Reference
protected void setSafeCaller(SafeCaller safeCaller) {
this.safeCaller = safeCaller;
}
protected void unsetSafeCaller(SafeCaller safeCaller) {
this.safeCaller = null;
}
@Reference
protected void setStorageService(StorageService storageService) {
if (this.storageService != storageService) {
this.storageService = storageService;
storage = storageService.getStorage(THING_STATUS_STORAGE_NAME, this.getClass().getClassLoader());
}
}
protected void unsetStorageService(StorageService storageService) {
if (this.storageService == storageService) {
this.storageService = null;
this.storage = null;
}
}
} }

View File

@ -12,6 +12,7 @@
*/ */
package org.openhab.core.thing.internal; package org.openhab.core.thing.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingRegistryChangeListener; import org.openhab.core.thing.ThingRegistryChangeListener;
@ -25,6 +26,7 @@ import org.openhab.core.thing.ThingRegistryChangeListener;
* @author Michael Grammling - Added dynamic configuration update * @author Michael Grammling - Added dynamic configuration update
* @author Simon Kaufmann - Added THING_REMOVING state * @author Simon Kaufmann - Added THING_REMOVING state
*/ */
@NonNullByDefault
public interface ThingTracker { public interface ThingTracker {
public enum ThingTrackerEvent { public enum ThingTrackerEvent {

View File

@ -14,6 +14,7 @@ package org.openhab.core.thing.link;
import java.util.Collection; import java.util.Collection;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.common.registry.DefaultAbstractManagedProvider; import org.openhab.core.common.registry.DefaultAbstractManagedProvider;
import org.openhab.core.storage.StorageService; import org.openhab.core.storage.StorageService;
import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.ThingUID;
@ -27,6 +28,7 @@ import org.osgi.service.component.annotations.Reference;
* *
* @author Dennis Nobel - Initial contribution * @author Dennis Nobel - Initial contribution
*/ */
@NonNullByDefault
@Component(immediate = true, service = { ItemChannelLinkProvider.class, ManagedItemChannelLinkProvider.class }) @Component(immediate = true, service = { ItemChannelLinkProvider.class, ManagedItemChannelLinkProvider.class })
public class ManagedItemChannelLinkProvider extends DefaultAbstractManagedProvider<ItemChannelLink, String> public class ManagedItemChannelLinkProvider extends DefaultAbstractManagedProvider<ItemChannelLink, String>
implements ItemChannelLinkProvider { implements ItemChannelLinkProvider {

View File

@ -24,6 +24,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNull;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock; import org.mockito.Mock;
@ -60,18 +61,12 @@ public class ChannelItemProviderTest {
private static final NumberItem ITEM = new NumberItem(ITEM_NAME); private static final NumberItem ITEM = new NumberItem(ITEM_NAME);
private static final ItemChannelLink LINK = new ItemChannelLink(ITEM_NAME, CHANNEL_UID); private static final ItemChannelLink LINK = new ItemChannelLink(ITEM_NAME, CHANNEL_UID);
@Mock private @Mock ItemFactory itemFactoryMock;
private ItemRegistry itemRegistry; private @Mock ItemRegistry itemRegistryMock;
@Mock private @Mock ItemChannelLinkRegistry linkRegistryMock;
private ThingRegistry thingRegistry; private @Mock ProviderChangeListener<@NonNull Item> listenerMock;
@Mock private @Mock LocaleProvider localeProviderMock;
private ItemFactory itemFactory; private @Mock ThingRegistry thingRegistryMock;
@Mock
private ProviderChangeListener<Item> listener;
@Mock
private LocaleProvider localeProvider;
@Mock
private ItemChannelLinkRegistry linkRegistry;
private ChannelItemProvider provider; private ChannelItemProvider provider;
@ -86,9 +81,9 @@ public class ChannelItemProviderTest {
props.put("initialDelay", "false"); props.put("initialDelay", "false");
provider.activate(props); provider.activate(props);
when(thingRegistry.getChannel(same(CHANNEL_UID))).thenReturn(CHANNEL); when(thingRegistryMock.getChannel(same(CHANNEL_UID))).thenReturn(CHANNEL);
when(itemFactory.createItem(CoreItemFactory.NUMBER, ITEM_NAME)).thenReturn(ITEM); when(itemFactoryMock.createItem(CoreItemFactory.NUMBER, ITEM_NAME)).thenReturn(ITEM);
when(localeProvider.getLocale()).thenReturn(Locale.ENGLISH); when(localeProviderMock.getLocale()).thenReturn(Locale.ENGLISH);
} }
@Test @Test
@ -96,17 +91,17 @@ public class ChannelItemProviderTest {
resetAndPrepareListener(); resetAndPrepareListener();
provider.thingRegistryListener.added(THING); provider.thingRegistryListener.added(THING);
verify(listener, only()).added(same(provider), same(ITEM)); verify(listenerMock, only()).added(same(provider), same(ITEM));
} }
@Test @Test
public void testItemCreationFromThingAlreadyExists() { public void testItemCreationFromThingAlreadyExists() {
when(itemRegistry.get(eq(ITEM_NAME))).thenReturn(ITEM); when(itemRegistryMock.get(eq(ITEM_NAME))).thenReturn(ITEM);
resetAndPrepareListener(); resetAndPrepareListener();
provider.thingRegistryListener.added(THING); provider.thingRegistryListener.added(THING);
verify(listener, never()).added(same(provider), same(ITEM)); verify(listenerMock, never()).added(same(provider), same(ITEM));
} }
@Test @Test
@ -116,22 +111,22 @@ public class ChannelItemProviderTest {
resetAndPrepareListener(); resetAndPrepareListener();
provider.thingRegistryListener.removed(THING); provider.thingRegistryListener.removed(THING);
verify(listener, never()).added(same(provider), same(ITEM)); verify(listenerMock, never()).added(same(provider), same(ITEM));
verify(listener, only()).removed(same(provider), same(ITEM)); verify(listenerMock, only()).removed(same(provider), same(ITEM));
} }
@Test @Test
public void testItemCreationFromLinkNotThere() { public void testItemCreationFromLinkNotThere() {
provider.linkRegistryListener.added(LINK); provider.linkRegistryListener.added(LINK);
verify(listener, only()).added(same(provider), same(ITEM)); verify(listenerMock, only()).added(same(provider), same(ITEM));
} }
@Test @Test
public void testItemCreationFromLinkAlreadyExists() { public void testItemCreationFromLinkAlreadyExists() {
when(itemRegistry.get(eq(ITEM_NAME))).thenReturn(ITEM); when(itemRegistryMock.get(eq(ITEM_NAME))).thenReturn(ITEM);
provider.linkRegistryListener.added(LINK); provider.linkRegistryListener.added(LINK);
verify(listener, never()).added(same(provider), same(ITEM)); verify(listenerMock, never()).added(same(provider), same(ITEM));
} }
@Test @Test
@ -141,8 +136,8 @@ public class ChannelItemProviderTest {
resetAndPrepareListener(); resetAndPrepareListener();
provider.linkRegistryListener.removed(LINK); provider.linkRegistryListener.removed(LINK);
verify(listener, never()).added(same(provider), same(ITEM)); verify(listenerMock, never()).added(same(provider), same(ITEM));
verify(listener, only()).removed(same(provider), same(ITEM)); verify(listenerMock, only()).removed(same(provider), same(ITEM));
} }
@Test @Test
@ -152,14 +147,14 @@ public class ChannelItemProviderTest {
resetAndPrepareListener(); resetAndPrepareListener();
provider.itemRegistryListener.beforeAdding(new NumberItem(ITEM_NAME)); provider.itemRegistryListener.beforeAdding(new NumberItem(ITEM_NAME));
verify(listener, only()).removed(same(provider), same(ITEM)); verify(listenerMock, only()).removed(same(provider), same(ITEM));
verify(listener, never()).added(same(provider), same(ITEM)); verify(listenerMock, never()).added(same(provider), same(ITEM));
} }
@Test @Test
public void testDisableBeforeDelayedInitialization() throws Exception { public void testDisableBeforeDelayedInitialization() throws Exception {
provider = createProvider(); provider = createProvider();
reset(linkRegistry); reset(linkRegistryMock);
// Set the initialization delay to 40ms so we don't have to wait 2000ms to do the assertion // Set the initialization delay to 40ms so we don't have to wait 2000ms to do the assertion
Field field = ChannelItemProvider.class.getDeclaredField("INITIALIZATION_DELAY_NANOS"); Field field = ChannelItemProvider.class.getDeclaredField("INITIALIZATION_DELAY_NANOS");
@ -174,8 +169,8 @@ public class ChannelItemProviderTest {
provider.activate(props); provider.activate(props);
provider.linkRegistryListener.added(LINK); provider.linkRegistryListener.added(LINK);
verify(listener, never()).added(same(provider), same(ITEM)); verify(listenerMock, never()).added(same(provider), same(ITEM));
verify(linkRegistry, never()).getAll(); verify(linkRegistryMock, never()).getAll();
props = new HashMap<>(); props = new HashMap<>();
props.put("enabled", "false"); props.put("enabled", "false");
@ -184,32 +179,32 @@ public class ChannelItemProviderTest {
Thread.sleep(100); Thread.sleep(100);
provider.linkRegistryListener.added(LINK); provider.linkRegistryListener.added(LINK);
verify(listener, never()).added(same(provider), same(ITEM)); verify(listenerMock, never()).added(same(provider), same(ITEM));
verify(linkRegistry, never()).getAll(); verify(linkRegistryMock, never()).getAll();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void resetAndPrepareListener() { private void resetAndPrepareListener() {
reset(listener); reset(listenerMock);
doAnswer(invocation -> { doAnswer(invocation -> {
// this is crucial as it mimics the real ItemRegistry's behavior // this is crucial as it mimics the real ItemRegistry's behavior
provider.itemRegistryListener.afterRemoving((Item) invocation.getArguments()[1]); provider.itemRegistryListener.afterRemoving((Item) invocation.getArguments()[1]);
return null; return null;
}).when(listener).removed(same(provider), any(Item.class)); }).when(listenerMock).removed(same(provider), any(Item.class));
doAnswer(invocation -> { doAnswer(invocation -> {
// this is crucial as it mimics the real ItemRegistry's behavior // this is crucial as it mimics the real ItemRegistry's behavior
provider.itemRegistryListener.beforeAdding((Item) invocation.getArguments()[1]); provider.itemRegistryListener.beforeAdding((Item) invocation.getArguments()[1]);
return null; return null;
}).when(listener).added(same(provider), any(Item.class)); }).when(listenerMock).added(same(provider), any(Item.class));
when(linkRegistry.getBoundChannels(eq(ITEM_NAME))).thenReturn(Collections.singleton(CHANNEL_UID)); when(linkRegistryMock.getBoundChannels(eq(ITEM_NAME))).thenReturn(Collections.singleton(CHANNEL_UID));
when(linkRegistry.getLinks(eq(CHANNEL_UID))).thenReturn(Collections.singleton(LINK)); when(linkRegistryMock.getLinks(eq(CHANNEL_UID))).thenReturn(Collections.singleton(LINK));
} }
private ChannelItemProvider createProvider() { private ChannelItemProvider createProvider() {
ChannelItemProvider provider = new ChannelItemProvider(localeProvider, mock(ChannelTypeRegistry.class), ChannelItemProvider provider = new ChannelItemProvider(localeProviderMock, mock(ChannelTypeRegistry.class),
thingRegistry, itemRegistry, linkRegistry); thingRegistryMock, itemRegistryMock, linkRegistryMock);
provider.addItemFactory(itemFactory); provider.addItemFactory(itemFactoryMock);
provider.addProviderChangeListener(listener); provider.addProviderChangeListener(listenerMock);
return provider; return provider;
} }

View File

@ -17,103 +17,129 @@ import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks; import static org.mockito.MockitoAnnotations.initMocks;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock; import org.mockito.Mock;
import org.openhab.core.common.SafeCaller;
import org.openhab.core.config.core.ConfigDescriptionRegistry;
import org.openhab.core.config.core.validation.ConfigDescriptionValidator;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.service.ReadyService; import org.openhab.core.service.ReadyService;
import org.openhab.core.storage.Storage; import org.openhab.core.storage.Storage;
import org.openhab.core.storage.StorageService; import org.openhab.core.storage.StorageService;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.openhab.core.thing.i18n.ThingStatusInfoI18nLocalizationService;
import org.openhab.core.thing.internal.ThingTracker.ThingTrackerEvent;
import org.openhab.core.thing.link.ItemChannelLinkRegistry;
import org.openhab.core.thing.type.ChannelGroupTypeRegistry;
import org.openhab.core.thing.type.ChannelTypeRegistry;
import org.openhab.core.thing.type.ThingTypeRegistry;
import org.openhab.core.util.BundleResolver; import org.openhab.core.util.BundleResolver;
import org.osgi.framework.Bundle; import org.osgi.framework.Bundle;
import org.osgi.service.component.ComponentContext;
/** /**
* @author Simon Kaufmann - Initial contribution * @author Simon Kaufmann - Initial contribution
*/ */
@NonNullByDefault
public class ThingManagerImplTest { public class ThingManagerImplTest {
private @Mock BundleResolver mockBundleResolver; private @Mock @NonNullByDefault({}) Bundle bundleMock;
private @Mock Bundle mockBundle; private @Mock @NonNullByDefault({}) BundleResolver bundleResolverMock;
private @Mock ComponentContext mockComponentContext; private @Mock @NonNullByDefault({}) ChannelGroupTypeRegistry channelGroupTypeRegistryMock;
private @Mock ReadyService mockReadyService; private @Mock @NonNullByDefault({}) ChannelTypeRegistry channelTypeRegistryMock;
private @Mock Thing mockThing; private @Mock @NonNullByDefault({}) CommunicationManager communicationManagerMock;
private @Mock @NonNullByDefault({}) EventPublisher eventPublisherMock;
private @Mock @NonNullByDefault({}) ConfigDescriptionRegistry configDescriptionRegistryMock;
private @Mock @NonNullByDefault({}) ConfigDescriptionValidator configDescriptionValidatorMock;
private @Mock @NonNullByDefault({}) ItemChannelLinkRegistry itemChannelLinkRegistryMock;
private @Mock @NonNullByDefault({}) ThingTypeRegistry thingTypeRegistryMock;
private @Mock @NonNullByDefault({}) ReadyService readyServiceMock;
private @Mock @NonNullByDefault({}) SafeCaller safeCallerMock;
private @Mock @NonNullByDefault({}) Storage<Object> storageMock;
private @Mock @NonNullByDefault({}) StorageService storageServiceMock;
private @Mock @NonNullByDefault({}) Thing thingMock;
private @Mock @NonNullByDefault({}) ThingRegistryImpl thingRegistryMock;
private @Mock StorageService mockStorageService; // This class is final so it cannot be mocked
private @Mock Storage<Object> mockStorage; private final ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService = new ThingStatusInfoI18nLocalizationService();
private final ThingRegistryImpl thingRegistry = new ThingRegistryImpl();
@Before @Before
public void setup() { public void setup() {
initMocks(this); initMocks(this);
when(mockBundle.getSymbolicName()).thenReturn("test");
when(mockBundleResolver.resolveBundle(any())).thenReturn(mockBundle); when(bundleMock.getSymbolicName()).thenReturn("test");
when(mockThing.getUID()).thenReturn(new ThingUID("test", "thing")); when(bundleResolverMock.resolveBundle(any())).thenReturn(bundleMock);
when(thingMock.getUID()).thenReturn(new ThingUID("test", "thing"));
}
private ThingManagerImpl createThingManager() {
return new ThingManagerImpl(bundleResolverMock, channelGroupTypeRegistryMock, channelTypeRegistryMock,
communicationManagerMock, configDescriptionRegistryMock, configDescriptionValidatorMock,
eventPublisherMock, itemChannelLinkRegistryMock, readyServiceMock, safeCallerMock, storageServiceMock,
thingRegistryMock, thingStatusInfoI18nLocalizationService, thingTypeRegistryMock);
} }
@Test @Test
public void testThingHandlerFactoryLifecycle() { public void thingHandlerFactoryLifecycle() {
ThingHandlerFactory mockFactory1 = mock(ThingHandlerFactory.class); ThingHandlerFactory mockFactory1 = mock(ThingHandlerFactory.class);
ThingHandlerFactory mockFactory2 = mock(ThingHandlerFactory.class); ThingHandlerFactory mockFactory2 = mock(ThingHandlerFactory.class);
ThingManagerImpl thingManager = new ThingManagerImpl(); ThingManagerImpl thingManager = createThingManager();
thingManager.setBundleResolver(mockBundleResolver);
thingManager.setThingRegistry(thingRegistry); thingManager.thingAdded(thingMock, ThingTrackerEvent.THING_ADDED);
thingManager.setReadyService(mockReadyService);
thingManager.thingAdded(mockThing, null);
// ensure usage is delayed until activation
thingManager.addThingHandlerFactory(mockFactory1); thingManager.addThingHandlerFactory(mockFactory1);
verify(mockFactory1, times(0)).supportsThingType(any());
thingManager.activate(mockComponentContext);
verify(mockFactory1, atLeastOnce()).supportsThingType(any()); verify(mockFactory1, atLeastOnce()).supportsThingType(any());
thingManager.removeThingHandlerFactory(mockFactory1);
// ensure it is directly used
thingManager.addThingHandlerFactory(mockFactory2); thingManager.addThingHandlerFactory(mockFactory2);
verify(mockFactory2, atLeastOnce()).supportsThingType(any()); verify(mockFactory2, atLeastOnce()).supportsThingType(any());
thingManager.removeThingHandlerFactory(mockFactory2);
} }
@Test @Test
public void testCallSetEnabledWithUnknownThingUID() throws Exception { public void setEnabledWithUnknownThingUID() throws Exception {
ThingUID unknownUID = new ThingUID("someBundle", "someType", "someID"); ThingUID unknownUID = new ThingUID("someBundle", "someType", "someID");
ThingManagerImpl thingManager = new ThingManagerImpl();
when(mockStorageService.getStorage(eq("thing_status_storage"), any(ClassLoader.class))).thenReturn(mockStorage); when(storageServiceMock.getStorage(eq("thing_status_storage"), any(ClassLoader.class))).thenReturn(storageMock);
thingManager.setStorageService(mockStorageService);
ThingManagerImpl thingManager = createThingManager();
thingManager.setEnabled(unknownUID, true); thingManager.setEnabled(unknownUID, true);
verify(mockStorage).remove(eq(unknownUID.getAsString())); verify(storageMock).remove(eq(unknownUID.getAsString()));
thingManager.setEnabled(unknownUID, false); thingManager.setEnabled(unknownUID, false);
verify(mockStorage).put(eq(unknownUID.getAsString()), eq("")); verify(storageMock).put(eq(unknownUID.getAsString()), eq(""));
} }
@Test @Test
public void testCallIsEnabledWithUnknownThingUIDAndNullStorage() throws Exception { public void isEnabledWithUnknownThingUIDAndNullStorage() throws Exception {
ThingUID unknownUID = new ThingUID("someBundle", "someType", "someID"); ThingUID unknownUID = new ThingUID("someBundle", "someType", "someID");
ThingManagerImpl thingManager = new ThingManagerImpl();
when(mockStorageService.getStorage(eq("thing_status_storage"), any(ClassLoader.class))).thenReturn(mockStorage); when(storageServiceMock.getStorage(eq("thing_status_storage"), any(ClassLoader.class))).thenReturn(storageMock);
thingManager.setStorageService(mockStorageService);
ThingManagerImpl thingManager = createThingManager();
assertEquals(thingManager.isEnabled(unknownUID), true); assertEquals(thingManager.isEnabled(unknownUID), true);
} }
@Test @Test
public void testCallIsEnabledWithUnknownThingUIDAndNonNullStorage() throws Exception { public void isEnabledWithUnknownThingUIDAndNonNullStorage() throws Exception {
ThingUID unknownUID = new ThingUID("someBundle", "someType", "someID"); ThingUID unknownUID = new ThingUID("someBundle", "someType", "someID");
ThingManagerImpl thingManager = new ThingManagerImpl();
when(mockStorage.containsKey(unknownUID.getAsString())).thenReturn(false); when(storageMock.containsKey(unknownUID.getAsString())).thenReturn(false);
when(mockStorageService.getStorage(eq("thing_status_storage"), any(ClassLoader.class))).thenReturn(mockStorage); when(storageServiceMock.getStorage(eq("thing_status_storage"), any(ClassLoader.class))).thenReturn(storageMock);
thingManager.setStorageService(mockStorageService);
ThingManagerImpl thingManager = createThingManager();
assertEquals(thingManager.isEnabled(unknownUID), true); assertEquals(thingManager.isEnabled(unknownUID), true);
when(mockStorage.containsKey(unknownUID.getAsString())).thenReturn(true); when(storageMock.containsKey(unknownUID.getAsString())).thenReturn(true);
when(mockStorageService.getStorage(eq("thing_status_storage"), any(ClassLoader.class))).thenReturn(mockStorage); when(storageServiceMock.getStorage(eq("thing_status_storage"), any(ClassLoader.class))).thenReturn(storageMock);
thingManager.setStorageService(mockStorageService);
assertEquals(thingManager.isEnabled(unknownUID), false); assertEquals(thingManager.isEnabled(unknownUID), false);
} }
} }

View File

@ -17,6 +17,8 @@ import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.storage.Storage; import org.openhab.core.storage.Storage;
import org.openhab.core.storage.StorageService; import org.openhab.core.storage.StorageService;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -41,8 +43,9 @@ import org.slf4j.LoggerFactory;
* @param <PE> * @param <PE>
* type of the persistable element * type of the persistable element
*/ */
public abstract class AbstractManagedProvider<E extends Identifiable<K>, K, PE> extends AbstractProvider<E> @NonNullByDefault
implements ManagedProvider<E, K> { public abstract class AbstractManagedProvider<@NonNull E extends Identifiable<K>, @NonNull K, PE>
extends AbstractProvider<E> implements ManagedProvider<E, K> {
private volatile Storage<PE> storage; private volatile Storage<PE> storage;
@ -67,37 +70,26 @@ public abstract class AbstractManagedProvider<E extends Identifiable<K>, K, PE>
@Override @Override
public Collection<E> getAll() { public Collection<E> getAll() {
return storage.getKeys().stream().map(key -> { return (Collection<E>) storage.getKeys().stream().map(this::getElement).filter(Objects::nonNull)
.collect(Collectors.toList());
}
@Override
public @Nullable E get(K key) {
return getElement(keyToString(key));
}
private @Nullable E getElement(String key) {
PE persistableElement = storage.get(key); PE persistableElement = storage.get(key);
if (persistableElement != null) { return persistableElement != null ? toElement(key, persistableElement) : null;
return toElement(key, persistableElement);
} else {
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toList());
} }
@Override @Override
public E get(K key) { public @Nullable E remove(K key) {
if (key == null) {
throw new IllegalArgumentException("Cannot get null element");
}
String keyAsString = keyToString(key);
PE persistableElement = storage.get(keyAsString);
if (persistableElement != null) {
return toElement(keyAsString, persistableElement);
} else {
return null;
}
}
@Override
public E remove(K key) {
String keyAsString = keyToString(key); String keyAsString = keyToString(key);
PE persistableElement = storage.remove(keyAsString); PE persistableElement = storage.remove(keyAsString);
if (persistableElement != null) { if (persistableElement != null) {
@Nullable
E element = toElement(keyAsString, persistableElement); E element = toElement(keyAsString, persistableElement);
if (element != null) { if (element != null) {
notifyListenersAboutRemovedElement(element); notifyListenersAboutRemovedElement(element);
@ -110,12 +102,16 @@ public abstract class AbstractManagedProvider<E extends Identifiable<K>, K, PE>
} }
@Override @Override
public E update(E element) { public @Nullable E update(E element) {
String key = getKeyAsString(element); String key = getKeyAsString(element);
if (storage.get(key) != null) { if (storage.get(key) != null) {
PE persistableElement = storage.put(key, toPersistableElement(element)); PE persistableElement = storage.put(key, toPersistableElement(element));
if (persistableElement != null) { if (persistableElement != null) {
@Nullable
E oldElement = toElement(key, persistableElement); E oldElement = toElement(key, persistableElement);
if (oldElement == null) {
oldElement = element;
}
notifyListenersAboutUpdatedElement(oldElement, element); notifyListenersAboutUpdatedElement(oldElement, element);
logger.debug("Updated element {} in {}.", key, this.getClass().getSimpleName()); logger.debug("Updated element {} in {}.", key, this.getClass().getSimpleName());
return oldElement; return oldElement;
@ -128,7 +124,7 @@ public abstract class AbstractManagedProvider<E extends Identifiable<K>, K, PE>
return null; return null;
} }
private @NonNull String getKeyAsString(@NonNull E element) { private String getKeyAsString(E element) {
return keyToString(element.getUID()); return keyToString(element.getUID());
} }
@ -145,7 +141,7 @@ public abstract class AbstractManagedProvider<E extends Identifiable<K>, K, PE>
* @param key key * @param key key
* @return string representation of the key * @return string representation of the key
*/ */
protected abstract @NonNull String keyToString(@NonNull K key); protected abstract String keyToString(K key);
/** /**
* Converts the persistable element into the original element. * Converts the persistable element into the original element.
@ -154,7 +150,7 @@ public abstract class AbstractManagedProvider<E extends Identifiable<K>, K, PE>
* @param persistableElement persistable element * @param persistableElement persistable element
* @return original element * @return original element
*/ */
protected abstract E toElement(@NonNull String key, @NonNull PE persistableElement); protected abstract @Nullable E toElement(String key, @NonNull PE persistableElement);
/** /**
* Converts the original element into an element that can be persisted. * Converts the original element into an element that can be persisted.

View File

@ -15,6 +15,9 @@ package org.openhab.core.common.registry;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -27,7 +30,8 @@ import org.slf4j.LoggerFactory;
* @param <E> * @param <E>
* type of the provided elements * type of the provided elements
*/ */
public abstract class AbstractProvider<E> implements Provider<E> { @NonNullByDefault
public abstract class AbstractProvider<@NonNull E> implements Provider<E> {
private enum EventType { private enum EventType {
ADDED, ADDED,
@ -48,7 +52,7 @@ public abstract class AbstractProvider<E> implements Provider<E> {
listeners.remove(listener); listeners.remove(listener);
} }
private void notifyListeners(E oldElement, E element, EventType eventType) { private void notifyListeners(@Nullable E oldElement, E element, EventType eventType) {
for (ProviderChangeListener<E> listener : this.listeners) { for (ProviderChangeListener<E> listener : this.listeners) {
try { try {
switch (eventType) { switch (eventType) {
@ -59,7 +63,7 @@ public abstract class AbstractProvider<E> implements Provider<E> {
listener.removed(this, element); listener.removed(this, element);
break; break;
case UPDATED: case UPDATED:
listener.updated(this, oldElement, element); listener.updated(this, oldElement != null ? oldElement : element, element);
break; break;
default: default:
break; break;

View File

@ -52,7 +52,7 @@ import org.slf4j.LoggerFactory;
* @param <E> type of the element * @param <E> type of the element
*/ */
@NonNullByDefault @NonNullByDefault
public abstract class AbstractRegistry<E extends Identifiable<K>, K, P extends Provider<E>> public abstract class AbstractRegistry<@NonNull E extends Identifiable<K>, @NonNull K, @NonNull P extends Provider<E>>
implements ProviderChangeListener<E>, Registry<E, K> { implements ProviderChangeListener<E>, Registry<E, K> {
private enum EventType { private enum EventType {

View File

@ -12,6 +12,9 @@
*/ */
package org.openhab.core.common.registry; package org.openhab.core.common.registry;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.storage.StorageService; import org.openhab.core.storage.StorageService;
/** /**
@ -27,7 +30,8 @@ import org.openhab.core.storage.StorageService;
* @param <K> * @param <K>
* type of the element key * type of the element key
*/ */
public abstract class DefaultAbstractManagedProvider<E extends Identifiable<K>, K> @NonNullByDefault
public abstract class DefaultAbstractManagedProvider<@NonNull E extends Identifiable<K>, @NonNull K>
extends AbstractManagedProvider<E, K, E> { extends AbstractManagedProvider<E, K, E> {
public DefaultAbstractManagedProvider(final StorageService storageService) { public DefaultAbstractManagedProvider(final StorageService storageService) {
@ -35,7 +39,7 @@ public abstract class DefaultAbstractManagedProvider<E extends Identifiable<K>,
} }
@Override @Override
protected E toElement(String key, E element) { protected @Nullable E toElement(String key, E element) {
return element; return element;
} }

View File

@ -13,6 +13,7 @@
package org.openhab.core.common.registry; package org.openhab.core.common.registry;
import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
/** /**
@ -26,14 +27,15 @@ import org.eclipse.jdt.annotation.Nullable;
* @param <K> * @param <K>
* type of the element key * type of the element key
*/ */
public interface ManagedProvider<E extends Identifiable<K>, K> extends Provider<E> { @NonNullByDefault
public interface ManagedProvider<@NonNull E extends Identifiable<K>, @NonNull K> extends Provider<E> {
/** /**
* Adds an element. * Adds an element.
* *
* @param element element to be added * @param element element to be added
*/ */
void add(@NonNull E element); void add(E element);
/** /**
* Removes an element and returns the removed element. * Removes an element and returns the removed element.
@ -43,7 +45,7 @@ public interface ManagedProvider<E extends Identifiable<K>, K> extends Provider<
* key exists * key exists
*/ */
@Nullable @Nullable
E remove(@NonNull K key); E remove(K key);
/** /**
* Updates an element. * Updates an element.
@ -53,7 +55,7 @@ public interface ManagedProvider<E extends Identifiable<K>, K> extends Provider<
* exists * exists
*/ */
@Nullable @Nullable
E update(@NonNull E element); E update(E element);
/** /**
* Returns an element for the given key or null if no element for the given * Returns an element for the given key or null if no element for the given

View File

@ -14,6 +14,7 @@ package org.openhab.core.common.registry;
import java.util.Collection; import java.util.Collection;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
/** /**
@ -27,7 +28,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
* @param <E> type of the provided elements * @param <E> type of the provided elements
*/ */
@NonNullByDefault @NonNullByDefault
public interface Provider<E> { public interface Provider<@NonNull E> {
/** /**
* Adds a {@link ProviderChangeListener} which must be notified if there are * Adds a {@link ProviderChangeListener} which must be notified if there are

View File

@ -12,6 +12,7 @@
*/ */
package org.openhab.core.common.registry; package org.openhab.core.common.registry;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
/** /**
@ -24,7 +25,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
* @param <E> type of the element from the provider * @param <E> type of the element from the provider
*/ */
@NonNullByDefault @NonNullByDefault
public interface ProviderChangeListener<E> { public interface ProviderChangeListener<@NonNull E> {
/** /**
* Notifies the listener that a single element has been added. * Notifies the listener that a single element has been added.

View File

@ -13,6 +13,7 @@
package org.openhab.core.internal.items; package org.openhab.core.internal.items;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.common.registry.AbstractManagedProvider; import org.openhab.core.common.registry.AbstractManagedProvider;
import org.openhab.core.items.ManagedMetadataProvider; import org.openhab.core.items.ManagedMetadataProvider;
import org.openhab.core.items.Metadata; import org.openhab.core.items.Metadata;
@ -33,8 +34,8 @@ import org.slf4j.LoggerFactory;
* *
* @author Kai Kreuzer - Initial contribution * @author Kai Kreuzer - Initial contribution
*/ */
@Component(immediate = true, service = { MetadataProvider.class, ManagedMetadataProvider.class })
@NonNullByDefault @NonNullByDefault
@Component(immediate = true, service = { MetadataProvider.class, ManagedMetadataProvider.class })
public class ManagedMetadataProviderImpl extends AbstractManagedProvider<Metadata, MetadataKey, Metadata> public class ManagedMetadataProviderImpl extends AbstractManagedProvider<Metadata, MetadataKey, Metadata>
implements ManagedMetadataProvider { implements ManagedMetadataProvider {
@ -56,7 +57,7 @@ public class ManagedMetadataProviderImpl extends AbstractManagedProvider<Metadat
} }
@Override @Override
protected Metadata toElement(String key, Metadata persistableElement) { protected @Nullable Metadata toElement(String key, Metadata persistableElement) {
return persistableElement; return persistableElement;
} }

View File

@ -12,6 +12,7 @@
*/ */
package org.openhab.core.items; package org.openhab.core.items;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.common.registry.Provider; import org.openhab.core.common.registry.Provider;
@ -23,6 +24,6 @@ import org.openhab.core.common.registry.Provider;
* @author Kai Kreuzer - Initial contribution * @author Kai Kreuzer - Initial contribution
*/ */
@NonNullByDefault @NonNullByDefault
public interface ItemProvider extends Provider<Item> { public interface ItemProvider extends Provider<@NonNull Item> {
} }

View File

@ -54,10 +54,10 @@ import com.google.gson.InstanceCreator;
* @author Kai Kreuzer - improved return values * @author Kai Kreuzer - improved return values
* @author Alex Tugarev - added tags * @author Alex Tugarev - added tags
*/ */
@NonNullByDefault
@Component(immediate = true, service = { ItemProvider.class, ManagedItemProvider.class }) @Component(immediate = true, service = { ItemProvider.class, ManagedItemProvider.class })
public class ManagedItemProvider extends AbstractManagedProvider<Item, String, PersistedItem> implements ItemProvider { public class ManagedItemProvider extends AbstractManagedProvider<Item, String, PersistedItem> implements ItemProvider {
@NonNullByDefault
public static class PersistedItem { public static class PersistedItem {
public PersistedItem(String itemType) { public PersistedItem(String itemType) {
@ -78,7 +78,7 @@ public class ManagedItemProvider extends AbstractManagedProvider<Item, String, P
public static class PersistedItemInstanceCreator implements InstanceCreator<PersistedItem> { public static class PersistedItemInstanceCreator implements InstanceCreator<PersistedItem> {
@Override @Override
public PersistedItem createInstance(Type type) { public PersistedItem createInstance(@NonNullByDefault({}) Type type) {
return new PersistedItem(""); return new PersistedItem("");
} }
} }
@ -100,7 +100,7 @@ public class ManagedItemProvider extends AbstractManagedProvider<Item, String, P
* @param recursive if set to true all members of the item will be removed, too. * @param recursive if set to true all members of the item will be removed, too.
* @return removed item or null if no item with that name exists * @return removed item or null if no item with that name exists
*/ */
public Item remove(String itemName, boolean recursive) { public @Nullable Item remove(String itemName, boolean recursive) {
Item item = get(itemName); Item item = get(itemName);
if (recursive && item instanceof GroupItem) { if (recursive && item instanceof GroupItem) {
for (String member : getMemberNamesRecursively((GroupItem) item, getAll())) { for (String member : getMemberNamesRecursively((GroupItem) item, getAll())) {
@ -128,7 +128,7 @@ public class ManagedItemProvider extends AbstractManagedProvider<Item, String, P
return memberNames; return memberNames;
} }
private Item createItem(String itemType, String itemName) { private @Nullable Item createItem(String itemType, String itemName) {
for (ItemFactory factory : itemFactories) { for (ItemFactory factory : itemFactories) {
Item item = factory.createItem(itemType, itemName); Item item = factory.createItem(itemType, itemName);
if (item != null) { if (item != null) {
@ -195,12 +195,13 @@ public class ManagedItemProvider extends AbstractManagedProvider<Item, String, P
} }
@Override @Override
protected Item toElement(String itemName, PersistedItem persistedItem) { protected @Nullable Item toElement(String itemName, PersistedItem persistedItem) {
Item item = null; Item item = null;
if (persistedItem.itemType.equals(GroupItem.TYPE)) { if (GroupItem.TYPE.equals(persistedItem.itemType)) {
if (persistedItem.baseItemType != null) { String baseItemType = persistedItem.baseItemType;
Item baseItem = createItem(persistedItem.baseItemType, itemName); if (baseItemType != null) {
Item baseItem = createItem(baseItemType, itemName);
if (persistedItem.functionName != null) { if (persistedItem.functionName != null) {
GroupFunction function = getGroupFunction(persistedItem, baseItem); GroupFunction function = getGroupFunction(persistedItem, baseItem);
item = new GroupItem(itemName, baseItem, function); item = new GroupItem(itemName, baseItem, function);
@ -227,7 +228,7 @@ public class ManagedItemProvider extends AbstractManagedProvider<Item, String, P
return item; return item;
} }
private GroupFunction getGroupFunction(PersistedItem persistedItem, Item baseItem) { private GroupFunction getGroupFunction(PersistedItem persistedItem, @Nullable Item baseItem) {
GroupFunctionDTO functionDTO = new GroupFunctionDTO(); GroupFunctionDTO functionDTO = new GroupFunctionDTO();
functionDTO.name = persistedItem.functionName; functionDTO.name = persistedItem.functionName;
if (persistedItem.functionParams != null) { if (persistedItem.functionParams != null) {
@ -237,7 +238,6 @@ public class ManagedItemProvider extends AbstractManagedProvider<Item, String, P
} }
private void configureItem(PersistedItem persistedItem, ActiveItem item) { private void configureItem(PersistedItem persistedItem, ActiveItem item) {
if (item != null) {
List<String> groupNames = persistedItem.groupNames; List<String> groupNames = persistedItem.groupNames;
if (groupNames != null) { if (groupNames != null) {
for (String groupName : groupNames) { for (String groupName : groupNames) {
@ -255,7 +255,6 @@ public class ManagedItemProvider extends AbstractManagedProvider<Item, String, P
item.setLabel(persistedItem.label); item.setLabel(persistedItem.label);
item.setCategory(persistedItem.category); item.setCategory(persistedItem.category);
} }
}
@Override @Override
protected PersistedItem toPersistableElement(Item item) { protected PersistedItem toPersistableElement(Item item) {

View File

@ -26,6 +26,8 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -60,6 +62,7 @@ import org.slf4j.LoggerFactory;
* @author Benedikt Niehues - Initial contribution * @author Benedikt Niehues - Initial contribution
* @author Markus Rathgeb - Migrated Groovy tests to pure Java ones and made it more robust * @author Markus Rathgeb - Migrated Groovy tests to pure Java ones and made it more robust
*/ */
@NonNullByDefault
public class RunRuleModuleTest extends JavaOSGiTest { public class RunRuleModuleTest extends JavaOSGiTest {
private final Logger logger = LoggerFactory.getLogger(RunRuleModuleTest.class); private final Logger logger = LoggerFactory.getLogger(RunRuleModuleTest.class);
@ -182,7 +185,7 @@ public class RunRuleModuleTest extends JavaOSGiTest {
} }
@Override @Override
public EventFilter getEventFilter() { public @Nullable EventFilter getEventFilter() {
return null; return null;
} }
}); });

View File

@ -26,6 +26,8 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
@ -67,6 +69,7 @@ import org.slf4j.LoggerFactory;
* @author Benedikt Niehues - Initial contribution * @author Benedikt Niehues - Initial contribution
* @author Markus Rathgeb - Migrated Groovy tests to pure Java ones and made it more robust * @author Markus Rathgeb - Migrated Groovy tests to pure Java ones and made it more robust
*/ */
@NonNullByDefault
public class RuntimeRuleTest extends JavaOSGiTest { public class RuntimeRuleTest extends JavaOSGiTest {
private final Logger logger = LoggerFactory.getLogger(RuntimeRuleTest.class); private final Logger logger = LoggerFactory.getLogger(RuntimeRuleTest.class);
@ -115,7 +118,7 @@ public class RuntimeRuleTest extends JavaOSGiTest {
} }
@Override @Override
public EventFilter getEventFilter() { public @Nullable EventFilter getEventFilter() {
return null; return null;
} }
}); });
@ -178,7 +181,7 @@ public class RuntimeRuleTest extends JavaOSGiTest {
} }
@Override @Override
public EventFilter getEventFilter() { public @Nullable EventFilter getEventFilter() {
return null; return null;
} }
}); });
@ -219,7 +222,7 @@ public class RuntimeRuleTest extends JavaOSGiTest {
} }
private void assertSatisfiedHandlerInput(final CompareConditionHandler handler, final boolean expected, private void assertSatisfiedHandlerInput(final CompareConditionHandler handler, final boolean expected,
final Object input) { final @Nullable Object input) {
final boolean is = handler.isSatisfied(Collections.singletonMap("input", input)); final boolean is = handler.isSatisfied(Collections.singletonMap("input", input));
if (expected) { if (expected) {
Assert.assertTrue(is); Assert.assertTrue(is);
@ -390,7 +393,7 @@ public class RuntimeRuleTest extends JavaOSGiTest {
} }
@Override @Override
public EventFilter getEventFilter() { public @Nullable EventFilter getEventFilter() {
return null; return null;
} }
}); });

View File

@ -21,6 +21,7 @@ import java.util.Collection;
import javax.measure.quantity.Length; import javax.measure.quantity.Length;
import javax.measure.quantity.Temperature; import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -45,6 +46,7 @@ import org.openhab.core.types.State;
* *
* @author Henning Treu - Initial contribution * @author Henning Treu - Initial contribution
*/ */
@NonNullByDefault
public class ScriptEngineOSGiTest extends JavaOSGiTest { public class ScriptEngineOSGiTest extends JavaOSGiTest {
private static final String ITEM_NAME = "Switch1"; private static final String ITEM_NAME = "Switch1";
@ -52,11 +54,9 @@ public class ScriptEngineOSGiTest extends JavaOSGiTest {
private static final String NUMBER_ITEM_DECIMAL = "NumberB"; private static final String NUMBER_ITEM_DECIMAL = "NumberB";
private static final String NUMBER_ITEM_LENGTH = "NumberC"; private static final String NUMBER_ITEM_LENGTH = "NumberC";
private ItemProvider itemProvider; private @NonNullByDefault({}) ItemProvider itemProvider;
private @NonNullByDefault({}) ItemRegistry itemRegistry;
private ScriptEngine scriptEngine; private @NonNullByDefault({}) ScriptEngine scriptEngine;
private ItemRegistry itemRegistry;
@Before @Before
public void setup() { public void setup() {

View File

@ -22,6 +22,8 @@ import java.io.ByteArrayInputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collection; import java.util.Collection;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -43,6 +45,7 @@ import org.openhab.core.thing.link.ItemChannelLinkRegistry;
* *
* @author Simon Kaufmann - Initial contribution and API * @author Simon Kaufmann - Initial contribution and API
*/ */
@NonNullByDefault
public class GenericItemChannelLinkProviderJavaTest extends JavaOSGiTest { public class GenericItemChannelLinkProviderJavaTest extends JavaOSGiTest {
private static final String THINGS_TESTMODEL_NAME = "test.things"; private static final String THINGS_TESTMODEL_NAME = "test.things";
@ -52,14 +55,13 @@ public class GenericItemChannelLinkProviderJavaTest extends JavaOSGiTest {
private static final String CHANNEL = "test:test:test:test"; private static final String CHANNEL = "test:test:test:test";
private static final String LINK = ITEM + " -> " + CHANNEL; private static final String LINK = ITEM + " -> " + CHANNEL;
private ModelRepository modelRepository; private @Mock @Nullable ProviderChangeListener<ItemChannelLink> listenerMock;
private ThingRegistry thingRegistry;
private ItemRegistry itemRegistry;
private ItemChannelLinkRegistry itemChannelLinkRegistry;
private ItemChannelLinkProvider itemChannelLinkProvider;
@Mock private @NonNullByDefault({}) ModelRepository modelRepository;
private ProviderChangeListener<ItemChannelLink> listener; private @NonNullByDefault({}) ThingRegistry thingRegistry;
private @NonNullByDefault({}) ItemRegistry itemRegistry;
private @NonNullByDefault({}) ItemChannelLinkRegistry itemChannelLinkRegistry;
private @NonNullByDefault({}) ItemChannelLinkProvider itemChannelLinkProvider;
@Before @Before
public void setUp() { public void setUp() {
@ -137,29 +139,38 @@ public class GenericItemChannelLinkProviderJavaTest extends JavaOSGiTest {
@Test @Test
public void testNoAmnesia() throws Exception { public void testNoAmnesia() throws Exception {
GenericItemChannelLinkProvider provider = new GenericItemChannelLinkProvider(); GenericItemChannelLinkProvider provider = new GenericItemChannelLinkProvider();
provider.addProviderChangeListener(listener);
ProviderChangeListener<ItemChannelLink> localListenerMock = listenerMock;
if (localListenerMock != null) {
provider.addProviderChangeListener(localListenerMock);
} else {
throw new IllegalStateException("listenerMock is null");
}
provider.startConfigurationUpdate(ITEMS_TESTMODEL_NAME); provider.startConfigurationUpdate(ITEMS_TESTMODEL_NAME);
provider.processBindingConfiguration(ITEMS_TESTMODEL_NAME, "Number", ITEM, CHANNEL, new Configuration()); provider.processBindingConfiguration(ITEMS_TESTMODEL_NAME, "Number", ITEM, CHANNEL, new Configuration());
provider.stopConfigurationUpdate(ITEMS_TESTMODEL_NAME); provider.stopConfigurationUpdate(ITEMS_TESTMODEL_NAME);
assertThat(provider.getAll().size(), is(1)); assertThat(provider.getAll().size(), is(1));
assertThat(provider.getAll().iterator().next().toString(), is(LINK)); assertThat(provider.getAll().iterator().next().toString(), is(LINK));
verify(listener, only()).added(same(provider), eq(new ItemChannelLink(ITEM, new ChannelUID(CHANNEL)))); verify(localListenerMock, only()).added(same(provider), eq(new ItemChannelLink(ITEM, new ChannelUID(CHANNEL))));
reset(listener); reset(localListenerMock);
provider.startConfigurationUpdate(ITEMS_TESTMODEL_NAME); provider.startConfigurationUpdate(ITEMS_TESTMODEL_NAME);
provider.processBindingConfiguration(ITEMS_TESTMODEL_NAME, "Number", ITEM, CHANNEL, new Configuration()); provider.processBindingConfiguration(ITEMS_TESTMODEL_NAME, "Number", ITEM, CHANNEL, new Configuration());
provider.stopConfigurationUpdate(ITEMS_TESTMODEL_NAME); provider.stopConfigurationUpdate(ITEMS_TESTMODEL_NAME);
assertThat(provider.getAll().size(), is(1)); assertThat(provider.getAll().size(), is(1));
assertThat(provider.getAll().iterator().next().toString(), is(LINK)); assertThat(provider.getAll().iterator().next().toString(), is(LINK));
verify(listener, only()).updated(same(provider), eq(new ItemChannelLink(ITEM, new ChannelUID(CHANNEL))), verify(localListenerMock, only()).updated(same(provider),
eq(new ItemChannelLink(ITEM, new ChannelUID(CHANNEL))),
eq(new ItemChannelLink(ITEM, new ChannelUID(CHANNEL)))); eq(new ItemChannelLink(ITEM, new ChannelUID(CHANNEL))));
reset(listener); reset(localListenerMock);
provider.startConfigurationUpdate(ITEMS_TESTMODEL_NAME); provider.startConfigurationUpdate(ITEMS_TESTMODEL_NAME);
provider.stopConfigurationUpdate(ITEMS_TESTMODEL_NAME); provider.stopConfigurationUpdate(ITEMS_TESTMODEL_NAME);
assertThat(provider.getAll().size(), is(0)); assertThat(provider.getAll().size(), is(0));
verify(listener, only()).removed(same(provider), eq(new ItemChannelLink(ITEM, new ChannelUID(CHANNEL)))); verify(localListenerMock, only()).removed(same(provider),
eq(new ItemChannelLink(ITEM, new ChannelUID(CHANNEL))));
} }
@Test @Test

View File

@ -17,6 +17,8 @@ import static org.junit.Assert.*;
import java.util.Collection; import java.util.Collection;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -35,6 +37,7 @@ import org.openhab.core.thing.binding.builder.ThingBuilder;
* @author Oliver Libutzki - Initial contribution * @author Oliver Libutzki - Initial contribution
* @author Wouter Born - Migrate tests from Groovy to Java * @author Wouter Born - Migrate tests from Groovy to Java
*/ */
@NonNullByDefault
public class ManagedThingProviderOSGiTest extends JavaOSGiTest { public class ManagedThingProviderOSGiTest extends JavaOSGiTest {
private static final String BINDIND_ID = "testBinding"; private static final String BINDIND_ID = "testBinding";
@ -43,8 +46,8 @@ public class ManagedThingProviderOSGiTest extends JavaOSGiTest {
private static final String THING1_ID = "testThing1"; private static final String THING1_ID = "testThing1";
private static final String THING2_ID = "testThing2"; private static final String THING2_ID = "testThing2";
private ManagedThingProvider managedThingProvider; private @NonNullByDefault({}) ManagedThingProvider managedThingProvider;
private ProviderChangeListener<Thing> thingChangeListener; private @NonNullByDefault({}) ProviderChangeListener<@NonNull Thing> thingChangeListener;
@Before @Before
public void setup() { public void setup() {
@ -60,7 +63,7 @@ public class ManagedThingProviderOSGiTest extends JavaOSGiTest {
managedThingProvider.getAll().forEach(t -> managedThingProvider.remove(t.getUID())); managedThingProvider.getAll().forEach(t -> managedThingProvider.remove(t.getUID()));
} }
private void registerThingsChangeListener(ProviderChangeListener<Thing> thingChangeListener) { private void registerThingsChangeListener(ProviderChangeListener<@NonNull Thing> thingChangeListener) {
unregisterCurrentThingsChangeListener(); unregisterCurrentThingsChangeListener();
this.thingChangeListener = thingChangeListener; this.thingChangeListener = thingChangeListener;
managedThingProvider.addProviderChangeListener(this.thingChangeListener); managedThingProvider.addProviderChangeListener(this.thingChangeListener);

View File

@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -81,25 +82,24 @@ import org.osgi.service.component.ComponentContext;
* *
* @author Christoph Weitkamp - Initial contribution * @author Christoph Weitkamp - Initial contribution
*/ */
@NonNullByDefault
public class ChannelCommandDescriptionProviderOSGiTest extends JavaOSGiTest { public class ChannelCommandDescriptionProviderOSGiTest extends JavaOSGiTest {
private static final String TEST_BUNDLE_NAME = "thingStatusInfoI18nTest.bundle"; private static final String TEST_BUNDLE_NAME = "thingStatusInfoI18nTest.bundle";
private static final ChannelTypeUID CHANNEL_TYPE_UID = new ChannelTypeUID("hue:dynamic"); private static final ChannelTypeUID CHANNEL_TYPE_UID = new ChannelTypeUID("hue:dynamic");
private ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService; private @Mock @NonNullByDefault({}) ComponentContext componentContextMock;
private ItemRegistry itemRegistry;
private ItemChannelLinkRegistry linkRegistry;
@Mock private @NonNullByDefault({}) ItemRegistry itemRegistry;
private ComponentContext componentContext; private @NonNullByDefault({}) ItemChannelLinkRegistry linkRegistry;
private @NonNullByDefault({}) Bundle testBundle;
private Bundle testBundle; private @NonNullByDefault({}) ThingStatusInfoI18nLocalizationService thingStatusInfoI18nLocalizationService;
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
initMocks(this); initMocks(this);
Mockito.when(componentContext.getBundleContext()).thenReturn(bundleContext); Mockito.when(componentContextMock.getBundleContext()).thenReturn(bundleContext);
registerVolatileStorageService(); registerVolatileStorageService();
@ -107,7 +107,7 @@ public class ChannelCommandDescriptionProviderOSGiTest extends JavaOSGiTest {
assertNotNull(itemRegistry); assertNotNull(itemRegistry);
final TestThingHandlerFactory thingHandlerFactory = new TestThingHandlerFactory(); final TestThingHandlerFactory thingHandlerFactory = new TestThingHandlerFactory();
thingHandlerFactory.activate(componentContext); thingHandlerFactory.activate(componentContextMock);
registerService(thingHandlerFactory, ThingHandlerFactory.class.getName()); registerService(thingHandlerFactory, ThingHandlerFactory.class.getName());
final StateDescription state = StateDescriptionFragmentBuilder.create().withMinimum(BigDecimal.ZERO) final StateDescription state = StateDescriptionFragmentBuilder.create().withMinimum(BigDecimal.ZERO)
@ -132,12 +132,12 @@ public class ChannelCommandDescriptionProviderOSGiTest extends JavaOSGiTest {
registerService(new ChannelTypeProvider() { registerService(new ChannelTypeProvider() {
@Override @Override
public Collection<ChannelType> getChannelTypes(Locale locale) { public Collection<ChannelType> getChannelTypes(@Nullable Locale locale) {
return channelTypes; return channelTypes;
} }
@Override @Override
public ChannelType getChannelType(ChannelTypeUID channelTypeUID, Locale locale) { public @Nullable ChannelType getChannelType(ChannelTypeUID channelTypeUID, @Nullable Locale locale) {
for (final ChannelType channelType : channelTypes) { for (final ChannelType channelType : channelTypes) {
if (channelType.getUID().equals(channelTypeUID)) { if (channelType.getUID().equals(channelTypeUID)) {
return channelType; return channelType;
@ -337,7 +337,7 @@ public class ChannelCommandDescriptionProviderOSGiTest extends JavaOSGiTest {
} }
@Override @Override
protected ThingHandler createHandler(Thing thing) { protected @Nullable ThingHandler createHandler(Thing thing) {
return new AbstractThingHandler(thing) { return new AbstractThingHandler(thing) {
@Override @Override
public void handleCommand(ChannelUID channelUID, Command command) { public void handleCommand(ChannelUID channelUID, Command command) {
@ -385,7 +385,7 @@ public class ChannelCommandDescriptionProviderOSGiTest extends JavaOSGiTest {
*/ */
private class BundleResolverImpl implements BundleResolver { private class BundleResolverImpl implements BundleResolver {
@Override @Override
public Bundle resolveBundle(Class<?> clazz) { public Bundle resolveBundle(@NonNullByDefault({}) Class<?> clazz) {
if (clazz != null && clazz.equals(AbstractThingHandler.class)) { if (clazz != null && clazz.equals(AbstractThingHandler.class)) {
return testBundle; return testBundle;
} else { } else {

View File

@ -24,6 +24,7 @@ import java.util.stream.Stream;
import javax.measure.quantity.Temperature; import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
@ -82,6 +83,7 @@ import org.openhab.core.types.StateDescriptionFragmentBuilder;
* *
* @author Simon Kaufmann - Initial contribution * @author Simon Kaufmann - Initial contribution
*/ */
@NonNullByDefault
public class CommunicationManagerOSGiTest extends JavaOSGiTest { public class CommunicationManagerOSGiTest extends JavaOSGiTest {
private class ItemChannelLinkRegistryAdvanced extends ItemChannelLinkRegistry { private class ItemChannelLinkRegistryAdvanced extends ItemChannelLinkRegistry {
@ -130,39 +132,19 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
ChannelBuilder.create(TRIGGER_CHANNEL_UID_1, "").withKind(ChannelKind.TRIGGER).build(), ChannelBuilder.create(TRIGGER_CHANNEL_UID_1, "").withKind(ChannelKind.TRIGGER).build(),
ChannelBuilder.create(TRIGGER_CHANNEL_UID_2, "").withKind(ChannelKind.TRIGGER).build()).build(); ChannelBuilder.create(TRIGGER_CHANNEL_UID_2, "").withKind(ChannelKind.TRIGGER).build()).build();
private CommunicationManager manager; private @Mock @NonNullByDefault({}) AutoUpdateManager autoUpdateManagerMock;
private @Mock @NonNullByDefault({}) ChannelTypeRegistry channelTypeRegistryMock;
private @Mock @NonNullByDefault({}) EventPublisher eventPublisherMock;
private @Mock @NonNullByDefault({}) ItemRegistry itemRegistryMock;
private @Mock @NonNullByDefault({}) ProfileAdvisor profileAdvisorMock;
private @Mock @NonNullByDefault({}) ProfileFactory profileFactoryMock;
private @Mock @NonNullByDefault({}) StateProfile stateProfileMock;
private @Mock @NonNullByDefault({}) ThingHandler thingHandlerMock;
private @Mock @NonNullByDefault({}) ThingRegistry thingRegistryMock;
private @Mock @NonNullByDefault({}) TriggerProfile triggerProfileMock;
@Mock private @NonNullByDefault({}) CommunicationManager manager;
private ProfileFactory mockProfileFactory; private @NonNullByDefault({}) SafeCaller safeCaller;
@Mock
private ProfileAdvisor mockProfileAdvisor;
@Mock
private StateProfile stateProfile;
@Mock
private TriggerProfile triggerProfile;
@Mock
private EventPublisher eventPublisher;
@Mock
private ItemRegistry itemRegistry;
@Mock
private ThingRegistry thingRegistry;
@Mock
private ThingHandler mockHandler;
@Mock
private AutoUpdateManager mockAutoUpdateManager;
@Mock
private ChannelTypeRegistry channelTypeRegistry;
private SafeCaller safeCaller;
@Before @Before
public void setup() { public void setup() {
@ -175,7 +157,7 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
assertNotNull(profileFactory); assertNotNull(profileFactory);
manager = new CommunicationManager(); manager = new CommunicationManager();
manager.setEventPublisher(eventPublisher); manager.setEventPublisher(eventPublisherMock);
manager.setDefaultProfileFactory(profileFactory); manager.setDefaultProfileFactory(profileFactory);
manager.setSafeCaller(safeCaller); manager.setSafeCaller(safeCaller);
@ -187,25 +169,26 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
return new ProfileTypeUID("test:trigger"); return new ProfileTypeUID("test:trigger");
} }
return null; return null;
}).when(mockProfileAdvisor).getSuggestedProfileTypeUID(isA(Channel.class), isA(String.class)); }).when(profileAdvisorMock).getSuggestedProfileTypeUID(isA(Channel.class), isA(String.class));
doAnswer(invocation -> { doAnswer(invocation -> {
switch (((ProfileTypeUID) invocation.getArguments()[0]).toString()) { switch (((ProfileTypeUID) invocation.getArguments()[0]).toString()) {
case "test:state": case "test:state":
return stateProfile; return stateProfileMock;
case "test:trigger": case "test:trigger":
return triggerProfile; return triggerProfileMock;
} }
return null; return null;
}).when(mockProfileFactory).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class), }).when(profileFactoryMock).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class),
isA(ProfileContext.class)); isA(ProfileContext.class));
when(mockProfileFactory.getSupportedProfileTypeUIDs()).thenReturn(Stream when(profileFactoryMock.getSupportedProfileTypeUIDs()).thenReturn(Stream
.of(new ProfileTypeUID("test:state"), new ProfileTypeUID("test:trigger")).collect(Collectors.toList())); .of(new ProfileTypeUID("test:state"), new ProfileTypeUID("test:trigger")).collect(Collectors.toList()));
manager.addProfileFactory(mockProfileFactory); manager.addProfileFactory(profileFactoryMock);
manager.addProfileAdvisor(mockProfileAdvisor); manager.addProfileAdvisor(profileAdvisorMock);
ItemChannelLinkRegistryAdvanced iclRegistry = new ItemChannelLinkRegistryAdvanced(thingRegistry, itemRegistry); ItemChannelLinkRegistryAdvanced iclRegistry = new ItemChannelLinkRegistryAdvanced(thingRegistryMock,
itemRegistryMock);
iclRegistry.addProvider(new ItemChannelLinkProvider() { iclRegistry.addProvider(new ItemChannelLinkProvider() {
@Override @Override
public void addProviderChangeListener(ProviderChangeListener<ItemChannelLink> listener) { public void addProviderChangeListener(ProviderChangeListener<ItemChannelLink> listener) {
@ -223,24 +206,24 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
}); });
manager.setItemChannelLinkRegistry(iclRegistry); manager.setItemChannelLinkRegistry(iclRegistry);
when(itemRegistry.get(eq(ITEM_NAME_1))).thenReturn(ITEM_1); when(itemRegistryMock.get(eq(ITEM_NAME_1))).thenReturn(ITEM_1);
when(itemRegistry.get(eq(ITEM_NAME_2))).thenReturn(ITEM_2); when(itemRegistryMock.get(eq(ITEM_NAME_2))).thenReturn(ITEM_2);
when(itemRegistry.get(eq(ITEM_NAME_3))).thenReturn(ITEM_3); when(itemRegistryMock.get(eq(ITEM_NAME_3))).thenReturn(ITEM_3);
when(itemRegistry.get(eq(ITEM_NAME_4))).thenReturn(ITEM_4); when(itemRegistryMock.get(eq(ITEM_NAME_4))).thenReturn(ITEM_4);
manager.setItemRegistry(itemRegistry); manager.setItemRegistry(itemRegistryMock);
ChannelType channelType4 = mock(ChannelType.class); ChannelType channelType4 = mock(ChannelType.class);
when(channelType4.getItemType()).thenReturn("Number:Temperature"); when(channelType4.getItemType()).thenReturn("Number:Temperature");
when(channelTypeRegistry.getChannelType(CHANNEL_TYPE_UID_4)).thenReturn(channelType4); when(channelTypeRegistryMock.getChannelType(CHANNEL_TYPE_UID_4)).thenReturn(channelType4);
manager.setChannelTypeRegistry(channelTypeRegistry); manager.setChannelTypeRegistry(channelTypeRegistryMock);
THING.setHandler(mockHandler); THING.setHandler(thingHandlerMock);
when(thingRegistry.get(eq(THING_UID))).thenReturn(THING); when(thingRegistryMock.get(eq(THING_UID))).thenReturn(THING);
manager.setThingRegistry(thingRegistry); manager.setThingRegistry(thingRegistryMock);
manager.addItemFactory(new CoreItemFactory()); manager.addItemFactory(new CoreItemFactory());
manager.setAutoUpdateManager(mockAutoUpdateManager); manager.setAutoUpdateManager(autoUpdateManagerMock);
UnitProvider unitProvider = mock(UnitProvider.class); UnitProvider unitProvider = mock(UnitProvider.class);
when(unitProvider.getUnit(Temperature.class)).thenReturn(SIUnits.CELSIUS); when(unitProvider.getUnit(Temperature.class)).thenReturn(SIUnits.CELSIUS);
@ -252,51 +235,51 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
public void testStateUpdatedSingleLink() { public void testStateUpdatedSingleLink() {
manager.stateUpdated(STATE_CHANNEL_UID_1, OnOffType.ON); manager.stateUpdated(STATE_CHANNEL_UID_1, OnOffType.ON);
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile).onStateUpdateFromHandler(eq(OnOffType.ON)); verify(stateProfileMock).onStateUpdateFromHandler(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
public void testStateUpdatedMultiLink() { public void testStateUpdatedMultiLink() {
manager.stateUpdated(STATE_CHANNEL_UID_2, OnOffType.ON); manager.stateUpdated(STATE_CHANNEL_UID_2, OnOffType.ON);
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile, times(2)).onStateUpdateFromHandler(eq(OnOffType.ON)); verify(stateProfileMock, times(2)).onStateUpdateFromHandler(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
public void testPostCommandSingleLink() { public void testPostCommandSingleLink() {
manager.postCommand(STATE_CHANNEL_UID_1, OnOffType.ON); manager.postCommand(STATE_CHANNEL_UID_1, OnOffType.ON);
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile).onCommandFromHandler(eq(OnOffType.ON)); verify(stateProfileMock).onCommandFromHandler(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
public void testPostCommandMultiLink() { public void testPostCommandMultiLink() {
manager.postCommand(STATE_CHANNEL_UID_2, OnOffType.ON); manager.postCommand(STATE_CHANNEL_UID_2, OnOffType.ON);
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile, times(2)).onCommandFromHandler(eq(OnOffType.ON)); verify(stateProfileMock, times(2)).onCommandFromHandler(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
public void testItemCommandEventSingleLink() { public void testItemCommandEventSingleLink() {
manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_2, OnOffType.ON)); manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_2, OnOffType.ON));
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile).onCommandFromItem(eq(OnOffType.ON)); verify(stateProfileMock).onCommandFromItem(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
verify(mockAutoUpdateManager).receiveCommand(isA(ItemCommandEvent.class), isA(Item.class)); verify(autoUpdateManagerMock).receiveCommand(isA(ItemCommandEvent.class), isA(Item.class));
} }
@Test @Test
@ -304,10 +287,10 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
// Take unit from accepted item type (see channel built from STATE_CHANNEL_UID_3) // Take unit from accepted item type (see channel built from STATE_CHANNEL_UID_3)
manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_3, DecimalType.valueOf("20"))); manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_3, DecimalType.valueOf("20")));
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile).onCommandFromItem(eq(QuantityType.valueOf("20 °C"))); verify(stateProfileMock).onCommandFromItem(eq(QuantityType.valueOf("20 °C")));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
@ -320,10 +303,10 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_3, DecimalType.valueOf("20"))); manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_3, DecimalType.valueOf("20")));
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile).onCommandFromItem(eq(QuantityType.valueOf("20 °F"))); verify(stateProfileMock).onCommandFromItem(eq(QuantityType.valueOf("20 °F")));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
ITEM_3.setStateDescriptionService(null); ITEM_3.setStateDescriptionService(null);
} }
@ -335,21 +318,21 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
// current ThingType. // current ThingType.
manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_4, DecimalType.valueOf("20"))); manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_4, DecimalType.valueOf("20")));
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile).onCommandFromItem(eq(QuantityType.valueOf("20 °C"))); verify(stateProfileMock).onCommandFromItem(eq(QuantityType.valueOf("20 °C")));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
public void testItemCommandEventMultiLink() { public void testItemCommandEventMultiLink() {
manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_1, OnOffType.ON)); manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_1, OnOffType.ON));
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile, times(2)).onCommandFromItem(eq(OnOffType.ON)); verify(stateProfileMock, times(2)).onCommandFromItem(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
verify(mockAutoUpdateManager).receiveCommand(isA(ItemCommandEvent.class), isA(Item.class)); verify(autoUpdateManagerMock).receiveCommand(isA(ItemCommandEvent.class), isA(Item.class));
} }
@Test @Test
@ -357,33 +340,33 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
manager.receive( manager.receive(
ItemEventFactory.createCommandEvent(ITEM_NAME_1, OnOffType.ON, STATE_CHANNEL_UID_2.getAsString())); ItemEventFactory.createCommandEvent(ITEM_NAME_1, OnOffType.ON, STATE_CHANNEL_UID_2.getAsString()));
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile).onCommandFromItem(eq(OnOffType.ON)); verify(stateProfileMock).onCommandFromItem(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
verify(mockAutoUpdateManager).receiveCommand(isA(ItemCommandEvent.class), isA(Item.class)); verify(autoUpdateManagerMock).receiveCommand(isA(ItemCommandEvent.class), isA(Item.class));
} }
@Test @Test
public void testItemStateEventSingleLink() { public void testItemStateEventSingleLink() {
manager.receive(ItemEventFactory.createStateEvent(ITEM_NAME_2, OnOffType.ON)); manager.receive(ItemEventFactory.createStateEvent(ITEM_NAME_2, OnOffType.ON));
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile).onStateUpdateFromItem(eq(OnOffType.ON)); verify(stateProfileMock).onStateUpdateFromItem(eq(OnOffType.ON));
verify(triggerProfile).onStateUpdateFromItem(eq(OnOffType.ON)); verify(triggerProfileMock).onStateUpdateFromItem(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
public void testItemStateEventMultiLink() { public void testItemStateEventMultiLink() {
manager.receive(ItemEventFactory.createStateEvent(ITEM_NAME_1, OnOffType.ON)); manager.receive(ItemEventFactory.createStateEvent(ITEM_NAME_1, OnOffType.ON));
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile, times(2)).onStateUpdateFromItem(eq(OnOffType.ON)); verify(stateProfileMock, times(2)).onStateUpdateFromItem(eq(OnOffType.ON));
verify(triggerProfile, times(2)).onStateUpdateFromItem(eq(OnOffType.ON)); verify(triggerProfileMock, times(2)).onStateUpdateFromItem(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
@ -391,31 +374,31 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
manager.receive( manager.receive(
ItemEventFactory.createStateEvent(ITEM_NAME_1, OnOffType.ON, STATE_CHANNEL_UID_2.getAsString())); ItemEventFactory.createStateEvent(ITEM_NAME_1, OnOffType.ON, STATE_CHANNEL_UID_2.getAsString()));
waitForAssert(() -> { waitForAssert(() -> {
verify(stateProfile).onStateUpdateFromItem(eq(OnOffType.ON)); verify(stateProfileMock).onStateUpdateFromItem(eq(OnOffType.ON));
verify(triggerProfile, times(2)).onStateUpdateFromItem(eq(OnOffType.ON)); verify(triggerProfileMock, times(2)).onStateUpdateFromItem(eq(OnOffType.ON));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
public void testChannelTriggeredEventSingleLink() { public void testChannelTriggeredEventSingleLink() {
manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_1)); manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_1));
waitForAssert(() -> { waitForAssert(() -> {
verify(triggerProfile).onTriggerFromHandler(eq(EVENT)); verify(triggerProfileMock).onTriggerFromHandler(eq(EVENT));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
public void testChannelTriggeredEventMultiLink() { public void testChannelTriggeredEventMultiLink() {
manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2)); manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2));
waitForAssert(() -> { waitForAssert(() -> {
verify(triggerProfile, times(2)).onTriggerFromHandler(eq(EVENT)); verify(triggerProfileMock, times(2)).onTriggerFromHandler(eq(EVENT));
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
@ -425,13 +408,13 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
} }
waitForAssert(() -> { waitForAssert(() -> {
verify(mockProfileFactory, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class), verify(profileFactoryMock, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class),
isA(ProfileContext.class)); isA(ProfileContext.class));
verify(mockProfileFactory, atLeast(0)).getSupportedProfileTypeUIDs(); verify(profileFactoryMock, atLeast(0)).getSupportedProfileTypeUIDs();
verify(mockProfileAdvisor, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any()); verify(profileAdvisorMock, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any());
}); });
verifyNoMoreInteractions(mockProfileFactory); verifyNoMoreInteractions(profileFactoryMock);
verifyNoMoreInteractions(mockProfileAdvisor); verifyNoMoreInteractions(profileAdvisorMock);
} }
@Test @Test
@ -439,24 +422,24 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2)); manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2));
} }
verify(mockProfileFactory, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class), verify(profileFactoryMock, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class),
isA(ProfileContext.class)); isA(ProfileContext.class));
manager.removeProfileFactory(mockProfileFactory); manager.removeProfileFactory(profileFactoryMock);
manager.addProfileFactory(mockProfileFactory); manager.addProfileFactory(profileFactoryMock);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2)); manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2));
} }
waitForAssert(() -> { waitForAssert(() -> {
verify(mockProfileFactory, times(4)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class), verify(profileFactoryMock, times(4)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class),
isA(ProfileContext.class)); isA(ProfileContext.class));
verify(mockProfileFactory, atLeast(0)).getSupportedProfileTypeUIDs(); verify(profileFactoryMock, atLeast(0)).getSupportedProfileTypeUIDs();
verify(mockProfileAdvisor, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any()); verify(profileAdvisorMock, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any());
}); });
verifyNoMoreInteractions(mockProfileFactory); verifyNoMoreInteractions(profileFactoryMock);
verifyNoMoreInteractions(mockProfileAdvisor); verifyNoMoreInteractions(profileAdvisorMock);
} }
@Test @Test
@ -465,7 +448,7 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2)); manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2));
} }
waitForAssert(() -> { waitForAssert(() -> {
verify(mockProfileFactory, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class), verify(profileFactoryMock, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class),
isA(ProfileContext.class)); isA(ProfileContext.class));
}); });
@ -477,13 +460,13 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
} }
waitForAssert(() -> { waitForAssert(() -> {
verify(mockProfileFactory, times(3)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class), verify(profileFactoryMock, times(3)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class),
isA(ProfileContext.class)); isA(ProfileContext.class));
verify(mockProfileFactory, atLeast(0)).getSupportedProfileTypeUIDs(); verify(profileFactoryMock, atLeast(0)).getSupportedProfileTypeUIDs();
verify(mockProfileAdvisor, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any()); verify(profileAdvisorMock, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any());
}); });
verifyNoMoreInteractions(mockProfileFactory); verifyNoMoreInteractions(profileFactoryMock);
verifyNoMoreInteractions(mockProfileAdvisor); verifyNoMoreInteractions(profileAdvisorMock);
} }
@Test @Test
@ -500,13 +483,13 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
} }
waitForAssert(() -> { waitForAssert(() -> {
verify(mockProfileFactory, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class), verify(profileFactoryMock, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class),
isA(ProfileContext.class)); isA(ProfileContext.class));
verify(mockProfileFactory, atLeast(0)).getSupportedProfileTypeUIDs(); verify(profileFactoryMock, atLeast(0)).getSupportedProfileTypeUIDs();
verify(mockProfileAdvisor, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any()); verify(profileAdvisorMock, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any());
}); });
verifyNoMoreInteractions(mockProfileFactory); verifyNoMoreInteractions(profileFactoryMock);
verifyNoMoreInteractions(mockProfileAdvisor); verifyNoMoreInteractions(profileAdvisorMock);
} }
@Test @Test
@ -514,7 +497,7 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2)); manager.receive(ThingEventFactory.createTriggerEvent(EVENT, TRIGGER_CHANNEL_UID_2));
} }
verify(mockProfileFactory, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class), verify(profileFactoryMock, times(2)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class),
isA(ProfileContext.class)); isA(ProfileContext.class));
manager.updated(LINK_2_T2, LINK_2_T2); manager.updated(LINK_2_T2, LINK_2_T2);
@ -524,13 +507,13 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
} }
waitForAssert(() -> { waitForAssert(() -> {
verify(mockProfileFactory, times(3)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class), verify(profileFactoryMock, times(3)).createProfile(isA(ProfileTypeUID.class), isA(ProfileCallback.class),
isA(ProfileContext.class)); isA(ProfileContext.class));
verify(mockProfileFactory, atLeast(0)).getSupportedProfileTypeUIDs(); verify(profileFactoryMock, atLeast(0)).getSupportedProfileTypeUIDs();
verify(mockProfileAdvisor, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any()); verify(profileAdvisorMock, atLeast(0)).getSuggestedProfileTypeUID(any(Channel.class), any());
}); });
verifyNoMoreInteractions(mockProfileFactory); verifyNoMoreInteractions(profileFactoryMock);
verifyNoMoreInteractions(mockProfileAdvisor); verifyNoMoreInteractions(profileAdvisorMock);
} }
@Test @Test
@ -538,19 +521,19 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
Thing thing = ThingBuilder.create(THING_TYPE_UID, THING_UID) Thing thing = ThingBuilder.create(THING_TYPE_UID, THING_UID)
.withChannels(ChannelBuilder.create(STATE_CHANNEL_UID_2, "Dimmer").withKind(ChannelKind.STATE).build()) .withChannels(ChannelBuilder.create(STATE_CHANNEL_UID_2, "Dimmer").withKind(ChannelKind.STATE).build())
.build(); .build();
thing.setHandler(mockHandler); thing.setHandler(thingHandlerMock);
when(thingRegistry.get(eq(THING_UID))).thenReturn(thing); when(thingRegistryMock.get(eq(THING_UID))).thenReturn(thing);
manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_2, HSBType.fromRGB(128, 128, 128))); manager.receive(ItemEventFactory.createCommandEvent(ITEM_NAME_2, HSBType.fromRGB(128, 128, 128)));
waitForAssert(() -> { waitForAssert(() -> {
ArgumentCaptor<Command> commandCaptor = ArgumentCaptor.forClass(Command.class); ArgumentCaptor<Command> commandCaptor = ArgumentCaptor.forClass(Command.class);
verify(stateProfile).onCommandFromItem(commandCaptor.capture()); verify(stateProfileMock).onCommandFromItem(commandCaptor.capture());
Command command = commandCaptor.getValue(); Command command = commandCaptor.getValue();
assertNotNull(command); assertNotNull(command);
assertEquals(PercentType.class, command.getClass()); assertEquals(PercentType.class, command.getClass());
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
@Test @Test
@ -558,19 +541,19 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
Thing thing = ThingBuilder.create(THING_TYPE_UID, THING_UID) Thing thing = ThingBuilder.create(THING_TYPE_UID, THING_UID)
.withChannels(ChannelBuilder.create(STATE_CHANNEL_UID_2, "Dimmer").withKind(ChannelKind.STATE).build()) .withChannels(ChannelBuilder.create(STATE_CHANNEL_UID_2, "Dimmer").withKind(ChannelKind.STATE).build())
.build(); .build();
thing.setHandler(mockHandler); thing.setHandler(thingHandlerMock);
when(thingRegistry.get(eq(THING_UID))).thenReturn(thing); when(thingRegistryMock.get(eq(THING_UID))).thenReturn(thing);
manager.receive(ItemEventFactory.createStateEvent(ITEM_NAME_2, HSBType.fromRGB(128, 128, 128))); manager.receive(ItemEventFactory.createStateEvent(ITEM_NAME_2, HSBType.fromRGB(128, 128, 128)));
waitForAssert(() -> { waitForAssert(() -> {
ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class); ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
verify(stateProfile).onStateUpdateFromItem(stateCaptor.capture()); verify(stateProfileMock).onStateUpdateFromItem(stateCaptor.capture());
State state = stateCaptor.getValue(); State state = stateCaptor.getValue();
assertNotNull(state); assertNotNull(state);
assertEquals(PercentType.class, state.getClass()); assertEquals(PercentType.class, state.getClass());
}); });
verifyNoMoreInteractions(stateProfile); verifyNoMoreInteractions(stateProfileMock);
verifyNoMoreInteractions(triggerProfile); verifyNoMoreInteractions(triggerProfileMock);
} }
} }