mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-25 19:55:48 +01:00
Fixed removal / replacement of annotated ThingActions (#1536)
Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
parent
4585dac84a
commit
c747f7f9bb
@ -169,8 +169,8 @@ public class AnnotatedActionModuleTypeProvider extends BaseModuleHandlerFactory
|
||||
|
||||
for (ModuleInformation mi : moduleInformations) {
|
||||
mi.setConfigName(configName);
|
||||
ModuleType oldType = null;
|
||||
|
||||
ModuleType oldType = null;
|
||||
Set<ModuleInformation> availableModuleConfigs = moduleInformation.get(mi.getUID());
|
||||
if (availableModuleConfigs != null) {
|
||||
if (availableModuleConfigs.size() > 1) {
|
||||
@ -181,11 +181,14 @@ public class AnnotatedActionModuleTypeProvider extends BaseModuleHandlerFactory
|
||||
}
|
||||
|
||||
ModuleType mt = helper.buildModuleType(mi.getUID(), moduleInformation);
|
||||
for (ProviderChangeListener<ModuleType> l : changeListeners) {
|
||||
if (oldType != null) {
|
||||
l.updated(this, oldType, mt);
|
||||
} else {
|
||||
l.removed(this, mt);
|
||||
// localize moduletype -> remove from map
|
||||
if (mt != null) {
|
||||
for (ProviderChangeListener<ModuleType> l : changeListeners) {
|
||||
if (oldType != null) {
|
||||
l.updated(this, oldType, mt);
|
||||
} else {
|
||||
l.removed(this, mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,8 +204,6 @@ public class AnnotatedActionModuleTypeProvider extends BaseModuleHandlerFactory
|
||||
return configName;
|
||||
}
|
||||
|
||||
// HandlerFactory:
|
||||
|
||||
@Override
|
||||
public Collection<String> getTypes() {
|
||||
return moduleInformation.keySet();
|
||||
@ -212,11 +213,9 @@ public class AnnotatedActionModuleTypeProvider extends BaseModuleHandlerFactory
|
||||
protected @Nullable ModuleHandler internalCreate(Module module, String ruleUID) {
|
||||
if (module instanceof Action) {
|
||||
Action actionModule = (Action) module;
|
||||
|
||||
if (moduleInformation.containsKey(actionModule.getTypeUID())) {
|
||||
ModuleInformation finalMI = helper.getModuleInformationForIdentifier(actionModule, moduleInformation,
|
||||
false);
|
||||
|
||||
if (finalMI != null) {
|
||||
ActionType moduleType = helper.buildModuleType(module.getTypeUID(), moduleInformation);
|
||||
return new AnnotationActionHandler(actionModule, moduleType, finalMI.getMethod(),
|
||||
|
@ -26,7 +26,10 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.automation.Action;
|
||||
import org.openhab.core.automation.AnnotatedActions;
|
||||
import org.openhab.core.automation.annotation.ActionInput;
|
||||
import org.openhab.core.automation.annotation.ActionOutput;
|
||||
import org.openhab.core.automation.annotation.ActionOutputs;
|
||||
@ -34,6 +37,7 @@ import org.openhab.core.automation.annotation.ActionScope;
|
||||
import org.openhab.core.automation.annotation.RuleAction;
|
||||
import org.openhab.core.automation.type.ActionType;
|
||||
import org.openhab.core.automation.type.Input;
|
||||
import org.openhab.core.automation.type.ModuleTypeProvider;
|
||||
import org.openhab.core.automation.type.Output;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter.Type;
|
||||
@ -44,10 +48,11 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Helper methods for annotated ActionModuleType provider
|
||||
* Helper methods for {@link AnnotatedActions} {@link ModuleTypeProvider}
|
||||
*
|
||||
* @author Stefan Triller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AnnotationActionModuleTypeHelper {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AnnotationActionModuleTypeHelper.class);
|
||||
@ -56,20 +61,18 @@ public class AnnotationActionModuleTypeHelper {
|
||||
private static final String SELECT_THING_LABEL = "Select Thing";
|
||||
public static final String CONFIG_PARAM = "config";
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public Collection<ModuleInformation> parseAnnotations(Object actionProvider) {
|
||||
Class clazz = actionProvider.getClass();
|
||||
Class<?> clazz = actionProvider.getClass();
|
||||
if (clazz.isAnnotationPresent(ActionScope.class)) {
|
||||
ActionScope scope = (ActionScope) clazz.getAnnotation(ActionScope.class);
|
||||
ActionScope scope = clazz.getAnnotation(ActionScope.class);
|
||||
return parseAnnotations(scope.name(), actionProvider);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
public Collection<ModuleInformation> parseAnnotations(String name, Object actionProvider) {
|
||||
Collection<ModuleInformation> moduleInformation = new ArrayList<>();
|
||||
Class clazz = actionProvider.getClass();
|
||||
Class<?> clazz = actionProvider.getClass();
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if (method.isAnnotationPresent(RuleAction.class)) {
|
||||
@ -103,11 +106,10 @@ public class AnnotationActionModuleTypeHelper {
|
||||
for (int i = 0; i < annotations.length; i++) {
|
||||
Parameter param = params[i];
|
||||
Annotation[] paramAnnotations = annotations[i];
|
||||
Input input = null;
|
||||
if (paramAnnotations.length == 0) {
|
||||
// we do not have an annotation with a name for this parameter
|
||||
input = new Input("p" + i, param.getType().getCanonicalName(), "", "", Collections.<String> emptySet(),
|
||||
false, "", "");
|
||||
inputs.add(new Input("p" + i, param.getType().getCanonicalName(), "", "", Collections.emptySet(), false,
|
||||
"", ""));
|
||||
} else if (paramAnnotations.length == 1) {
|
||||
Annotation a = paramAnnotations[0];
|
||||
if (a instanceof ActionInput) {
|
||||
@ -121,12 +123,11 @@ public class AnnotationActionModuleTypeHelper {
|
||||
type = param.getType().getCanonicalName();
|
||||
}
|
||||
|
||||
input = new Input(inp.name(), type, inp.label(), inp.description(),
|
||||
inputs.add(new Input(inp.name(), type, inp.label(), inp.description(),
|
||||
Arrays.stream(inp.tags()).collect(Collectors.toSet()), inp.required(), inp.reference(),
|
||||
inp.defaultValue());
|
||||
inp.defaultValue()));
|
||||
}
|
||||
}
|
||||
inputs.add(input);
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
@ -146,7 +147,7 @@ public class AnnotationActionModuleTypeHelper {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
public ActionType buildModuleType(String UID, Map<String, Set<ModuleInformation>> moduleInformation) {
|
||||
public @Nullable ActionType buildModuleType(String UID, Map<String, Set<ModuleInformation>> moduleInformation) {
|
||||
Set<ModuleInformation> mis = moduleInformation.get(UID);
|
||||
List<ConfigDescriptionParameter> configDescriptions = new ArrayList<>();
|
||||
|
||||
@ -177,7 +178,7 @@ public class AnnotationActionModuleTypeHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ConfigDescriptionParameter buildConfigParam(Set<ModuleInformation> moduleInformations,
|
||||
private @Nullable ConfigDescriptionParameter buildConfigParam(Set<ModuleInformation> moduleInformations,
|
||||
ActionModuleKind kind) {
|
||||
List<ParameterOption> options = new ArrayList<>();
|
||||
if (kind == ActionModuleKind.SINGLE) {
|
||||
@ -206,8 +207,8 @@ public class AnnotationActionModuleTypeHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ModuleInformation getModuleInformationForIdentifier(Action module,
|
||||
Map<String, Set<ModuleInformation>> moduleInformation, boolean thing) {
|
||||
public @Nullable ModuleInformation getModuleInformationForIdentifier(Action module,
|
||||
Map<String, Set<ModuleInformation>> moduleInformation, boolean isThing) {
|
||||
Configuration c = module.getConfiguration();
|
||||
String config = (String) c.get(AnnotationActionModuleTypeHelper.CONFIG_PARAM);
|
||||
|
||||
@ -218,7 +219,7 @@ public class AnnotationActionModuleTypeHelper {
|
||||
finalMI = (ModuleInformation) mis.toArray()[0];
|
||||
} else {
|
||||
for (ModuleInformation mi : mis) {
|
||||
if (thing) {
|
||||
if (isThing) {
|
||||
if (Objects.equals(mi.getThingUID(), config)) {
|
||||
finalMI = mi;
|
||||
break;
|
||||
|
@ -43,9 +43,12 @@ import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.component.annotations.ReferenceCardinality;
|
||||
import org.osgi.service.component.annotations.ReferencePolicy;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ModuleTypeProvider that collects actions for {@link ThingHandler}s
|
||||
@ -56,6 +59,8 @@ import org.osgi.service.component.annotations.ReferencePolicy;
|
||||
@Component(service = { ModuleTypeProvider.class, ModuleHandlerFactory.class })
|
||||
public class AnnotatedThingActionModuleTypeProvider extends BaseModuleHandlerFactory implements ModuleTypeProvider {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AnnotatedThingActionModuleTypeProvider.class);
|
||||
|
||||
private final Collection<ProviderChangeListener<ModuleType>> changeListeners = ConcurrentHashMap.newKeySet();
|
||||
private final Map<String, Set<ModuleInformation>> moduleInformation = new ConcurrentHashMap<>();
|
||||
private final AnnotationActionModuleTypeHelper helper = new AnnotationActionModuleTypeHelper();
|
||||
@ -67,72 +72,10 @@ public class AnnotatedThingActionModuleTypeProvider extends BaseModuleHandlerFac
|
||||
this.moduleTypeI18nService = moduleTypeI18nService;
|
||||
}
|
||||
|
||||
@Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.MULTIPLE)
|
||||
public void addAnnotatedThingActions(ThingActions annotatedThingActions) {
|
||||
if (annotatedThingActions.getClass().isAnnotationPresent(ThingActionsScope.class)) {
|
||||
ThingActionsScope scope = annotatedThingActions.getClass().getAnnotation(ThingActionsScope.class);
|
||||
Collection<ModuleInformation> moduleInformations = helper.parseAnnotations(scope.name(),
|
||||
annotatedThingActions);
|
||||
|
||||
String thingUID = annotatedThingActions.getThingHandler().getThing().getUID().getAsString();
|
||||
|
||||
for (ModuleInformation mi : moduleInformations) {
|
||||
mi.setThingUID(thingUID);
|
||||
|
||||
ModuleType oldType = null;
|
||||
if (moduleInformation.containsKey(mi.getUID())) {
|
||||
oldType = helper.buildModuleType(mi.getUID(), moduleInformation);
|
||||
Set<ModuleInformation> availableModuleConfigs = moduleInformation.get(mi.getUID());
|
||||
availableModuleConfigs.add(mi);
|
||||
} else {
|
||||
Set<ModuleInformation> configs = ConcurrentHashMap.newKeySet();
|
||||
configs.add(mi);
|
||||
moduleInformation.put(mi.getUID(), configs);
|
||||
}
|
||||
|
||||
ModuleType mt = helper.buildModuleType(mi.getUID(), moduleInformation);
|
||||
if (mt != null) {
|
||||
for (ProviderChangeListener<ModuleType> l : changeListeners) {
|
||||
if (oldType != null) {
|
||||
l.updated(this, oldType, mt);
|
||||
} else {
|
||||
l.added(this, mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAnnotatedThingActions(ThingActions annotatedThingActions, Map<String, Object> properties) {
|
||||
Collection<ModuleInformation> moduleInformations = helper.parseAnnotations(annotatedThingActions);
|
||||
|
||||
String thingUID = annotatedThingActions.getThingHandler().getThing().getUID().getAsString();
|
||||
|
||||
for (ModuleInformation mi : moduleInformations) {
|
||||
mi.setThingUID(thingUID);
|
||||
ModuleType oldType = null;
|
||||
|
||||
Set<ModuleInformation> availableModuleConfigs = moduleInformation.get(mi.getUID());
|
||||
if (availableModuleConfigs != null) {
|
||||
if (availableModuleConfigs.size() > 1) {
|
||||
oldType = helper.buildModuleType(mi.getUID(), moduleInformation);
|
||||
availableModuleConfigs.remove(mi);
|
||||
} else {
|
||||
moduleInformation.remove(mi.getUID());
|
||||
}
|
||||
|
||||
ModuleType mt = helper.buildModuleType(mi.getUID(), moduleInformation);
|
||||
// localize moduletype -> remove from map
|
||||
for (ProviderChangeListener<ModuleType> l : changeListeners) {
|
||||
if (oldType != null) {
|
||||
l.updated(this, oldType, mt);
|
||||
} else {
|
||||
l.removed(this, mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
@Deactivate
|
||||
protected void deactivate() {
|
||||
moduleInformation.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -140,6 +83,11 @@ public class AnnotatedThingActionModuleTypeProvider extends BaseModuleHandlerFac
|
||||
changeListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProviderChangeListener(ProviderChangeListener<ModuleType> listener) {
|
||||
changeListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ModuleType> getAll() {
|
||||
Collection<ModuleType> moduleTypes = new ArrayList<>();
|
||||
@ -152,16 +100,6 @@ public class AnnotatedThingActionModuleTypeProvider extends BaseModuleHandlerFac
|
||||
return moduleTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProviderChangeListener(ProviderChangeListener<ModuleType> listener) {
|
||||
changeListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getTypes() {
|
||||
return moduleInformation.keySet();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends ModuleType> T getModuleType(String UID, @Nullable Locale locale) {
|
||||
@ -195,15 +133,107 @@ public class AnnotatedThingActionModuleTypeProvider extends BaseModuleHandlerFac
|
||||
return null;
|
||||
}
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
|
||||
public void addAnnotatedThingActions(ThingActions annotatedThingActions) {
|
||||
if (annotatedThingActions.getClass().isAnnotationPresent(ThingActionsScope.class)) {
|
||||
ThingActionsScope scope = annotatedThingActions.getClass().getAnnotation(ThingActionsScope.class);
|
||||
Collection<ModuleInformation> moduleInformations = helper.parseAnnotations(scope.name(),
|
||||
annotatedThingActions);
|
||||
|
||||
String thingUID = getThingUID(annotatedThingActions);
|
||||
|
||||
for (ModuleInformation mi : moduleInformations) {
|
||||
mi.setThingUID(thingUID);
|
||||
|
||||
ModuleType oldType = null;
|
||||
if (moduleInformation.containsKey(mi.getUID())) {
|
||||
oldType = helper.buildModuleType(mi.getUID(), moduleInformation);
|
||||
Set<ModuleInformation> availableModuleConfigs = moduleInformation.get(mi.getUID());
|
||||
availableModuleConfigs.add(mi);
|
||||
} else {
|
||||
Set<ModuleInformation> configs = ConcurrentHashMap.newKeySet();
|
||||
configs.add(mi);
|
||||
moduleInformation.put(mi.getUID(), configs);
|
||||
}
|
||||
|
||||
ModuleType mt = helper.buildModuleType(mi.getUID(), moduleInformation);
|
||||
if (mt != null) {
|
||||
for (ProviderChangeListener<ModuleType> l : changeListeners) {
|
||||
if (oldType != null) {
|
||||
l.updated(this, oldType, mt);
|
||||
} else {
|
||||
l.added(this, mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.error("Missing 'ThingActionsScope' for '{}'. Please add it to your class definition.",
|
||||
annotatedThingActions.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAnnotatedThingActions(ThingActions annotatedThingActions) {
|
||||
if (annotatedThingActions.getClass().isAnnotationPresent(ThingActionsScope.class)) {
|
||||
ThingActionsScope scope = annotatedThingActions.getClass().getAnnotation(ThingActionsScope.class);
|
||||
Collection<ModuleInformation> moduleInformations = helper.parseAnnotations(scope.name(),
|
||||
annotatedThingActions);
|
||||
|
||||
String thingUID = getThingUID(annotatedThingActions);
|
||||
|
||||
for (ModuleInformation mi : moduleInformations) {
|
||||
mi.setThingUID(thingUID);
|
||||
|
||||
ModuleType oldType = null;
|
||||
Set<ModuleInformation> availableModuleConfigs = moduleInformation.get(mi.getUID());
|
||||
if (availableModuleConfigs != null) {
|
||||
if (availableModuleConfigs.size() > 1) {
|
||||
oldType = helper.buildModuleType(mi.getUID(), moduleInformation);
|
||||
availableModuleConfigs.remove(mi);
|
||||
} else {
|
||||
moduleInformation.remove(mi.getUID());
|
||||
}
|
||||
|
||||
ModuleType mt = helper.buildModuleType(mi.getUID(), moduleInformation);
|
||||
// localize moduletype -> remove from map
|
||||
if (mt != null) {
|
||||
for (ProviderChangeListener<ModuleType> l : changeListeners) {
|
||||
if (oldType != null) {
|
||||
l.updated(this, oldType, mt);
|
||||
} else {
|
||||
l.removed(this, mt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.error("Missing 'ThingActionsScope' for '{}'. Please add it to your class definition.",
|
||||
annotatedThingActions.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
private String getThingUID(ThingActions annotatedThingActions) {
|
||||
ThingHandler handler = annotatedThingActions.getThingHandler();
|
||||
if (handler == null) {
|
||||
throw new RuntimeException(
|
||||
String.format("ThingHandler for '%s' is missing.", annotatedThingActions.getClass()));
|
||||
}
|
||||
return handler.getThing().getUID().getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getTypes() {
|
||||
return moduleInformation.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ModuleHandler internalCreate(Module module, String ruleUID) {
|
||||
if (module instanceof Action) {
|
||||
Action actionModule = (Action) module;
|
||||
|
||||
if (moduleInformation.containsKey(actionModule.getTypeUID())) {
|
||||
ModuleInformation finalMI = helper.getModuleInformationForIdentifier(actionModule, moduleInformation,
|
||||
true);
|
||||
|
||||
if (finalMI != null) {
|
||||
ActionType moduleType = helper.buildModuleType(module.getTypeUID(), moduleInformation);
|
||||
return new AnnotationActionHandler(actionModule, moduleType, finalMI.getMethod(),
|
||||
|
@ -0,0 +1,233 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.automation.thingsupport;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.openhab.core.automation.Visibility;
|
||||
import org.openhab.core.automation.annotation.ActionInput;
|
||||
import org.openhab.core.automation.annotation.ActionOutput;
|
||||
import org.openhab.core.automation.annotation.RuleAction;
|
||||
import org.openhab.core.automation.module.provider.AnnotationActionModuleTypeHelper;
|
||||
import org.openhab.core.automation.module.provider.i18n.ModuleTypeI18nService;
|
||||
import org.openhab.core.automation.type.ActionType;
|
||||
import org.openhab.core.automation.type.Input;
|
||||
import org.openhab.core.automation.type.ModuleType;
|
||||
import org.openhab.core.automation.type.Output;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.config.core.ParameterOption;
|
||||
import org.openhab.core.test.java.JavaTest;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.ThingActions;
|
||||
import org.openhab.core.thing.binding.ThingActionsScope;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
|
||||
/**
|
||||
* Tests for the {@link AnnotatedThingActionModuleTypeProvider}
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class AnnotatedThingActionModuleTypeProviderTest extends JavaTest {
|
||||
|
||||
private static final ThingTypeUID TEST_THING_TYPE_UID = new ThingTypeUID("binding", "thing-type");
|
||||
|
||||
private static final String TEST_ACTION_TYPE_ID = "test.testMethod";
|
||||
private static final String ACTION_LABEL = "Test Label";
|
||||
private static final String ACTION_DESCRIPTION = "My Description";
|
||||
|
||||
private static final String ACTION_INPUT1 = "input1";
|
||||
private static final String ACTION_INPUT1_DESCRIPTION = "input1 description";
|
||||
private static final String ACTION_INPUT1_LABEL = "input1 label";
|
||||
private static final String ACTION_INPUT1_DEFAULT_VALUE = "input1 default";
|
||||
private static final String ACTION_INPUT1_REFERENCE = "input1 reference";
|
||||
private static final String ACTION_INPUT2 = "input2";
|
||||
private static final String ACTION_OUTPUT1 = "output1";
|
||||
private static final String ACTION_OUTPUT1_DESCRIPTION = "output1 description";
|
||||
private static final String ACTION_OUTPUT1_LABEL = "output1 label";
|
||||
private static final String ACTION_OUTPUT1_DEFAULT_VALUE = "output1 default";
|
||||
private static final String ACTION_OUTPUT1_REFERENCE = "output1 reference";
|
||||
private static final String ACTION_OUTPUT1_TYPE = "java.lang.Integer";
|
||||
private static final String ACTION_OUTPUT2 = "output2";
|
||||
private static final String ACTION_OUTPUT2_TYPE = "java.lang.String";
|
||||
|
||||
private ModuleTypeI18nService moduleTypeI18nService;
|
||||
|
||||
private ThingHandler mockHandler1;
|
||||
private ThingHandler mockHandler2;
|
||||
|
||||
private ThingActions actionProviderConf1;
|
||||
private ThingActions actionProviderConf2;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mockHandler1 = mock(ThingHandler.class);
|
||||
when(mockHandler1.getThing()).thenReturn(ThingBuilder.create(TEST_THING_TYPE_UID, "test1").build());
|
||||
|
||||
actionProviderConf1 = new TestThingActionProvider();
|
||||
actionProviderConf1.setThingHandler(mockHandler1);
|
||||
|
||||
mockHandler2 = mock(ThingHandler.class);
|
||||
when(mockHandler2.getThing()).thenReturn(ThingBuilder.create(TEST_THING_TYPE_UID, "test2").build());
|
||||
|
||||
actionProviderConf2 = new TestThingActionProvider();
|
||||
actionProviderConf2.setThingHandler(mockHandler2);
|
||||
|
||||
moduleTypeI18nService = mock(ModuleTypeI18nService.class);
|
||||
when(moduleTypeI18nService.getModuleTypePerLocale(any(ModuleType.class), any(), any()))
|
||||
.thenAnswer(i -> i.getArguments()[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiServiceAnnotationActions() {
|
||||
AnnotatedThingActionModuleTypeProvider prov = new AnnotatedThingActionModuleTypeProvider(moduleTypeI18nService);
|
||||
|
||||
prov.addAnnotatedThingActions(actionProviderConf1);
|
||||
|
||||
Collection<String> types = prov.getTypes();
|
||||
assertEquals(1, types.size());
|
||||
assertTrue(types.contains(TEST_ACTION_TYPE_ID));
|
||||
|
||||
prov.addAnnotatedThingActions(actionProviderConf2);
|
||||
|
||||
// we only have ONE type but TWO configurations for it
|
||||
types = prov.getTypes();
|
||||
assertEquals(1, types.size());
|
||||
assertTrue(types.contains(TEST_ACTION_TYPE_ID));
|
||||
|
||||
ModuleType mt = prov.getModuleType(TEST_ACTION_TYPE_ID, null);
|
||||
assertTrue(mt instanceof ActionType);
|
||||
|
||||
ActionType at = (ActionType) mt;
|
||||
|
||||
assertEquals(ACTION_LABEL, at.getLabel());
|
||||
assertEquals(ACTION_DESCRIPTION, at.getDescription());
|
||||
assertEquals(Visibility.HIDDEN, at.getVisibility());
|
||||
assertEquals(TEST_ACTION_TYPE_ID, at.getUID());
|
||||
|
||||
Set<String> tags = at.getTags();
|
||||
assertTrue(tags.contains("tag1"));
|
||||
assertTrue(tags.contains("tag2"));
|
||||
|
||||
List<Input> inputs = at.getInputs();
|
||||
assertEquals(2, inputs.size());
|
||||
|
||||
for (Input in : inputs) {
|
||||
if (ACTION_INPUT1.equals(in.getName())) {
|
||||
assertEquals(ACTION_INPUT1_LABEL, in.getLabel());
|
||||
assertEquals(ACTION_INPUT1_DEFAULT_VALUE, in.getDefaultValue());
|
||||
assertEquals(ACTION_INPUT1_DESCRIPTION, in.getDescription());
|
||||
assertEquals(ACTION_INPUT1_REFERENCE, in.getReference());
|
||||
assertEquals(true, in.isRequired());
|
||||
assertEquals("Item", in.getType());
|
||||
|
||||
Set<String> inputTags = in.getTags();
|
||||
assertTrue(inputTags.contains("tagIn11"));
|
||||
assertTrue(inputTags.contains("tagIn12"));
|
||||
} else if (ACTION_INPUT2.equals(in.getName())) {
|
||||
// if the annotation does not specify a type, we use the java type
|
||||
assertEquals("java.lang.String", in.getType());
|
||||
}
|
||||
}
|
||||
|
||||
List<Output> outputs = at.getOutputs();
|
||||
assertEquals(2, outputs.size());
|
||||
|
||||
for (Output o : outputs) {
|
||||
if (ACTION_OUTPUT1.equals(o.getName())) {
|
||||
assertEquals(ACTION_OUTPUT1_LABEL, o.getLabel());
|
||||
assertEquals(ACTION_OUTPUT1_DEFAULT_VALUE, o.getDefaultValue());
|
||||
assertEquals(ACTION_OUTPUT1_DESCRIPTION, o.getDescription());
|
||||
assertEquals(ACTION_OUTPUT1_REFERENCE, o.getReference());
|
||||
assertEquals(ACTION_OUTPUT1_TYPE, o.getType());
|
||||
|
||||
Set<String> outputTags = o.getTags();
|
||||
assertTrue(outputTags.contains("tagOut11"));
|
||||
assertTrue(outputTags.contains("tagOut12"));
|
||||
} else if (ACTION_INPUT2.equals(o.getName())) {
|
||||
assertEquals(ACTION_OUTPUT2_TYPE, o.getType());
|
||||
}
|
||||
}
|
||||
|
||||
// remove the first configuration
|
||||
prov.removeAnnotatedThingActions(actionProviderConf1);
|
||||
types = prov.getTypes();
|
||||
assertEquals(1, types.size());
|
||||
|
||||
// check of the second configuration is still valid
|
||||
mt = prov.getModuleType(TEST_ACTION_TYPE_ID, null);
|
||||
List<ConfigDescriptionParameter> configParams = mt.getConfigurationDescriptions();
|
||||
boolean found = false;
|
||||
for (ConfigDescriptionParameter cdp : configParams) {
|
||||
if (AnnotationActionModuleTypeHelper.CONFIG_PARAM.equals(cdp.getName())) {
|
||||
found = true;
|
||||
List<ParameterOption> parameterOptions = cdp.getOptions();
|
||||
assertEquals(1, parameterOptions.size());
|
||||
|
||||
ParameterOption po = parameterOptions.get(0);
|
||||
assertEquals("binding:thing-type:test2", po.getValue());
|
||||
}
|
||||
}
|
||||
assertTrue(found);
|
||||
|
||||
// remove the second configuration and there should be none left
|
||||
prov.removeAnnotatedThingActions(actionProviderConf2);
|
||||
types = prov.getTypes();
|
||||
assertEquals(0, types.size());
|
||||
|
||||
mt = prov.getModuleType(TEST_ACTION_TYPE_ID, null);
|
||||
assertNull(mt);
|
||||
}
|
||||
|
||||
@ThingActionsScope(name = "test")
|
||||
private class TestThingActionProvider implements ThingActions {
|
||||
|
||||
private @Nullable ThingHandler handler;
|
||||
|
||||
@RuleAction(label = ACTION_LABEL, description = ACTION_DESCRIPTION, visibility = Visibility.HIDDEN, tags = {
|
||||
"tag1", "tag2" })
|
||||
public @ActionOutput(name = ACTION_OUTPUT1, type = ACTION_OUTPUT1_TYPE, description = ACTION_OUTPUT1_DESCRIPTION, label = ACTION_OUTPUT1_LABEL, defaultValue = ACTION_OUTPUT1_DEFAULT_VALUE, reference = ACTION_OUTPUT1_REFERENCE, tags = {
|
||||
"tagOut11",
|
||||
"tagOut12" }) @ActionOutput(name = ACTION_OUTPUT2, type = ACTION_OUTPUT2_TYPE) Map<String, Object> testMethod(
|
||||
@ActionInput(name = ACTION_INPUT1, label = ACTION_INPUT1_LABEL, defaultValue = ACTION_INPUT1_DEFAULT_VALUE, description = ACTION_INPUT1_DESCRIPTION, reference = ACTION_INPUT1_REFERENCE, required = true, type = "Item", tags = {
|
||||
"tagIn11", "tagIn12" }) String input1,
|
||||
@ActionInput(name = ACTION_INPUT2) String input2) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("output1", 23);
|
||||
result.put("output2", "hello world");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(ThingHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user