From 3752d0e6fe95cc6cc1af776be2b7dfc3c66184e3 Mon Sep 17 00:00:00 2001 From: MMaiero Date: Wed, 28 Aug 2024 19:04:51 +0200 Subject: [PATCH] feat: Added type conversion math component Signed-off-by: MMaiero --- .../OSGI-INF/TypeConversionComponent.xml | 47 ++++++ .../org.eclipse.kura.wire.TypeConversion.xml | 41 +++++ .../TypeConversionComponent.java | 141 ++++++++++++++++++ .../TypeConversionComponentOptions.java | 52 +++++++ .../typeconversion/TypeConversionEntry.java | 85 +++++++++++ 5 files changed, 366 insertions(+) create mode 100644 kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/OSGI-INF/TypeConversionComponent.xml create mode 100644 kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/OSGI-INF/metatype/org.eclipse.kura.wire.TypeConversion.xml create mode 100644 kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionComponent.java create mode 100644 kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionComponentOptions.java create mode 100644 kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionEntry.java diff --git a/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/OSGI-INF/TypeConversionComponent.xml b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/OSGI-INF/TypeConversionComponent.xml new file mode 100644 index 00000000000..fc4edad86c4 --- /dev/null +++ b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/OSGI-INF/TypeConversionComponent.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/OSGI-INF/metatype/org.eclipse.kura.wire.TypeConversion.xml b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/OSGI-INF/metatype/org.eclipse.kura.wire.TypeConversion.xml new file mode 100644 index 00000000000..98c3caa5f11 --- /dev/null +++ b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/OSGI-INF/metatype/org.eclipse.kura.wire.TypeConversion.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + diff --git a/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionComponent.java b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionComponent.java new file mode 100644 index 00000000000..83b0cdf24c6 --- /dev/null +++ b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionComponent.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2024 Eurotech and/or its affiliates and others + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eurotech + *******************************************************************************/ + +package org.eclipse.kura.example.wire.math.singleport.typeconversion; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.kura.configuration.ConfigurableComponent; +import org.eclipse.kura.type.DataType; +import org.eclipse.kura.type.TypedValue; +import org.eclipse.kura.type.TypedValues; +import org.eclipse.kura.wire.WireComponent; +import org.eclipse.kura.wire.WireEmitter; +import org.eclipse.kura.wire.WireEnvelope; +import org.eclipse.kura.wire.WireHelperService; +import org.eclipse.kura.wire.WireReceiver; +import org.eclipse.kura.wire.WireRecord; +import org.eclipse.kura.wire.WireSupport; +import org.osgi.framework.ServiceReference; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.wireadmin.Wire; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TypeConversionComponent implements WireEmitter, WireReceiver, ConfigurableComponent { + + private static final Logger logger = LoggerFactory.getLogger(TypeConversionComponent.class); + + private WireHelperService wireHelperService; + private WireSupport wireSupport; + + private TypeConversionComponentOptions options; + + public void bindWireHelperService(final WireHelperService wireHelperService) { + this.wireHelperService = wireHelperService; + } + + public void unbindWireHelperService(final WireHelperService wireHelperService) { + if (this.wireHelperService == wireHelperService) { + this.wireHelperService = null; + } + } + + public void activate(final Map properties, ComponentContext componentContext) { + this.wireSupport = this.wireHelperService.newWireSupport(this, + (ServiceReference) componentContext.getServiceReference()); + updated(properties); + } + + public void updated(final Map properties) { + try { + this.options = new TypeConversionComponentOptions(properties); + } catch (Exception e) { + logger.warn("Invalid configuration, please review", e); + this.options = null; + } + } + + public void deactivate() { + } + + @Override + public Object polled(Wire wire) { + return wireSupport.polled(wire); + } + + @Override + public void consumersConnected(Wire[] wires) { + wireSupport.consumersConnected(wires); + } + + @Override + public void updated(Wire wire, Object value) { + wireSupport.updated(wire, value); + } + + @Override + public void producersConnected(Wire[] wires) { + wireSupport.producersConnected(wires); + } + + @Override + public void onWireReceive(WireEnvelope wireEnvelope) { + if (options == null) { + logger.warn("Invalid configuration, please review"); + } + final List inputRecords = wireEnvelope.getRecords(); + final List records = new ArrayList<>(inputRecords.size()); + for (final WireRecord record : inputRecords) { + records.add(processRecord(record)); + } + this.wireSupport.emit(records); + } + + private WireRecord processRecord(WireRecord record) { + final Map> inputProperties = record.getProperties(); + final Map> outProperties = new HashMap<>(); + if (this.options.shouldEmitReceivedProperties()) { + outProperties.putAll(inputProperties); + } + for (TypeConversionEntry e : this.options.getEntries()) { + final String propertyName = e.getPropertyName(); + final TypedValue typedValue = inputProperties.get(propertyName); + if (typedValue == null) { + continue; + } + final Object value = typedValue.getValue(); + if (!(value instanceof Number)) { + logger.warn("Invalid property value: {}={}", propertyName, typedValue); + continue; + } + if (e.getType().equals(DataType.DOUBLE)) { + outProperties.put(propertyName, + TypedValues.newDoubleValue(((Number) value).doubleValue())); + } else if (e.getType().equals(DataType.FLOAT)) { + outProperties.put(propertyName, + TypedValues.newFloatValue(((Number) value).floatValue())); + } else if (e.getType().equals(DataType.INTEGER)) { + outProperties.put(propertyName, + TypedValues.newFloatValue(((Number) value).intValue())); + } else if (e.getType().equals(DataType.LONG)) { + outProperties.put(propertyName, + TypedValues.newFloatValue(((Number) value).longValue())); + } + } + return new WireRecord(outProperties); + } +} diff --git a/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionComponentOptions.java b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionComponentOptions.java new file mode 100644 index 00000000000..15263b8d1f2 --- /dev/null +++ b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionComponentOptions.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2024 Eurotech and/or its affiliates and others + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eurotech + *******************************************************************************/ + +package org.eclipse.kura.example.wire.math.singleport.typeconversion; + +import java.util.List; +import java.util.Map; + +public class TypeConversionComponentOptions { + + private static final String CONFIGURATION_PROP_NAME = "channels"; + private static final String EMIT_RECEIVED_PROPERTIES_PROP_NAME = "emit.received.properties"; + + private static final boolean EMIT_RECEIVED_PROPERTIES_DEFAULT = false; + private static final String CONFIGURATION_DEFAULT = ""; + + private List entries; + private boolean emitReceivedProperties; + + public TypeConversionComponentOptions(final Map properties) { + this.emitReceivedProperties = getSafe(properties.get(EMIT_RECEIVED_PROPERTIES_PROP_NAME), + EMIT_RECEIVED_PROPERTIES_DEFAULT); + this.entries = TypeConversionEntry + .parseAll(getSafe(properties.get(CONFIGURATION_PROP_NAME), CONFIGURATION_DEFAULT)); + } + + public List getEntries() { + return entries; + } + + public boolean shouldEmitReceivedProperties() { + return emitReceivedProperties; + } + + @SuppressWarnings("unchecked") + private T getSafe(Object o, T defaultValue) { + if (defaultValue.getClass().isInstance(o)) { + return (T) o; + } + return defaultValue; + } +} diff --git a/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionEntry.java b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionEntry.java new file mode 100644 index 00000000000..9abfb058a56 --- /dev/null +++ b/kura/examples/org.eclipse.kura.example.wire.math.singleport.provider/src/main/java/org/eclipse/kura/example/wire/math/singleport/typeconversion/TypeConversionEntry.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2024 Eurotech and/or its affiliates and others + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eurotech + *******************************************************************************/ + +package org.eclipse.kura.example.wire.math.singleport.typeconversion; + +import static java.util.Objects.requireNonNull; + +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.eclipse.kura.type.DataType; + +public class TypeConversionEntry { + + private static final Pattern ENTRY_DELIMITER = Pattern.compile("[;\n]"); + private static final Pattern FIELD_DELIMITER = Pattern.compile("[|]"); + + private final String propertyName; + private final DataType type; + + public TypeConversionEntry(final String propertyName, final DataType type) { + this.propertyName = propertyName; + this.type = type; + } + + public String getPropertyName() { + return propertyName; + } + + public DataType getType() { + return type; + } + + private static void clear(String[] entryArray) { + entryArray[0] = null; + entryArray[1] = null; + } + + private static TypeConversionEntry parse(final String entryString, final String[] tempArray) { + try { + clear(tempArray); + + FIELD_DELIMITER.splitAsStream(entryString).map(String::trim).filter(s -> !s.isEmpty()) + .toArray(i -> tempArray); + + requireNonNull(tempArray[0]); + requireNonNull(tempArray[1]); + String typeTemp = tempArray[1]; + DataType dataType; + + if ("double".equalsIgnoreCase(typeTemp)) { + dataType = DataType.DOUBLE; + } else if ("float".equalsIgnoreCase(typeTemp)) { + dataType = DataType.FLOAT; + } else if ("integer".equalsIgnoreCase(typeTemp)) { + dataType = DataType.INTEGER; + } else if ("long".equalsIgnoreCase(typeTemp)) { + dataType = DataType.LONG; + } else { + throw new IllegalArgumentException("Unsupported type"); + } + + return new TypeConversionEntry(tempArray[0], dataType); + } catch (Exception e) { + throw new IllegalArgumentException("Invalid entry: " + entryString); + } + } + + public static List parseAll(String configuration) { + final String[] tempArray = new String[3]; + return ENTRY_DELIMITER.splitAsStream(configuration).map(String::trim).filter(s -> !s.isEmpty()) + .map(entryString -> parse(entryString, tempArray)).collect(Collectors.toList()); + } +}