You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2024/02/14 09:48:02 UTC

(plc4x) branch develop updated: feat: add support for nested configuration in the metadata reporting

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new 387c44f01c feat: add support for nested configuration in the metadata reporting
387c44f01c is described below

commit 387c44f01ceb94939405b381beb5c7e0c7fd9fbe
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Wed Feb 14 10:47:49 2024 +0100

    feat: add support for nested configuration in the metadata reporting
---
 plc4j/drivers/all/src/site/generated/firmata.adoc  |   2 +-
 .../all/src/site/generated/modbus-ascii.adoc       |   2 +-
 .../drivers/all/src/site/generated/modbus-rtu.adoc |   2 +-
 plc4j/drivers/all/src/site/generated/opcua.adoc    |   5 +-
 .../java/spi/connection/GeneratedDriverBase.java   | 302 ++++++++-------------
 5 files changed, 122 insertions(+), 191 deletions(-)

diff --git a/plc4j/drivers/all/src/site/generated/firmata.adoc b/plc4j/drivers/all/src/site/generated/firmata.adoc
index f08198567b..e6ee1a3fdd 100644
--- a/plc4j/drivers/all/src/site/generated/firmata.adoc
+++ b/plc4j/drivers/all/src/site/generated/firmata.adoc
@@ -57,7 +57,7 @@ Typical values are:
 - 1
 - 2
 (The theoretical 1.5 stop-bits setting is not supported)
-|`serial.parity` |STRUCT |NO_PARITY| |Number of bits used to calculate data parity.
+|`serial.parity` |STRING |NO_PARITY| |Number of bits used to calculate data parity.
 This is used to detect errors in transmission.
 Allowed values are:
 - NO_PARITY
diff --git a/plc4j/drivers/all/src/site/generated/modbus-ascii.adoc b/plc4j/drivers/all/src/site/generated/modbus-ascii.adoc
index 203d421145..ca81e9a4ff 100644
--- a/plc4j/drivers/all/src/site/generated/modbus-ascii.adoc
+++ b/plc4j/drivers/all/src/site/generated/modbus-ascii.adoc
@@ -64,7 +64,7 @@ Typical values are:
 - 1
 - 2
 (The theoretical 1.5 stop-bits setting is not supported)
-|`serial.parity` |STRUCT |NO_PARITY| |Number of bits used to calculate data parity.
+|`serial.parity` |STRING |NO_PARITY| |Number of bits used to calculate data parity.
 This is used to detect errors in transmission.
 Allowed values are:
 - NO_PARITY
diff --git a/plc4j/drivers/all/src/site/generated/modbus-rtu.adoc b/plc4j/drivers/all/src/site/generated/modbus-rtu.adoc
index 8dc898c0de..aa5648ad0a 100644
--- a/plc4j/drivers/all/src/site/generated/modbus-rtu.adoc
+++ b/plc4j/drivers/all/src/site/generated/modbus-rtu.adoc
@@ -64,7 +64,7 @@ Typical values are:
 - 1
 - 2
 (The theoretical 1.5 stop-bits setting is not supported)
-|`serial.parity` |STRUCT |NO_PARITY| |Number of bits used to calculate data parity.
+|`serial.parity` |STRING |NO_PARITY| |Number of bits used to calculate data parity.
 This is used to detect errors in transmission.
 Allowed values are:
 - NO_PARITY
diff --git a/plc4j/drivers/all/src/site/generated/opcua.adoc b/plc4j/drivers/all/src/site/generated/opcua.adoc
index 2bff9f83be..bbe9322694 100644
--- a/plc4j/drivers/all/src/site/generated/opcua.adoc
+++ b/plc4j/drivers/all/src/site/generated/opcua.adoc
@@ -64,7 +64,10 @@ Possible values are between others `jks`, `pkcs11`, `dks`, `jceks`.
 |`session-timeout` |LONG |120000| |Expiry time for opened secure session, value in milliseconds. Defaults to 2 minutes.
 |`negotiation-timeout` |LONG |60000| |Timeout for all negotiation steps prior acceptance of application level operations - this timeout applies to open secure channel, create session and close calls. Defaults to 60 seconds.
 |`request-timeout` |LONG |30000| |Timeout for read/write/subscribe calls. Value in milliseconds.
