Skip to content

Commit

Permalink
feat: Added type conversion math component
Browse files Browse the repository at this point in the history
Signed-off-by: MMaiero <[email protected]>
  • Loading branch information
MMaiero committed Aug 28, 2024
1 parent 30a2ed5 commit c04840e
Show file tree
Hide file tree
Showing 5 changed files with 366 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="org.eclipse.kura.wire.TypeConversion"
activate="activate"
deactivate="deactivate"
modified="updated"
enabled="true"
immediate="true"
configuration-policy="require">
<implementation class="org.eclipse.kura.example.wire.math.singleport.typeconversion.TypeConversionComponent"/>
<service>
<provide interface="org.eclipse.kura.configuration.ConfigurableComponent"/>
<provide interface="org.eclipse.kura.wire.WireComponent"/>
<provide interface="org.osgi.service.wireadmin.Consumer"/>
<provide interface="org.eclipse.kura.wire.WireEmitter"/>
<provide interface="org.eclipse.kura.wire.WireReceiver"/>
<provide interface="org.osgi.service.wireadmin.Producer"/>
</service>
<reference bind="bindWireHelperService"
cardinality="1..1"
interface="org.eclipse.kura.wire.WireHelperService"
name="WireHelperService"
policy="static"
unbind="unbindWireHelperService"/>
<property name="service.pid" value="org.eclipse.kura.wire.TypeConversion"/>
<property name="kura.ui.service.hide" type="Boolean" value="true"/>
<property name="input.cardinality.minimum" type="Integer" value="1"/>
<property name="input.cardinality.maximum" type="Integer" value="1"/>
<property name="input.cardinality.default" type="Integer" value="1"/>
<property name="output.cardinality.minimum" type="Integer" value="1"/>
<property name="output.cardinality.maximum" type="Integer" value="1"/>
<property name="output.cardinality.default" type="Integer" value="1"/>
</scr:component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<MetaData xmlns="http://www.osgi.org/xmlns/metatype/v1.2.0" localization="en_us">
<OCD id="org.eclipse.kura.wire.TypeConversion"
name="GainOffset"
description="A wire component that applies a type conversion to a configurable set of numerical input properties.">

<AD id="channels"
name="Channels and Conversion"
type="String" cardinality="0"
required="true"
default="channel1|Long"
description="Specifies the properties on which apply the type conversion. Separated by a new line|textarea">
</AD>

<AD id="emit.received.properties"
name="emit.received.properties"
type="Boolean" cardinality="0"
required="true"
default="false"
description="Specifies whether received properties should be included in the emitted envelope or not.">
</AD>
</OCD>

<Designate pid="org.eclipse.kura.wire.TypeConversion" factoryPid="org.eclipse.kura.wire.TypeConversion">
<Object ocdref="org.eclipse.kura.wire.TypeConversion"/>
</Designate>
</MetaData>
Original file line number Diff line number Diff line change
@@ -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<String, Object> properties, ComponentContext componentContext) {
this.wireSupport = this.wireHelperService.newWireSupport(this,
(ServiceReference<WireComponent>) componentContext.getServiceReference());
updated(properties);
}

public void updated(final Map<String, Object> 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<WireRecord> inputRecords = wireEnvelope.getRecords();
final List<WireRecord> 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<String, TypedValue<?>> inputProperties = record.getProperties();
final Map<String, TypedValue<?>> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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<TypeConversionEntry> entries;
private boolean emitReceivedProperties;

public TypeConversionComponentOptions(final Map<String, Object> 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<TypeConversionEntry> getEntries() {
return entries;
}

public boolean shouldEmitReceivedProperties() {
return emitReceivedProperties;
}

@SuppressWarnings("unchecked")
private <T> T getSafe(Object o, T defaultValue) {
if (defaultValue.getClass().isInstance(o)) {
return (T) o;
}
return defaultValue;
}
}
Original file line number Diff line number Diff line change
@@ -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<TypeConversionEntry> 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());
}
}

0 comments on commit c04840e

Please sign in to comment.