diff --git a/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/generic/ChannelTransformation.java b/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/generic/ChannelTransformation.java index 0cd9438ea32..69cf6c1d700 100644 --- a/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/generic/ChannelTransformation.java +++ b/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/generic/ChannelTransformation.java @@ -17,7 +17,9 @@ import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Stream; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.transform.TransformationException; import org.openhab.core.transform.TransformationHelper; @@ -33,6 +35,7 @@ * * @author Jan N. Klug - Initial contribution */ +@NonNullByDefault public class ChannelTransformation { private final Logger logger = LoggerFactory.getLogger(ChannelTransformation.class); private List transformationSteps; @@ -40,8 +43,8 @@ public class ChannelTransformation { public ChannelTransformation(@Nullable String transformationString) { if (transformationString != null) { try { - transformationSteps = Arrays.stream(transformationString.split("∩")).filter(s -> !s.isBlank()) - .map(TransformationStep::new).toList(); + transformationSteps = splitTransformationString(transformationString).map(TransformationStep::new) + .toList(); return; } catch (IllegalArgumentException e) { logger.warn("Transformation ignored, failed to parse {}: {}", transformationString, e.getMessage()); @@ -50,6 +53,24 @@ public ChannelTransformation(@Nullable String transformationString) { transformationSteps = List.of(); } + public ChannelTransformation(@Nullable List transformationStrings) { + if (transformationStrings != null) { + try { + transformationSteps = transformationStrings.stream() + .flatMap(ChannelTransformation::splitTransformationString).map(TransformationStep::new) + .toList(); + return; + } catch (IllegalArgumentException e) { + logger.warn("Transformation ignored, failed to parse {}: {}", transformationStrings, e.getMessage()); + } + } + transformationSteps = List.of(); + } + + private static Stream splitTransformationString(String transformationString) { + return Arrays.stream(transformationString.split("∩")).filter(s -> !s.isBlank()); + } + public Optional apply(String value) { Optional valueOptional = Optional.of(value); diff --git a/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/binding/generic/ChannelTransformationTest.java b/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/binding/generic/ChannelTransformationTest.java index f860fd0e7db..9dd0c6914cf 100644 --- a/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/binding/generic/ChannelTransformationTest.java +++ b/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/binding/generic/ChannelTransformationTest.java @@ -17,6 +17,8 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import java.util.List; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -54,8 +56,8 @@ public class ChannelTransformationTest { private static final String T3_NAME = T2_NAME; private static final String T3_PATTERN = "a()b()))"; - private static final String T3_INPUT = T2_INPUT; - private static final String T3_RESULT = T2_RESULT; + private static final String T3_INPUT = T2_RESULT; + private static final String T3_RESULT = "T3Result"; private @Mock @NonNullByDefault({}) TransformationService transformationService1Mock; private @Mock @NonNullByDefault({}) TransformationService transformationService2Mock; @@ -163,6 +165,38 @@ public void testColonDoubleTransformationWithoutSpaces() { assertEquals(T2_RESULT, result); } + @Test + public void testTransformationsInAList() { + List patterns = List.of(T1_NAME + ":" + T1_PATTERN, T2_NAME + ":" + T2_PATTERN); + + ChannelTransformation transformation = new ChannelTransformation(patterns); + String result = transformation.apply(T1_INPUT).orElse(null); + + assertEquals(T2_RESULT, result); + } + + @Test + public void testMixedTransformationsInAList1() { + List patterns = List.of(T1_NAME + ":" + T1_PATTERN + "∩" + T2_NAME + ":" + T2_PATTERN, + T3_NAME + ":" + T3_PATTERN); + + ChannelTransformation transformation = new ChannelTransformation(patterns); + String result = transformation.apply(T1_INPUT).orElse(null); + + assertEquals(T3_RESULT, result); + } + + @Test + public void testMixedTransformationsInAList2() { + List patterns = List.of(T1_NAME + ":" + T1_PATTERN, + T2_NAME + ":" + T2_PATTERN + "∩" + T3_NAME + ":" + T3_PATTERN); + + ChannelTransformation transformation = new ChannelTransformation(patterns); + String result = transformation.apply(T1_INPUT).orElse(null); + + assertEquals(T3_RESULT, result); + } + @Test public void testParensDoubleTransformationWithoutSpaces() { String pattern = T1_NAME + "(" + T1_PATTERN + ")∩" + T2_NAME + "(" + T2_PATTERN + ")"; diff --git a/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/binding/generic/converter/ConverterTest.java b/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/binding/generic/converter/ConverterTest.java index 229bfa237dc..ea293c01db6 100644 --- a/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/binding/generic/converter/ConverterTest.java +++ b/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/binding/generic/converter/ConverterTest.java @@ -62,7 +62,8 @@ public class ConverterTest { @Test public void numberItemConverter() { NumberChannelHandler converter = new NumberChannelHandler(updateStateMock, postCommandMock, sendValueMock, - new ChannelTransformation(null), new ChannelTransformation(null), new ChannelValueConverterConfig()); + new ChannelTransformation((String) null), new ChannelTransformation((String) null), + new ChannelValueConverterConfig()); // without unit Assertions.assertEquals(Optional.of(new DecimalType(1234)), converter.toState("1234")); @@ -80,7 +81,7 @@ public void numberItemConverterWithUnit() { ChannelValueConverterConfig channelConfig = new ChannelValueConverterConfig(); channelConfig.unit = "W"; NumberChannelHandler converter = new NumberChannelHandler(updateStateMock, postCommandMock, sendValueMock, - new ChannelTransformation(null), new ChannelTransformation(null), channelConfig); + new ChannelTransformation((String) null), new ChannelTransformation((String) null), channelConfig); // without unit Assertions.assertEquals(Optional.of(new QuantityType<>(500, Units.WATT)), converter.toState("500")); @@ -117,7 +118,7 @@ public void playerItemTypeConverter() { ChannelHandlerContent content = new ChannelHandlerContent("PLAY".getBytes(StandardCharsets.UTF_8), "UTF-8", null); PlayerChannelHandler converter = new PlayerChannelHandler(updateStateMock, postCommandMock, sendValueMock, - new ChannelTransformation(null), new ChannelTransformation(null), cfg); + new ChannelTransformation((String) null), new ChannelTransformation((String) null), cfg); converter.process(content); converter.process(content); @@ -132,7 +133,7 @@ public void colorItemTypeRGBConverter() { ChannelHandlerContent content = new ChannelHandlerContent("123,34,47".getBytes(StandardCharsets.UTF_8), "UTF-8", null); ColorChannelHandler converter = new ColorChannelHandler(updateStateMock, postCommandMock, sendValueMock, - new ChannelTransformation(null), new ChannelTransformation(null), cfg); + new ChannelTransformation((String) null), new ChannelTransformation((String) null), cfg); converter.process(content); Mockito.verify(updateStateMock).accept(HSBType.fromRGB(123, 34, 47)); @@ -145,7 +146,7 @@ public void colorItemTypeHSBConverter() { ChannelHandlerContent content = new ChannelHandlerContent("123,34,47".getBytes(StandardCharsets.UTF_8), "UTF-8", null); ColorChannelHandler converter = new ColorChannelHandler(updateStateMock, postCommandMock, sendValueMock, - new ChannelTransformation(null), new ChannelTransformation(null), cfg); + new ChannelTransformation((String) null), new ChannelTransformation((String) null), cfg); converter.process(content); Mockito.verify(updateStateMock).accept(new HSBType("123,34,47")); @@ -155,7 +156,7 @@ public void colorItemTypeHSBConverter() { public void rollerSHutterConverter() { ChannelValueConverterConfig cfg = new ChannelValueConverterConfig(); RollershutterChannelHandler converter = new RollershutterChannelHandler(updateStateMock, postCommandMock, - sendValueMock, new ChannelTransformation(null), new ChannelTransformation(null), cfg); + sendValueMock, new ChannelTransformation((String) null), new ChannelTransformation((String) null), cfg); // test 0 and 100 ChannelHandlerContent content = new ChannelHandlerContent("0".getBytes(StandardCharsets.UTF_8), "UTF-8", null); @@ -181,6 +182,7 @@ public void rollerSHutterConverter() { public GenericChannelHandler createConverter(Function fcn) { return new GenericChannelHandler(fcn, updateStateMock, postCommandMock, sendValueMock, - new ChannelTransformation(null), new ChannelTransformation(null), new ChannelValueConverterConfig()); + new ChannelTransformation((String) null), new ChannelTransformation((String) null), + new ChannelValueConverterConfig()); } } diff --git a/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/internal/binding/generic/converter/AbstractTransformingItemConverterTest.java b/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/internal/binding/generic/converter/AbstractTransformingItemConverterTest.java index bf4725b2f96..8011d7eff8f 100644 --- a/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/internal/binding/generic/converter/AbstractTransformingItemConverterTest.java +++ b/bundles/org.openhab.core.thing/src/test/java/org/openhab/core/thing/internal/binding/generic/converter/AbstractTransformingItemConverterTest.java @@ -59,10 +59,10 @@ public class AbstractTransformingItemConverterTest { private @NonNullByDefault({}) AutoCloseable closeable; @Spy - private ChannelTransformation stateChannelTransformation = new ChannelTransformation(null); + private ChannelTransformation stateChannelTransformation = new ChannelTransformation((String) null); @Spy - private ChannelTransformation commandChannelTransformation = new ChannelTransformation(null); + private ChannelTransformation commandChannelTransformation = new ChannelTransformation((String) null); @BeforeEach public void init() {