-|`encoding` |STRUCT | | |TCP encoding options
+|`encoding.receive-buffer-size` |INT |Optional[65535]| |Maximum size of received TCP transport message chunk value in bytes.
+|`encoding.send-buffer-size` |INT |Optional[65535]| |Maximum size of sent transport message chunk.
+|`encoding.max-message-size` |INT |Optional[2097152]| |Maximum size of complete message.
+|`encoding.max-chunk-count` |INT |Optional[64]| |Maximum number of chunks for both sent and received messages.
 5+|Transport config options:
 5+| - `tcp`
 |`tcp.keep-alive` |BOOLEAN |false| |Should keep-alive packets be sent?
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/GeneratedDriverBase.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/GeneratedDriverBase.java
index 58c1001459..127155c13a 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/GeneratedDriverBase.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/GeneratedDriverBase.java
@@ -21,6 +21,7 @@ package org.apache.plc4x.java.spi.connection;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.PlcDriver;
 import org.apache.plc4x.java.api.authentication.PlcAuthentication;
+import org.apache.plc4x.java.api.configuration.PlcConfiguration;
 import org.apache.plc4x.java.api.configuration.PlcConnectionConfiguration;
 import org.apache.plc4x.java.api.configuration.PlcTransportConfiguration;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
@@ -86,7 +87,7 @@ public abstract class GeneratedDriverBase<BASE_PACKET extends Message> implement
             @Override
             public List<String> getSupportedTransportCodes() {
                 List<String> supportedTransportCodes = GeneratedDriverBase.this.getSupportedTransportCodes();
-                if(supportedTransportCodes.isEmpty() && (getDefaultTransportCode().isPresent())) {
+                if (supportedTransportCodes.isEmpty() && (getDefaultTransportCode().isPresent())) {
                     return Collections.singletonList(getDefaultTransportCode().get());
                 }
                 return GeneratedDriverBase.this.getSupportedTransportCodes();
@@ -98,100 +99,7 @@ public abstract class GeneratedDriverBase<BASE_PACKET extends Message> implement
                 if (clazz == null) {
                     return Optional.empty();
                 }
-                var options = getAllFields(clazz).stream().map(field -> {
-                        String key = null;
-                        var configurationParameterAnnotation = field.getAnnotation(ConfigurationParameter.class);
-                        if (configurationParameterAnnotation != null) {
-                            key = configurationParameterAnnotation.value();
-                            if(key.isEmpty()) {
-                                key = field.getName();
-                            }
-                        } else {
-                            var complexConfigurationParameterAnnotation = field.getAnnotation(ComplexConfigurationParameter.class);
-                            if (complexConfigurationParameterAnnotation != null) {
-                                key = complexConfigurationParameterAnnotation.prefix();
-                                // TODO: Add support for listing the options of a complex configuration parameter.
-                            }
-                        }
-                        if(key == null) {
-                            return null;
-                        }
-                        String description = "";
-                        var descriptionAnnotation = field.getAnnotation(Description.class);
-                        if (descriptionAnnotation != null) {
-                            description = descriptionAnnotation.value();
-                        }
-                        boolean required = false;
-                        var requiredAnnotation = field.getAnnotation(Required.class);
-                        if (requiredAnnotation != null) {
-                            required = true;
-                        }
-                        OptionType type;
-                        switch (field.getType().getSimpleName()) {
-                            case "boolean":
-                            case "Boolean":
-                                type = OptionType.BOOLEAN;
-                                break;
-                            case "float":
-                            case "Float":
-                                type = OptionType.FLOAT;
-                                break;
-                            case "double":
-                            case "Double":
-                                type = OptionType.DOUBLE;
-                                break;
-                            case "int":
-                            case "Integer":
-                                type = OptionType.INT;
-                                break;
-                            case "long":
-                            case "Long":
-                                type = OptionType.LONG;
-                                break;
-                            case "String":
-                                type = OptionType.STRING;
-                                break;
-                            default:
-                                // If there's a property-converter, use "STRING" as type.
-                                var parameterConverterAnnotation = field.getAnnotation(ParameterConverter.class);
-                                if(parameterConverterAnnotation != null) {
-                                   type = OptionType.STRING;
-                                } else {
-                                    type = OptionType.STRUCT;
-                                }
-                                break;
-                        }
-                        Object defaultValue = null;
-                        var booleanDefaultValueAnnotation = field.getAnnotation(BooleanDefaultValue.class);
-                        if (booleanDefaultValueAnnotation != null) {
-                            defaultValue = booleanDefaultValueAnnotation.value();
-                        }
-                        var doubleDefaultValueAnnotation = field.getAnnotation(DoubleDefaultValue.class);
-                        if (doubleDefaultValueAnnotation != null) {
-                            defaultValue = doubleDefaultValueAnnotation.value();
-                        }
-                        var floatDefaultValueAnnotation = field.getAnnotation(FloatDefaultValue.class);
-                        if (floatDefaultValueAnnotation != null) {
-                            defaultValue = floatDefaultValueAnnotation.value();
-                        }
-                        var intDefaultValueAnnotation = field.getAnnotation(IntDefaultValue.class);
-                        if (intDefaultValueAnnotation != null) {
-                            defaultValue = intDefaultValueAnnotation.value();
-                        }
-                        var longDefaultValueAnnotation = field.getAnnotation(LongDefaultValue.class);
-                        if (longDefaultValueAnnotation != null) {
-                            defaultValue = longDefaultValueAnnotation.value();
-                        }
-                        var stringDefaultValueAnnotation = field.getAnnotation(StringDefaultValue.class);
-                        if (stringDefaultValueAnnotation != null) {
-                            type = OptionType.STRING;
-                            defaultValue = stringDefaultValueAnnotation.value();
-                        }
-                        return new DefaultOption(key, type, description, required, defaultValue);
-                    })
-                    .filter(Objects::nonNull)
-                    .map(Option.class::cast)
-                    .collect(Collectors.toList());
+                var options = getOptions(clazz);
                 return Optional.of(new DefaultOptionMetadata(options));
             }
 
@@ -202,100 +110,120 @@ public abstract class GeneratedDriverBase<BASE_PACKET extends Message> implement
                     return Optional.empty();
                 }
                 var clazz = clazzOption.get();
