mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 13:21:53 +01:00
Enhance ThingActions UI support (#4392)
* Enhance ThingActions UI support Fixes #1745 Return config description parameters for the ActionInputs of ThingActions for the REST GET /action/{thingUID} and REST GET /module-types endpoints. The config description parameters are only provided if all input parameters have a type that can be mapped to a config description parameter (String, boolean, Boolean, byte, Byte, short, Short, int, Integer, long, Long, float, Float, double, Double, Number, DecimalType, QuantityType<?>, LocalDateTime, LocalDate, LocalTime, ZonedDateTime, Date, Instant and Duration). Enhance the REST POST /actions/{thingUID}/{actionUid} endpoint (allows invoking Thing actions via REST) and the AnnotationActionHandler (allows invoking Thing actions from UI-rules) in order to be more flexible regarding the type of each provided argument value and to map the value to the expected data type. Number and string values will be accepted as inputs and the expected data type will be created from this value. This will be used by the UI's Thing page and rule editor to allow invoking Thing actions through the UI or adding them to UI-bases rules. Signed-off-by: Laurent Garnier <lg.hc@free.fr> Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
This commit is contained in:
parent
6d0a3b330c
commit
d431013198
@ -44,8 +44,12 @@ import org.openhab.core.automation.type.ActionType;
|
||||
import org.openhab.core.automation.type.Input;
|
||||
import org.openhab.core.automation.type.ModuleTypeRegistry;
|
||||
import org.openhab.core.automation.type.Output;
|
||||
import org.openhab.core.automation.util.ActionInputsHelper;
|
||||
import org.openhab.core.automation.util.ModuleBuilder;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.config.core.dto.ConfigDescriptionDTOMapper;
|
||||
import org.openhab.core.config.core.dto.ConfigDescriptionParameterDTO;
|
||||
import org.openhab.core.io.rest.LocaleService;
|
||||
import org.openhab.core.io.rest.RESTConstants;
|
||||
import org.openhab.core.io.rest.RESTResource;
|
||||
@ -77,6 +81,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
* The {@link ThingActionsResource} allows retrieving and executing thing actions via REST API
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
* @author Laurent Garnier - API enhanced to be able to run thing actions in Main UI
|
||||
*/
|
||||
@Component
|
||||
@JaxrsResource
|
||||
@ -91,15 +96,17 @@ public class ThingActionsResource implements RESTResource {
|
||||
|
||||
private final LocaleService localeService;
|
||||
private final ModuleTypeRegistry moduleTypeRegistry;
|
||||
private final ActionInputsHelper actionInputsHelper;
|
||||
|
||||
Map<ThingUID, Map<String, ThingActions>> thingActionsMap = new ConcurrentHashMap<>();
|
||||
private List<ModuleHandlerFactory> moduleHandlerFactories = new ArrayList<>();
|
||||
|
||||
@Activate
|
||||
public ThingActionsResource(@Reference LocaleService localeService,
|
||||
@Reference ModuleTypeRegistry moduleTypeRegistry) {
|
||||
@Reference ModuleTypeRegistry moduleTypeRegistry, @Reference ActionInputsHelper actionInputsHelper) {
|
||||
this.localeService = localeService;
|
||||
this.moduleTypeRegistry = moduleTypeRegistry;
|
||||
this.actionInputsHelper = actionInputsHelper;
|
||||
}
|
||||
|
||||
@Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.MULTIPLE)
|
||||
@ -171,11 +178,27 @@ public class ThingActionsResource implements RESTResource {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter the configuration description parameters that correspond to inputs
|
||||
List<ConfigDescriptionParameter> inputParameters = new ArrayList<>();
|
||||
for (ConfigDescriptionParameter parameter : actionType.getConfigurationDescriptions()) {
|
||||
if (actionType.getInputs().stream().anyMatch(i -> i.getName().equals(parameter.getName()))) {
|
||||
inputParameters.add(parameter);
|
||||
}
|
||||
}
|
||||
// If the resulting list of configuration description parameters is empty while the list of
|
||||
// inputs is not empty, this is because the conversion of inputs into configuration description
|
||||
// parameters failed for at least one input
|
||||
if (inputParameters.isEmpty() && !actionType.getInputs().isEmpty()) {
|
||||
inputParameters = null;
|
||||
}
|
||||
|
||||
ThingActionDTO actionDTO = new ThingActionDTO();
|
||||
actionDTO.actionUid = actionType.getUID();
|
||||
actionDTO.description = actionType.getDescription();
|
||||
actionDTO.label = actionType.getLabel();
|
||||
actionDTO.inputs = actionType.getInputs();
|
||||
actionDTO.inputConfigDescriptions = inputParameters == null ? null
|
||||
: ConfigDescriptionDTOMapper.mapParameters(inputParameters);
|
||||
actionDTO.outputs = actionType.getOutputs();
|
||||
actions.add(actionDTO);
|
||||
}
|
||||
@ -221,7 +244,9 @@ public class ThingActionsResource implements RESTResource {
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> returnValue = Objects.requireNonNullElse(handler.execute(actionInputs), Map.of());
|
||||
Map<String, Object> returnValue = Objects.requireNonNullElse(
|
||||
handler.execute(actionInputsHelper.mapSerializedInputsToActionInputs(actionType, actionInputs)),
|
||||
Map.of());
|
||||
moduleHandlerFactory.ungetHandler(action, ruleUID, handler);
|
||||
return Response.ok(returnValue).build();
|
||||
} catch (Exception e) {
|
||||
@ -245,6 +270,9 @@ public class ThingActionsResource implements RESTResource {
|
||||
public @Nullable String description;
|
||||
|
||||
public List<Input> inputs = new ArrayList<>();
|
||||
|
||||
public @Nullable List<ConfigDescriptionParameterDTO> inputConfigDescriptions;
|
||||
|
||||
public List<Output> outputs = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import org.openhab.core.automation.handler.BaseActionModuleHandler;
|
||||
import org.openhab.core.automation.type.ActionType;
|
||||
import org.openhab.core.automation.type.Input;
|
||||
import org.openhab.core.automation.type.Output;
|
||||
import org.openhab.core.automation.util.ActionInputsHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -36,6 +37,7 @@ import org.slf4j.LoggerFactory;
|
||||
* ActionHandler which is dynamically created upon annotation on services
|
||||
*
|
||||
* @author Stefan Triller - Initial contribution
|
||||
* @author Laurent Garnier - Added ActionInputsHelper
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AnnotationActionHandler extends BaseActionModuleHandler {
|
||||
@ -47,13 +49,16 @@ public class AnnotationActionHandler extends BaseActionModuleHandler {
|
||||
private final Method method;
|
||||
private final ActionType moduleType;
|
||||
private final Object actionProvider;
|
||||
private final ActionInputsHelper actionInputsHelper;
|
||||
|
||||
public AnnotationActionHandler(Action module, ActionType mt, Method method, Object actionProvider) {
|
||||
public AnnotationActionHandler(Action module, ActionType mt, Method method, Object actionProvider,
|
||||
ActionInputsHelper actionInputsHelper) {
|
||||
super(module);
|
||||
|
||||
this.method = method;
|
||||
this.moduleType = mt;
|
||||
this.actionProvider = actionProvider;
|
||||
this.actionInputsHelper = actionInputsHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -69,7 +74,21 @@ public class AnnotationActionHandler extends BaseActionModuleHandler {
|
||||
if (annotationsOnParam[0] instanceof ActionInput inputAnnotation) {
|
||||
// check if the moduleType has a configdescription with this input
|
||||
if (hasInput(moduleType, inputAnnotation.name())) {
|
||||
args.add(i, context.get(inputAnnotation.name()));
|
||||
Object value = context.get(inputAnnotation.name());
|
||||
// fallback to configuration as this is where the UI stores the input values
|
||||
if (value == null) {
|
||||
Object configValue = module.getConfiguration().get(inputAnnotation.name());
|
||||
if (configValue != null) {
|
||||
try {
|
||||
value = actionInputsHelper.mapSerializedInputToActionInput(
|
||||
moduleType.getInputs().get(i), configValue);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.debug("{} Input parameter is ignored.", e.getMessage());
|
||||
// Ignore it and keep null in value
|
||||
}
|
||||
}
|
||||
}
|
||||
args.add(i, value);
|
||||
} else {
|
||||
logger.error(
|
||||
"Annotated method defines input '{}' but the module type '{}' does not specify an input with this name.",
|
||||
@ -84,8 +103,20 @@ public class AnnotationActionHandler extends BaseActionModuleHandler {
|
||||
}
|
||||
|
||||
Object result = null;
|
||||
Object @Nullable [] arguments = args.toArray();
|
||||
if (arguments.length > 0 && logger.isDebugEnabled()) {
|
||||
logger.debug("Calling action method {} with the following arguments:", method.getName());
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
if (arguments[i] == null) {
|
||||
logger.debug(" - Argument {}: null", i);
|
||||
} else {
|
||||
logger.debug(" - Argument {}: type {} value {}", i, arguments[i].getClass().getCanonicalName(),
|
||||
arguments[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
result = method.invoke(this.actionProvider, args.toArray());
|
||||
result = method.invoke(this.actionProvider, arguments);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
logger.error("Could not call method '{}' from module type '{}'.", method, moduleType.getUID(), e);
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ import org.openhab.core.automation.module.provider.i18n.ModuleTypeI18nService;
|
||||
import org.openhab.core.automation.type.ActionType;
|
||||
import org.openhab.core.automation.type.ModuleType;
|
||||
import org.openhab.core.automation.type.ModuleTypeProvider;
|
||||
import org.openhab.core.automation.util.ActionInputsHelper;
|
||||
import org.openhab.core.common.registry.ProviderChangeListener;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
@ -52,6 +53,7 @@ import org.osgi.service.component.annotations.ReferencePolicy;
|
||||
* from them
|
||||
*
|
||||
* @author Stefan Triller - Initial contribution
|
||||
* @author Laurent Garnier - Injected components AnnotationActionModuleTypeHelper and ActionInputsHelper
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = { ModuleTypeProvider.class, ModuleHandlerFactory.class })
|
||||
@ -59,13 +61,17 @@ public class AnnotatedActionModuleTypeProvider extends BaseModuleHandlerFactory
|
||||
|
||||
private final Collection<ProviderChangeListener<ModuleType>> changeListeners = ConcurrentHashMap.newKeySet();
|
||||
private final Map<String, Set<ModuleInformation>> moduleInformation = new ConcurrentHashMap<>();
|
||||
private final AnnotationActionModuleTypeHelper helper = new AnnotationActionModuleTypeHelper();
|
||||
|
||||
private final AnnotationActionModuleTypeHelper helper;
|
||||
private final ModuleTypeI18nService moduleTypeI18nService;
|
||||
private final ActionInputsHelper actionInputsHelper;
|
||||
|
||||
@Activate
|
||||
public AnnotatedActionModuleTypeProvider(final @Reference ModuleTypeI18nService moduleTypeI18nService) {
|
||||
public AnnotatedActionModuleTypeProvider(final @Reference ModuleTypeI18nService moduleTypeI18nService,
|
||||
final @Reference AnnotationActionModuleTypeHelper helper,
|
||||
final @Reference ActionInputsHelper actionInputsHelper) {
|
||||
this.moduleTypeI18nService = moduleTypeI18nService;
|
||||
this.helper = helper;
|
||||
this.actionInputsHelper = actionInputsHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -219,7 +225,7 @@ public class AnnotatedActionModuleTypeProvider extends BaseModuleHandlerFactory
|
||||
return null;
|
||||
}
|
||||
return new AnnotationActionHandler(actionModule, moduleType, finalMI.getMethod(),
|
||||
finalMI.getActionProvider());
|
||||
finalMI.getActionProvider(), actionInputsHelper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,15 @@ 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.automation.util.ActionInputsHelper;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter.Type;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameterBuilder;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.config.core.ParameterOption;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -51,8 +55,11 @@ import org.slf4j.LoggerFactory;
|
||||
* Helper methods for {@link AnnotatedActions} {@link ModuleTypeProvider}
|
||||
*
|
||||
* @author Stefan Triller - Initial contribution
|
||||
* @author Florian Hotze - Added configuration description parameters for thing modules
|
||||
* @author Laurent Garnier - Converted into a an OSGi component
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = AnnotationActionModuleTypeHelper.class)
|
||||
public class AnnotationActionModuleTypeHelper {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AnnotationActionModuleTypeHelper.class);
|
||||
@ -61,6 +68,13 @@ public class AnnotationActionModuleTypeHelper {
|
||||
private static final String SELECT_THING_LABEL = "Select Thing";
|
||||
public static final String CONFIG_PARAM = "config";
|
||||
|
||||
private final ActionInputsHelper actionInputsHelper;
|
||||
|
||||
@Activate
|
||||
public AnnotationActionModuleTypeHelper(final @Reference ActionInputsHelper actionInputsHelper) {
|
||||
this.actionInputsHelper = actionInputsHelper;
|
||||
}
|
||||
|
||||
public Collection<ModuleInformation> parseAnnotations(Object actionProvider) {
|
||||
Class<?> clazz = actionProvider.getClass();
|
||||
if (clazz.isAnnotationPresent(ActionScope.class)) {
|
||||
@ -77,7 +91,7 @@ public class AnnotationActionModuleTypeHelper {
|
||||
for (Method method : methods) {
|
||||
if (method.isAnnotationPresent(RuleAction.class)) {
|
||||
List<Input> inputs = getInputsFromAction(method);
|
||||
List<Output> outputs = getOutputsFromMethod(method);
|
||||
List<Output> outputs = getOutputsFromAction(method);
|
||||
|
||||
RuleAction ruleAction = method.getAnnotation(RuleAction.class);
|
||||
String uid = name + "." + method.getName();
|
||||
@ -86,10 +100,7 @@ public class AnnotationActionModuleTypeHelper {
|
||||
ModuleInformation mi = new ModuleInformation(uid, actionProvider, method);
|
||||
mi.setLabel(ruleAction.label());
|
||||
mi.setDescription(ruleAction.description());
|
||||
// We temporarily want to hide all ThingActions in UIs as we do not have a proper solution to enter
|
||||
// their input values (see https://github.com/openhab/openhab-core/issues/1745)
|
||||
// mi.setVisibility(ruleAction.visibility());
|
||||
mi.setVisibility(Visibility.HIDDEN);
|
||||
mi.setVisibility(ruleAction.visibility());
|
||||
mi.setInputs(inputs);
|
||||
mi.setOutputs(outputs);
|
||||
mi.setTags(tags);
|
||||
@ -132,7 +143,7 @@ public class AnnotationActionModuleTypeHelper {
|
||||
return inputs;
|
||||
}
|
||||
|
||||
private List<Output> getOutputsFromMethod(Method method) {
|
||||
private List<Output> getOutputsFromAction(Method method) {
|
||||
List<Output> outputs = new ArrayList<>();
|
||||
if (method.isAnnotationPresent(ActionOutputs.class)) {
|
||||
for (ActionOutput ruleActionOutput : method.getAnnotationsByType(ActionOutput.class)) {
|
||||
@ -170,8 +181,25 @@ public class AnnotationActionModuleTypeHelper {
|
||||
if (configParam != null) {
|
||||
configDescriptions.add(configParam);
|
||||
}
|
||||
return new ActionType(uid, configDescriptions, mi.getLabel(), mi.getDescription(), mi.getTags(),
|
||||
mi.getVisibility(), mi.getInputs(), mi.getOutputs());
|
||||
|
||||
Visibility visibility = mi.getVisibility();
|
||||
|
||||
if (kind == ActionModuleKind.THING) {
|
||||
// we have a Thing module, so we have to map the inputs to config description parameters for the UI
|
||||
try {
|
||||
List<ConfigDescriptionParameter> inputConfigDescriptions = actionInputsHelper
|
||||
.mapActionInputsToConfigDescriptionParameters(mi.getInputs());
|
||||
configDescriptions.addAll(inputConfigDescriptions);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// we have an input without a supported type, so hide the Thing action
|
||||
visibility = Visibility.HIDDEN;
|
||||
logger.debug("{} Thing action {} has an input with an unsupported type, hiding it in the UI.",
|
||||
e.getMessage(), uid);
|
||||
}
|
||||
}
|
||||
|
||||
return new ActionType(uid, configDescriptions, mi.getLabel(), mi.getDescription(), mi.getTags(), visibility,
|
||||
mi.getInputs(), mi.getOutputs());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import org.openhab.core.automation.module.provider.i18n.ModuleTypeI18nService;
|
||||
import org.openhab.core.automation.type.ActionType;
|
||||
import org.openhab.core.automation.type.ModuleType;
|
||||
import org.openhab.core.automation.type.ModuleTypeProvider;
|
||||
import org.openhab.core.automation.util.ActionInputsHelper;
|
||||
import org.openhab.core.common.registry.ProviderChangeListener;
|
||||
import org.openhab.core.thing.binding.ThingActions;
|
||||
import org.openhab.core.thing.binding.ThingActionsScope;
|
||||
@ -54,6 +55,7 @@ import org.slf4j.LoggerFactory;
|
||||
* ModuleTypeProvider that collects actions for {@link ThingHandler}s
|
||||
*
|
||||
* @author Stefan Triller - Initial contribution
|
||||
* @author Laurent Garnier - Injected components AnnotationActionModuleTypeHelper and ActionInputsHelper
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = { ModuleTypeProvider.class, ModuleHandlerFactory.class })
|
||||
@ -63,13 +65,17 @@ public class AnnotatedThingActionModuleTypeProvider extends BaseModuleHandlerFac
|
||||
|
||||
private final Collection<ProviderChangeListener<ModuleType>> changeListeners = ConcurrentHashMap.newKeySet();
|
||||
private final Map<String, Set<ModuleInformation>> moduleInformation = new ConcurrentHashMap<>();
|
||||
private final AnnotationActionModuleTypeHelper helper = new AnnotationActionModuleTypeHelper();
|
||||
|
||||
private final AnnotationActionModuleTypeHelper helper;
|
||||
private final ModuleTypeI18nService moduleTypeI18nService;
|
||||
private final ActionInputsHelper actionInputsHelper;
|
||||
|
||||
@Activate
|
||||
public AnnotatedThingActionModuleTypeProvider(final @Reference ModuleTypeI18nService moduleTypeI18nService) {
|
||||
public AnnotatedThingActionModuleTypeProvider(final @Reference ModuleTypeI18nService moduleTypeI18nService,
|
||||
final @Reference AnnotationActionModuleTypeHelper helper,
|
||||
final @Reference ActionInputsHelper actionInputsHelper) {
|
||||
this.moduleTypeI18nService = moduleTypeI18nService;
|
||||
this.helper = helper;
|
||||
this.actionInputsHelper = actionInputsHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -236,7 +242,7 @@ public class AnnotatedThingActionModuleTypeProvider extends BaseModuleHandlerFac
|
||||
return null;
|
||||
}
|
||||
return new AnnotationActionHandler(actionModule, moduleType, finalMI.getMethod(),
|
||||
finalMI.getActionProvider());
|
||||
finalMI.getActionProvider(), actionInputsHelper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,293 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.util;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.measure.Quantity;
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.automation.type.ActionType;
|
||||
import org.openhab.core.automation.type.Input;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameterBuilder;
|
||||
import org.openhab.core.i18n.UnitProvider;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.types.util.UnitUtils;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This is an utility class to convert the {@link Input}s of a {@link ActionType} into a list of
|
||||
* {@link ConfigDescriptionParameter}s and to convert serialised inputs to the Java types required by the
|
||||
* {@link Input}s of a {@link ActionType}.
|
||||
*
|
||||
* @author Laurent Garnier & Florian Hotze - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ActionInputsHelper.class)
|
||||
public class ActionInputsHelper {
|
||||
private static final Pattern QUANTITY_TYPE_PATTERN = Pattern
|
||||
.compile("([a-z0-9]+\\.)*QuantityType<([a-z0-9]+\\.)*(?<dimension>[A-Z][a-zA-Z0-9]*)>");
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ActionInputsHelper.class);
|
||||
|
||||
private final UnitProvider unitProvider;
|
||||
|
||||
@Activate
|
||||
public ActionInputsHelper(final @Reference UnitProvider unitProvider) {
|
||||
this.unitProvider = unitProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a list of {@link Input}s to a list of {@link ConfigDescriptionParameter}s.
|
||||
*
|
||||
* @param inputs the list of inputs to map to config description parameters
|
||||
* @return the list of config description parameters
|
||||
* @throws IllegalArgumentException if at least one of the input parameters has an unsupported type
|
||||
*/
|
||||
public List<ConfigDescriptionParameter> mapActionInputsToConfigDescriptionParameters(List<Input> inputs)
|
||||
throws IllegalArgumentException {
|
||||
List<ConfigDescriptionParameter> configDescriptionParameters = new ArrayList<>();
|
||||
|
||||
for (Input input : inputs) {
|
||||
configDescriptionParameters.add(mapActionInputToConfigDescriptionParameter(input));
|
||||
}
|
||||
|
||||
return configDescriptionParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps an {@link Input} to a {@link ConfigDescriptionParameter}.
|
||||
*
|
||||
* @param input the input to map to a config description parameter
|
||||
* @return the config description parameter
|
||||
* @throws IllegalArgumentException if the input parameter has an unsupported type
|
||||
*/
|
||||
public ConfigDescriptionParameter mapActionInputToConfigDescriptionParameter(Input input)
|
||||
throws IllegalArgumentException {
|
||||
ConfigDescriptionParameter.Type parameterType = ConfigDescriptionParameter.Type.TEXT;
|
||||
String defaultValue = null;
|
||||
Unit<?> unit = null;
|
||||
boolean required = false;
|
||||
String context = null;
|
||||
Matcher matcher = QUANTITY_TYPE_PATTERN.matcher(input.getType());
|
||||
if (matcher.matches()) {
|
||||
parameterType = ConfigDescriptionParameter.Type.DECIMAL;
|
||||
try {
|
||||
unit = getDefaultUnit(matcher.group("dimension"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException("Input parameter '" + input.getName() + "' with type "
|
||||
+ input.getType() + "cannot be converted into a config description parameter!", e);
|
||||
}
|
||||
} else {
|
||||
switch (input.getType()) {
|
||||
case "boolean":
|
||||
defaultValue = "false";
|
||||
required = true;
|
||||
case "java.lang.Boolean":
|
||||
parameterType = ConfigDescriptionParameter.Type.BOOLEAN;
|
||||
break;
|
||||
case "byte":
|
||||
case "short":
|
||||
case "int":
|
||||
case "long":
|
||||
defaultValue = "0";
|
||||
required = true;
|
||||
case "java.lang.Byte":
|
||||
case "java.lang.Short":
|
||||
case "java.lang.Integer":
|
||||
case "java.lang.Long":
|
||||
parameterType = ConfigDescriptionParameter.Type.INTEGER;
|
||||
break;
|
||||
case "float":
|
||||
case "double":
|
||||
defaultValue = "0";
|
||||
required = true;
|
||||
case "java.lang.Float":
|
||||
case "java.lang.Double":
|
||||
case "java.lang.Number":
|
||||
case "org.openhab.core.library.types.DecimalType":
|
||||
parameterType = ConfigDescriptionParameter.Type.DECIMAL;
|
||||
break;
|
||||
case "java.lang.String":
|
||||
break;
|
||||
case "java.time.LocalDate":
|
||||
context = "date";
|
||||
break;
|
||||
case "java.time.LocalTime":
|
||||
context = "time";
|
||||
break;
|
||||
case "java.time.LocalDateTime":
|
||||
case "java.util.Date":
|
||||
context = "datetime";
|
||||
break;
|
||||
case "java.time.ZonedDateTime":
|
||||
case "java.time.Instant":
|
||||
case "java.time.Duration":
|
||||
// There is no available configuration parameter context for these types.
|
||||
// A text parameter is used. The expected value must respect a particular format specific
|
||||
// to each of these types.
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Input parameter '" + input.getName() + "' with type "
|
||||
+ input.getType() + "cannot be converted into a config description parameter!");
|
||||
}
|
||||
}
|
||||
|
||||
ConfigDescriptionParameterBuilder builder = ConfigDescriptionParameterBuilder
|
||||
.create(input.getName(), parameterType).withLabel(input.getLabel())
|
||||
.withDescription(input.getDescription()).withReadOnly(false)
|
||||
.withRequired(required || input.isRequired()).withContext(context);
|
||||
if (input.getDefaultValue() != null && !input.getDefaultValue().isEmpty()) {
|
||||
builder = builder.withDefault(input.getDefaultValue());
|
||||
} else if (defaultValue != null) {
|
||||
builder = builder.withDefault(defaultValue);
|
||||
}
|
||||
if (unit != null) {
|
||||
builder = builder.withUnit(unit.getSymbol());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps serialised inputs to the Java types required by the {@link Input}s of the given {@link ActionType}.
|
||||
*
|
||||
* @param actionType the action type whose inputs to consider
|
||||
* @param arguments the serialised arguments
|
||||
* @return the mapped arguments
|
||||
*/
|
||||
public Map<String, Object> mapSerializedInputsToActionInputs(ActionType actionType, Map<String, Object> arguments) {
|
||||
Map<String, Object> newArguments = new HashMap<>();
|
||||
for (Input input : actionType.getInputs()) {
|
||||
Object value = arguments.get(input.getName());
|
||||
if (value != null) {
|
||||
try {
|
||||
newArguments.put(input.getName(), mapSerializedInputToActionInput(input, value));
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.warn("{} Input parameter is ignored.", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
return newArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a serialised input to the Java type required by the given {@link Input}.
|
||||
*
|
||||
* @param input the input whose type to consider
|
||||
* @param argument the serialised argument
|
||||
* @return the mapped argument
|
||||
* @throws IllegalArgumentException if the mapping failed
|
||||
*/
|
||||
public Object mapSerializedInputToActionInput(Input input, Object argument) throws IllegalArgumentException {
|
||||
try {
|
||||
Matcher matcher = QUANTITY_TYPE_PATTERN.matcher(input.getType());
|
||||
if (argument instanceof Double valueDouble) {
|
||||
// When an integer value is provided as input value, the value type in the Map is Double.
|
||||
// We have to convert Double type into the target type.
|
||||
if (matcher.matches()) {
|
||||
return new QuantityType<>(valueDouble, getDefaultUnit(matcher.group("dimension")));
|
||||
} else {
|
||||
return switch (input.getType()) {
|
||||
case "byte", "java.lang.Byte" -> Byte.valueOf(valueDouble.byteValue());
|
||||
case "short", "java.lang.Short" -> Short.valueOf(valueDouble.shortValue());
|
||||
case "int", "java.lang.Integer" -> Integer.valueOf(valueDouble.intValue());
|
||||
case "long", "java.lang.Long" -> Long.valueOf(valueDouble.longValue());
|
||||
case "float", "java.lang.Float" -> Float.valueOf(valueDouble.floatValue());
|
||||
case "org.openhab.core.library.types.DecimalType" -> new DecimalType(valueDouble);
|
||||
default -> argument;
|
||||
};
|
||||
}
|
||||
} else if (argument instanceof String valueString) {
|
||||
// String value is accepted to instantiate few target types
|
||||
if (matcher.matches()) {
|
||||
// The string can contain either a simple decimal value without unit or a decimal value with
|
||||
// unit
|
||||
try {
|
||||
BigDecimal bigDecimal = new BigDecimal(valueString);
|
||||
return new QuantityType<>(bigDecimal, getDefaultUnit(matcher.group("dimension")));
|
||||
} catch (NumberFormatException e) {
|
||||
return new QuantityType<>(valueString);
|
||||
}
|
||||
} else {
|
||||
return switch (input.getType()) {
|
||||
case "boolean", "java.lang.Boolean" -> Boolean.valueOf(valueString.toLowerCase());
|
||||
case "byte", "java.lang.Byte" -> Byte.valueOf(valueString);
|
||||
case "short", "java.lang.Short" -> Short.valueOf(valueString);
|
||||
case "int", "java.lang.Integer" -> Integer.valueOf(valueString);
|
||||
case "long", "java.lang.Long" -> Long.valueOf(valueString);
|
||||
case "float", "java.lang.Float" -> Float.valueOf(valueString);
|
||||
case "double", "java.lang.Double", "java.lang.Number" -> Double.valueOf(valueString);
|
||||
case "org.openhab.core.library.types.DecimalType" -> new DecimalType(valueString);
|
||||
case "java.time.LocalDate" ->
|
||||
// Accepted format is: 2007-12-03
|
||||
LocalDate.parse(valueString);
|
||||
case "java.time.LocalTime" ->
|
||||
// Accepted format is: 10:15:30
|
||||
LocalTime.parse(valueString);
|
||||
case "java.time.LocalDateTime" ->
|
||||
// Accepted format is: 2007-12-03 10:15:30
|
||||
LocalDateTime.parse(valueString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
case "java.util.Date" ->
|
||||
// Accepted format is: 2007-12-03 10:15:30
|
||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(valueString);
|
||||
case "java.time.ZonedDateTime" ->
|
||||
// Accepted format is: 2007-12-03T10:15:30+01:00[Europe/Paris]
|
||||
ZonedDateTime.parse(valueString);
|
||||
case "java.time.Instant" ->
|
||||
// Accepted format is: 2007-12-03T10:15:30.00Z
|
||||
Instant.parse(valueString);
|
||||
case "java.time.Duration" ->
|
||||
// Accepted format is: P2DT17H25M30.5S
|
||||
Duration.parse(valueString);
|
||||
default -> argument;
|
||||
};
|
||||
}
|
||||
}
|
||||
return argument;
|
||||
} catch (IllegalArgumentException | DateTimeParseException | ParseException e) {
|
||||
throw new IllegalArgumentException("Input parameter '" + input.getName() + "': converting value '"
|
||||
+ argument.toString() + "' into type " + input.getType() + " failed!");
|
||||
}
|
||||
}
|
||||
|
||||
private Unit<?> getDefaultUnit(String dimensionName) throws IllegalArgumentException {
|
||||
Class<? extends Quantity<?>> dimension = UnitUtils.parseDimension(dimensionName);
|
||||
if (dimension == null) {
|
||||
throw new IllegalArgumentException("Unknown dimension " + dimensionName);
|
||||
}
|
||||
return unitProvider.getUnit((Class<? extends Quantity>) dimension);
|
||||
}
|
||||
}
|
@ -41,6 +41,7 @@ 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.automation.util.ActionInputsHelper;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.config.core.ParameterOption;
|
||||
import org.openhab.core.test.java.JavaTest;
|
||||
@ -74,6 +75,7 @@ public class AnnotationActionModuleTypeProviderTest extends JavaTest {
|
||||
private static final String ACTION_OUTPUT2_TYPE = "java.lang.String";
|
||||
|
||||
private @Mock @NonNullByDefault({}) ModuleTypeI18nService moduleTypeI18nServiceMock;
|
||||
private @Mock @NonNullByDefault({}) ActionInputsHelper actionInputsHelperMock;
|
||||
|
||||
private AnnotatedActions actionProviderConf1 = new TestActionProvider();
|
||||
private AnnotatedActions actionProviderConf2 = new TestActionProvider();
|
||||
@ -86,7 +88,8 @@ public class AnnotationActionModuleTypeProviderTest extends JavaTest {
|
||||
|
||||
@Test
|
||||
public void testMultiServiceAnnotationActions() {
|
||||
AnnotatedActionModuleTypeProvider prov = new AnnotatedActionModuleTypeProvider(moduleTypeI18nServiceMock);
|
||||
AnnotatedActionModuleTypeProvider prov = new AnnotatedActionModuleTypeProvider(moduleTypeI18nServiceMock,
|
||||
new AnnotationActionModuleTypeHelper(actionInputsHelperMock), actionInputsHelperMock);
|
||||
|
||||
Map<String, Object> properties1 = Map.of(OpenHAB.SERVICE_CONTEXT, "conf1");
|
||||
prov.addActionProvider(actionProviderConf1, properties1);
|
||||
|
@ -39,6 +39,7 @@ 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.automation.util.ActionInputsHelper;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.config.core.ParameterOption;
|
||||
import org.openhab.core.test.java.JavaTest;
|
||||
@ -79,6 +80,7 @@ public class AnnotatedThingActionModuleTypeProviderTest extends JavaTest {
|
||||
private static final String ACTION_OUTPUT2_TYPE = "java.lang.String";
|
||||
|
||||
private @Mock @NonNullByDefault({}) ModuleTypeI18nService moduleTypeI18nServiceMock;
|
||||
private @Mock @NonNullByDefault({}) ActionInputsHelper actionInputsHelperMock;
|
||||
private @Mock @NonNullByDefault({}) ThingHandler handler1Mock;
|
||||
private @Mock @NonNullByDefault({}) ThingHandler handler2Mock;
|
||||
|
||||
@ -104,7 +106,8 @@ public class AnnotatedThingActionModuleTypeProviderTest extends JavaTest {
|
||||
@Test
|
||||
public void testMultiServiceAnnotationActions() {
|
||||
AnnotatedThingActionModuleTypeProvider prov = new AnnotatedThingActionModuleTypeProvider(
|
||||
moduleTypeI18nServiceMock);
|
||||
moduleTypeI18nServiceMock, new AnnotationActionModuleTypeHelper(actionInputsHelperMock),
|
||||
actionInputsHelperMock);
|
||||
|
||||
prov.addAnnotatedThingActions(actionProviderConf1);
|
||||
|
||||
|
@ -0,0 +1,556 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.util;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.measure.Quantity;
|
||||
import javax.measure.Unit;
|
||||
import javax.measure.quantity.Temperature;
|
||||
import javax.measure.spi.SystemOfUnits;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.automation.type.ActionType;
|
||||
import org.openhab.core.automation.type.Input;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.i18n.UnitProvider;
|
||||
import org.openhab.core.internal.i18n.I18nProviderImpl;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
|
||||
/**
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ActionInputHelperTest {
|
||||
private static final String PARAM_NAME = "Param";
|
||||
private static final String PARAM_LABEL = "Label Parameter";
|
||||
private static final String PARAM_DESCRIPTION = "Description parameter";
|
||||
|
||||
private UnitProvider unitProvider = new TestUnitProvider();
|
||||
private ActionInputsHelper helper = new ActionInputsHelper(unitProvider);
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenBoolean() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.lang.Boolean")),
|
||||
ConfigDescriptionParameter.Type.BOOLEAN, false, null, null, null);
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("boolean")),
|
||||
ConfigDescriptionParameter.Type.BOOLEAN, true, "false", null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenByte() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.lang.Byte")),
|
||||
ConfigDescriptionParameter.Type.INTEGER, false, null, null, null);
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("byte")),
|
||||
ConfigDescriptionParameter.Type.INTEGER, true, "0", null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenShort() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.lang.Short")),
|
||||
ConfigDescriptionParameter.Type.INTEGER, false, null, null, null);
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("short")),
|
||||
ConfigDescriptionParameter.Type.INTEGER, true, "0", null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenInteger() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.lang.Integer")),
|
||||
ConfigDescriptionParameter.Type.INTEGER, false, null, null, null);
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("int")),
|
||||
ConfigDescriptionParameter.Type.INTEGER, true, "0", null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenLong() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.lang.Long")),
|
||||
ConfigDescriptionParameter.Type.INTEGER, false, null, null, null);
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("long")),
|
||||
ConfigDescriptionParameter.Type.INTEGER, true, "0", null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenFloat() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.lang.Float")),
|
||||
ConfigDescriptionParameter.Type.DECIMAL, false, null, null, null);
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("float")),
|
||||
ConfigDescriptionParameter.Type.DECIMAL, true, "0", null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenDouble() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.lang.Double")),
|
||||
ConfigDescriptionParameter.Type.DECIMAL, false, null, null, null);
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("double")),
|
||||
ConfigDescriptionParameter.Type.DECIMAL, true, "0", null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenNumber() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.lang.Number")),
|
||||
ConfigDescriptionParameter.Type.DECIMAL, false, null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenDecimalType() {
|
||||
checkParameter(
|
||||
helper.mapActionInputToConfigDescriptionParameter(
|
||||
buildInput("org.openhab.core.library.types.DecimalType")),
|
||||
ConfigDescriptionParameter.Type.DECIMAL, false, null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenQuantityType() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("QuantityType<Temperature>")),
|
||||
ConfigDescriptionParameter.Type.DECIMAL, false, null, null, "°C");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenString() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.lang.String")),
|
||||
ConfigDescriptionParameter.Type.TEXT, false, null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenLocalDate() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.time.LocalDate")),
|
||||
ConfigDescriptionParameter.Type.TEXT, false, null, "date", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenLocalTime() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.time.LocalTime")),
|
||||
ConfigDescriptionParameter.Type.TEXT, false, null, "time", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenLocalDateTime() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.time.LocalDateTime")),
|
||||
ConfigDescriptionParameter.Type.TEXT, false, null, "datetime", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenDate() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.util.Date")),
|
||||
ConfigDescriptionParameter.Type.TEXT, false, null, "datetime", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenZonedDateTime() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.time.ZonedDateTime")),
|
||||
ConfigDescriptionParameter.Type.TEXT, false, null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenInstant() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.time.Instant")),
|
||||
ConfigDescriptionParameter.Type.TEXT, false, null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenDuration() {
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(buildInput("java.time.Duration")),
|
||||
ConfigDescriptionParameter.Type.TEXT, false, null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenDefaultValue() {
|
||||
Input input = new Input(PARAM_NAME, "int", PARAM_LABEL, PARAM_DESCRIPTION, null, false, null, "-1");
|
||||
checkParameter(helper.mapActionInputToConfigDescriptionParameter(input),
|
||||
ConfigDescriptionParameter.Type.INTEGER, true, "-1", null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputToConfigDescriptionParameterWhenUnsupportedType() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> helper.mapActionInputToConfigDescriptionParameter(buildInput("List<String>")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputsToConfigDescriptionParametersWhenOk() {
|
||||
Input input1 = buildInput("Boolean", "boolean");
|
||||
Input input2 = buildInput("String", "java.lang.String");
|
||||
List<ConfigDescriptionParameter> params = helper
|
||||
.mapActionInputsToConfigDescriptionParameters(List.of(input1, input2));
|
||||
assertThat(params.size(), is(2));
|
||||
checkParameter(params.get(0), "Boolean", ConfigDescriptionParameter.Type.BOOLEAN, PARAM_LABEL,
|
||||
PARAM_DESCRIPTION, true, "false", null, null);
|
||||
checkParameter(params.get(1), "String", ConfigDescriptionParameter.Type.TEXT, PARAM_LABEL, PARAM_DESCRIPTION,
|
||||
false, null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapActionInputsToConfigDescriptionParametersWhenUnsupportedType() {
|
||||
Input input1 = buildInput("Boolean", "boolean");
|
||||
Input input2 = buildInput("List", "List<String>");
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> helper.mapActionInputsToConfigDescriptionParameters(List.of(input1, input2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenBoolean() {
|
||||
Input input = buildInput("java.lang.Boolean");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, true), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, false), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, Boolean.TRUE), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, Boolean.FALSE), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "true"), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "True"), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "TRUE"), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "false"), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "False"), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "FALSE"), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "other"), is(Boolean.FALSE));
|
||||
|
||||
Input input2 = buildInput("boolean");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, true), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, false), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, Boolean.TRUE), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, Boolean.FALSE), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "true"), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "True"), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "TRUE"), is(Boolean.TRUE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "false"), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "False"), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "FALSE"), is(Boolean.FALSE));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "other"), is(Boolean.FALSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenByte() {
|
||||
byte val = 127;
|
||||
Byte valAsByte = Byte.valueOf(val);
|
||||
|
||||
Input input = buildInput("java.lang.Byte");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(valAsByte));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsByte), is(valAsByte));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, Double.valueOf(val)), is(valAsByte));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "127"), is(valAsByte));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input, "128"));
|
||||
|
||||
Input input2 = buildInput("byte");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, val), is(valAsByte));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, valAsByte), is(valAsByte));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, Double.valueOf(val)), is(valAsByte));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "127"), is(valAsByte));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input2, "128"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenShort() {
|
||||
short val = 32767;
|
||||
Short valAsShort = Short.valueOf(val);
|
||||
|
||||
Input input = buildInput("java.lang.Short");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(valAsShort));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsShort), is(valAsShort));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, Double.valueOf(val)), is(valAsShort));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "32767"), is(valAsShort));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input, "32768"));
|
||||
|
||||
Input input2 = buildInput("short");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, val), is(valAsShort));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, valAsShort), is(valAsShort));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, Double.valueOf(val)), is(valAsShort));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "32767"), is(valAsShort));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input2, "32768"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenInteger() {
|
||||
int val = 123456789;
|
||||
Integer valAsInteger = Integer.valueOf(val);
|
||||
|
||||
Input input = buildInput("java.lang.Integer");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(valAsInteger));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsInteger), is(valAsInteger));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, Double.valueOf(val)), is(valAsInteger));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "123456789"), is(valAsInteger));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input, "wrong"));
|
||||
|
||||
Input input2 = buildInput("int");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, val), is(valAsInteger));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, valAsInteger), is(valAsInteger));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, Double.valueOf(val)), is(valAsInteger));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "123456789"), is(valAsInteger));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input2, "wrong"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenLong() {
|
||||
long val = 123456789;
|
||||
Long valAsLong = Long.valueOf(val);
|
||||
|
||||
Input input = buildInput("java.lang.Long");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(valAsLong));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsLong), is(valAsLong));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, Double.valueOf(val)), is(valAsLong));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "123456789"), is(valAsLong));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input, "wrong"));
|
||||
|
||||
Input input2 = buildInput("long");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, val), is(valAsLong));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, valAsLong), is(valAsLong));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, Double.valueOf(val)), is(valAsLong));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "123456789"), is(valAsLong));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input2, "wrong"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenFloat() {
|
||||
Float val = 456.789f;
|
||||
Float valAsFloat = Float.valueOf(val);
|
||||
|
||||
Input input = buildInput("java.lang.Float");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(valAsFloat));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsFloat), is(valAsFloat));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, Double.valueOf(val)), is(valAsFloat));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "456.789"), is(valAsFloat));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input, "wrong"));
|
||||
|
||||
Input input2 = buildInput("float");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, val), is(valAsFloat));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, valAsFloat), is(valAsFloat));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, Double.valueOf(val)), is(valAsFloat));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "456.789"), is(valAsFloat));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input2, "wrong"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenDouble() {
|
||||
Double val = 456.789d;
|
||||
Double valAsDouble = Double.valueOf(val);
|
||||
|
||||
Input input = buildInput("java.lang.Double");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(valAsDouble));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsDouble), is(valAsDouble));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "456.789"), is(valAsDouble));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input, "wrong"));
|
||||
|
||||
Input input2 = buildInput("double");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, val), is(valAsDouble));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, valAsDouble), is(valAsDouble));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input2, "456.789"), is(valAsDouble));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input2, "wrong"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenDecimalType() {
|
||||
DecimalType val = new DecimalType(23.45);
|
||||
Input input = buildInput("org.openhab.core.library.types.DecimalType");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val.doubleValue()), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "23.45"), is(val));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input, "wrong"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenQuantityType() {
|
||||
QuantityType<Temperature> val = new QuantityType<>(19.7, SIUnits.CELSIUS);
|
||||
Input input = buildInput("QuantityType<Temperature>");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, 19.7d), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "19.7"), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, "19.7 °C"), is(val));
|
||||
assertThrows(IllegalArgumentException.class, () -> helper.mapSerializedInputToActionInput(input, "19.7 XXX"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenLocalDate() {
|
||||
String valAsString = "2024-08-31";
|
||||
LocalDate val = LocalDate.parse(valAsString);
|
||||
Input input = buildInput("java.time.LocalDate");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsString), is(val));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> helper.mapSerializedInputToActionInput(input, valAsString.replaceAll("-", " ")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenLocalTime() {
|
||||
String valAsString = "08:30:55";
|
||||
LocalTime val = LocalTime.parse(valAsString);
|
||||
Input input = buildInput("java.time.LocalTime");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsString), is(val));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> helper.mapSerializedInputToActionInput(input, valAsString.replaceAll(":", " ")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenLocalDateTime() {
|
||||
String valAsString = "2024-07-01 20:30:45";
|
||||
LocalDateTime val = LocalDateTime.parse(valAsString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
Input input = buildInput("java.time.LocalDateTime");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsString), is(val));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> helper.mapSerializedInputToActionInput(input, valAsString.replaceAll(" ", "T")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenZonedDateTime() {
|
||||
String valAsString = "2007-12-03T10:15:30+01:00[Europe/Paris]";
|
||||
ZonedDateTime val = ZonedDateTime.parse(valAsString);
|
||||
Input input = buildInput("java.time.ZonedDateTime");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsString), is(val));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> helper.mapSerializedInputToActionInput(input, valAsString.replaceAll("T", " ")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenDate() {
|
||||
String valAsString = "2024-11-05 09:45:12";
|
||||
Date val;
|
||||
try {
|
||||
val = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(valAsString);
|
||||
} catch (IllegalArgumentException | ParseException e) {
|
||||
val = null;
|
||||
}
|
||||
assertNotNull(val);
|
||||
Input input = buildInput("java.util.Date");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsString), is(val));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> helper.mapSerializedInputToActionInput(input, valAsString.replaceAll(" ", "T")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenInstant() {
|
||||
String valAsString = "2017-12-09T20:15:30.00Z";
|
||||
Instant val = Instant.parse(valAsString);
|
||||
Input input = buildInput("java.time.Instant");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsString), is(val));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> helper.mapSerializedInputToActionInput(input, valAsString.replaceAll("T", " ")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenDuration() {
|
||||
String valAsString = "P2DT17H25M30.5S";
|
||||
Duration val = Duration.parse(valAsString);
|
||||
Input input = buildInput("java.time.Duration");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, valAsString), is(val));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> helper.mapSerializedInputToActionInput(input, valAsString.replaceAll("T", " ")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputToActionInputWhenAnyOtherType() {
|
||||
List<String> val = List.of("Value 1", "Value 2");
|
||||
Input input = buildInput("List<String>");
|
||||
assertThat(helper.mapSerializedInputToActionInput(input, val), is(val));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapSerializedInputsToActionInputs() {
|
||||
Input input1 = buildInput("BooleanParam", "java.lang.Boolean");
|
||||
Input input2 = buildInput("DoubleParam", "java.lang.Double");
|
||||
Input input3 = buildInput("StringParam", "java.lang.String");
|
||||
ActionType action = new ActionType("action", null, List.of(input1, input2, input3));
|
||||
|
||||
Map<String, Object> result = helper.mapSerializedInputsToActionInputs(action,
|
||||
Map.of("BooleanParam", true, "OtherParam", "other", "DoubleParam", "invalid", "StringParam", "test"));
|
||||
assertThat(result.size(), is(2));
|
||||
assertThat(result.get("BooleanParam"), is(Boolean.TRUE));
|
||||
assertNull(result.get("DoubleParam"));
|
||||
assertThat(result.get("StringParam"), is("test"));
|
||||
}
|
||||
|
||||
private Input buildInput(String type) {
|
||||
return buildInput(PARAM_NAME, type);
|
||||
}
|
||||
|
||||
private Input buildInput(String name, String type) {
|
||||
return new Input(name, type, PARAM_LABEL, PARAM_DESCRIPTION, null, false, null, null);
|
||||
}
|
||||
|
||||
private void checkParameter(ConfigDescriptionParameter param, ConfigDescriptionParameter.Type type,
|
||||
boolean required, @Nullable String defaultValue, @Nullable String context, @Nullable String unit) {
|
||||
checkParameter(param, PARAM_NAME, type, PARAM_LABEL, PARAM_DESCRIPTION, required, defaultValue, context, unit);
|
||||
}
|
||||
|
||||
private void checkParameter(ConfigDescriptionParameter param, String name, ConfigDescriptionParameter.Type type,
|
||||
String label, String description, boolean required, @Nullable String defaultValue, @Nullable String context,
|
||||
@Nullable String unit) {
|
||||
assertThat(param.getName(), is(name));
|
||||
assertThat(param.getLabel(), is(label));
|
||||
assertThat(param.getDescription(), is(description));
|
||||
assertThat(param.getType(), is(type));
|
||||
assertThat(param.isReadOnly(), is(false));
|
||||
assertThat(param.isRequired(), is(required));
|
||||
if (defaultValue == null) {
|
||||
assertNull(param.getDefault());
|
||||
} else {
|
||||
assertThat(param.getDefault(), is(defaultValue));
|
||||
}
|
||||
if (context == null) {
|
||||
assertNull(param.getContext());
|
||||
} else {
|
||||
assertThat(param.getContext(), is(context));
|
||||
}
|
||||
if (unit == null) {
|
||||
assertNull(param.getUnit());
|
||||
} else {
|
||||
assertNotNull(param.getUnit());
|
||||
}
|
||||
}
|
||||
|
||||
public class TestUnitProvider implements UnitProvider {
|
||||
|
||||
private final Map<Class<? extends Quantity<?>>, Map<SystemOfUnits, Unit<? extends Quantity<?>>>> dimensionMap = I18nProviderImpl
|
||||
.getDimensionMap();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Quantity<T>> Unit<T> getUnit(Class<T> dimension) {
|
||||
return Objects.requireNonNull(
|
||||
(Unit<T>) dimensionMap.getOrDefault(dimension, Map.of()).get(SIUnits.getInstance()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemOfUnits getMeasurementSystem() {
|
||||
return SIUnits.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends Quantity<?>>> getAllDimensions() {
|
||||
return Set.of();
|
||||
}
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ import com.google.gson.annotations.SerializedName;
|
||||
* @author Christoph Knauf - Added default constructor, changed Boolean
|
||||
* getter to return primitive types
|
||||
* @author Thomas Höfer - Added unit
|
||||
* @author Laurent Garnier - Removed constraint on unit value
|
||||
*/
|
||||
public class ConfigDescriptionParameter {
|
||||
|
||||
@ -182,9 +183,6 @@ public class ConfigDescriptionParameter {
|
||||
throw new IllegalArgumentException(
|
||||
"Unit or unit label must only be set for integer or decimal configuration parameters");
|
||||
}
|
||||
if (unit != null && !UNITS.contains(unit)) {
|
||||
throw new IllegalArgumentException("The given unit is invalid.");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
|
Loading…
Reference in New Issue
Block a user