-                var options = getAllFields(clazz).stream().map(field -> {
-                        String key = null;
-                        var configurationParameterAnnotation = field.getAnnotation(ConfigurationParameter.class);
-                        if (configurationParameterAnnotation != null) {
-                            key = configurationParameterAnnotation.value();
-                            if(key.isEmpty()) {
-                                key = field.getName();
-                            }
-                        } else {
-                            var complexConfigurationParameterAnnotation = field.getAnnotation(ComplexConfigurationParameter.class);
-                            if (complexConfigurationParameterAnnotation != null) {
-                                key = complexConfigurationParameterAnnotation.prefix();
-                                // TODO: Add support for listing the options of a complex configuration parameter.
-                            }
-                        }
-                        if(key == null) {
-                            return null;
-                        }
-                        String description = "";
-                        var descriptionAnnotation = field.getAnnotation(Description.class);
-                        if (descriptionAnnotation != null) {
-                            description = descriptionAnnotation.value();
-                        }
-                        boolean required = false;
-                        var requiredAnnotation = field.getAnnotation(Required.class);
-                        if (requiredAnnotation != null) {
-                            required = true;
-                        }
-                        OptionType type;
-                        switch (field.getType().getSimpleName()) {
-                            case "boolean":
-                            case "Boolean":
-                                type = OptionType.BOOLEAN;
-                                break;
-                            case "float":
-                            case "Float":
-                                type = OptionType.FLOAT;
-                                break;
-                            case "double":
-                            case "Double":
-                                type = OptionType.DOUBLE;
-                                break;
-                            case "int":
-                            case "Integer":
-                                type = OptionType.INT;
-                                break;
-                            case "long":
-                            case "Long":
-                                type = OptionType.LONG;
-                                break;
-                            case "String":
-                                type = OptionType.STRING;
-                                break;
-                            default:
-                                // If there's a property-converter, use "STRING" as type.
-                                var parameterConverterAnnotation = field.getAnnotation(ParameterConverter.class);
-                                if(parameterConverterAnnotation != null) {
-                                    type = OptionType.STRING;
-                                } else {
-                                    type = OptionType.STRUCT;
-                                }
-                                break;
-                        }
-                        Object defaultValue = null;
-                        var booleanDefaultValueAnnotation = field.getAnnotation(BooleanDefaultValue.class);
-                        if (booleanDefaultValueAnnotation != null) {
-                            defaultValue = booleanDefaultValueAnnotation.value();
-                        }
-                        var doubleDefaultValueAnnotation = field.getAnnotation(DoubleDefaultValue.class);
-                        if (doubleDefaultValueAnnotation != null) {
-                            defaultValue = doubleDefaultValueAnnotation.value();
-                        }
-                        var floatDefaultValueAnnotation = field.getAnnotation(FloatDefaultValue.class);
-                        if (floatDefaultValueAnnotation != null) {
-                            defaultValue = floatDefaultValueAnnotation.value();
-                        }
-                        var intDefaultValueAnnotation = field.getAnnotation(IntDefaultValue.class);
-                        if (intDefaultValueAnnotation != null) {
-                            defaultValue = intDefaultValueAnnotation.value();
-                        }
-                        var longDefaultValueAnnotation = field.getAnnotation(LongDefaultValue.class);
-                        if (longDefaultValueAnnotation != null) {
-                            defaultValue = longDefaultValueAnnotation.value();
-                        }
-                        var stringDefaultValueAnnotation = field.getAnnotation(StringDefaultValue.class);
-                        if (stringDefaultValueAnnotation != null) {
-                            defaultValue = stringDefaultValueAnnotation.value();
-                        }
-                        return new DefaultOption(key, type, description, required, defaultValue);
-                    })
+                var options = getOptions(clazz);
+                return Optional.of(new DefaultOptionMetadata(options));
+            }
+
+            private List<Option> getOptions(Class<? extends PlcConfiguration> clazz) {
+                return getAllFields(clazz).stream()
+                    .map(this::optionsForField)
+                    .flatMap(Collection::stream)
                     .filter(Objects::nonNull)
                     .map(Option.class::cast)
                     .collect(Collectors.toList());
-                return Optional.of(new DefaultOptionMetadata(options));
+            }
+
+            private List<DefaultOption> optionsForField(Field field) {
+                // check if this is a complex configuration parameter and bail early
+                var complexConfigurationParameterAnnotation = field.getAnnotation(ComplexConfigurationParameter.class);
+                if (complexConfigurationParameterAnnotation != null) {
+                    var prefix = complexConfigurationParameterAnnotation.prefix();
+                    if (PlcConfiguration.class.isAssignableFrom(field.getType())) {
+                        return getOptions((Class<? extends PlcConfiguration>) field.getType())
+                            .stream()
+                            .map(option -> new DefaultOption(
+                                prefix + "." + option.getKey(),
+                                option.getType(),
+                                option.getDescription(),
+                                option.isRequired(),
+                                option.getDefaultValue()
+                            ))
+                            .collect(Collectors.toList());
+                    }
+                }
+                String key = null;
+                var configurationParameterAnnotation = field.getAnnotation(ConfigurationParameter.class);
+                if (configurationParameterAnnotation != null) {
+                    key = configurationParameterAnnotation.value();
+                    if (key.isEmpty()) {
+                        key = field.getName();
+                    }
+                }
+                if (key == null) {
+                    return Collections.emptyList();
+                }
+                String description = "";
+                var descriptionAnnotation = field.getAnnotation(Description.class);
+                if (descriptionAnnotation != null) {
+                    description = descriptionAnnotation.value();
+                }
+                boolean required = false;
+                var requiredAnnotation = field.getAnnotation(Required.class);
+                if (requiredAnnotation != null) {
+                    required = true;
+                }
+                OptionType type;
+                switch (field.getType().getSimpleName()) {
+                    case "boolean":
+                    case "Boolean":
+                        type = OptionType.BOOLEAN;
+                        break;
+                    case "float":
+                    case "Float":
+                        type = OptionType.FLOAT;
+                        break;
+                    case "double":
+                    case "Double":
+                        type = OptionType.DOUBLE;
+                        break;
+                    case "int":
+                    case "Integer":
+                        type = OptionType.INT;
+                        break;
+                    case "long":
+                    case "Long":
+                        type = OptionType.LONG;
+                        break;
+                    case "String":
+                        type = OptionType.STRING;
+                        break;
+                    default:
+                        // If there's a property-converter, use "STRING" as type.
+                        var parameterConverterAnnotation = field.getAnnotation(ParameterConverter.class);
+                        if (parameterConverterAnnotation != null) {
+                            type = OptionType.STRING;
+                        } else {
+                            type = OptionType.STRUCT;
+                        }
+                        break;
+                }
+                Object defaultValue = null;
+                var booleanDefaultValueAnnotation = field.getAnnotation(BooleanDefaultValue.class);
+                if (booleanDefaultValueAnnotation != null) {
+                    defaultValue = booleanDefaultValueAnnotation.value();
+                }
+                var doubleDefaultValueAnnotation = field.getAnnotation(DoubleDefaultValue.class);
+                if (doubleDefaultValueAnnotation != null) {
+                    defaultValue = doubleDefaultValueAnnotation.value();
+                }
+                var floatDefaultValueAnnotation = field.getAnnotation(FloatDefaultValue.class);
+                if (floatDefaultValueAnnotation != null) {
+                    defaultValue = floatDefaultValueAnnotation.value();
+                }
+                var intDefaultValueAnnotation = field.getAnnotation(IntDefaultValue.class);
+                if (intDefaultValueAnnotation != null) {
+                    defaultValue = intDefaultValueAnnotation.value();
+                }
+                var longDefaultValueAnnotation = field.getAnnotation(LongDefaultValue.class);
+                if (longDefaultValueAnnotation != null) {
+                    defaultValue = longDefaultValueAnnotation.value();
+                }
+                var stringDefaultValueAnnotation = field.getAnnotation(StringDefaultValue.class);
+                if (stringDefaultValueAnnotation != null) {
+                    type = OptionType.STRING;
+                    defaultValue = stringDefaultValueAnnotation.value();
+                }
+                return Collections.singletonList(new DefaultOption(key, type, description, required, defaultValue));
             }
 
             @Override
@@ -497,7 +425,7 @@ public abstract class GeneratedDriverBase<BASE_PACKET extends Message> implement
 
     protected List<Field> getAllFields(Class<?> type) {
         List<Field> fields = new ArrayList<>(Arrays.asList(type.getDeclaredFields()));
-        if(type.getSuperclass() != null) {
+        if (type.getSuperclass() != null) {
             fields.addAll(getAllFields(type.getSuperclass()));
         }
         return fields;