You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by ld...@apache.org on 2021/07/29 13:24:05 UTC

[plc4x] branch feature/PLC4X-307 updated (35ff4b5 -> 8c76728)

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

ldywicki pushed a change to branch feature/PLC4X-307
in repository https://gitbox.apache.org/repos/asf/plc4x.git.


    from 35ff4b5  plc4go: initial bacnet draft
     add ba6c58b  added language x protocol table
     add 0df4777  Update index.adoc
     add d652e05  Update index.adoc
     add dc98df2  Feature/native opua client (#253)
     add 0f8c760  Fix for initial OPCUA sequence number, some servers don't start at 1
     new 43f239e  PLC4X-307 Add support for custom generator options.
     new 8c76728  PLC4X-307 Provide configuration options for test framework.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../BaseFreemarkerLanguageTemplateHelper.java      |   24 +-
 .../freemarker/FreemarkerLanguageOutput.java       |   11 +-
 .../apache/plc4x/language/c/CLanguageOutput.java   |    9 +-
 .../apache/plc4x/language/go/GoLanguageOutput.java |    8 +-
 .../plc4x/language/java/JavaLanguageOutput.java    |   10 +-
 .../language/java/JavaLanguageTemplateHelper.java  |   14 +-
 .../resources/templates/java/io-template.java.ftlh |   48 +-
 .../templates/java/pojo-template.java.ftlh         |    2 +
 .../definitions/DefaultComplexTypeDefinition.java  |    5 +
 .../src/main/resources/protocols/test/test.mspec   |   44 +-
 plc4j/drivers/opcua/pom.xml                        |   82 +-
 .../apache/plc4x/java/opcua/OpcuaPlcDriver.java    |  233 +++-
 .../java/opcua/config/OpcuaConfiguration.java      |  229 ++++
 .../opcua/connection/BaseOpcuaPlcConnection.java   |  103 --
 .../opcua/connection/OpcuaConnectionFactory.java   |   38 -
 .../opcua/connection/OpcuaTcpPlcConnection.java    |  919 ---------------
 .../java/opcua}/context/CertificateGenerator.java  |   38 +-
 .../java/opcua}/context/CertificateKeyPair.java    |   10 +-
 .../java/opcua/context/EncryptionHandler.java      |  246 ++++
 .../plc4x/java/opcua/context/SecureChannel.java    | 1201 ++++++++++++++++++++
 .../context/SecureChannelTransactionManager.java   |  116 ++
 .../java/opcua/{protocol => field}/OpcuaField.java |   13 +-
 .../{protocol => field}/OpcuaPlcFieldHandler.java  |    5 +-
 .../plc4x/java/opcua/optimizer/OpcuaOptimizer.java |   58 +
 .../java/opcua/protocol/OpcuaProtocolLogic.java    |  905 +++++++++++++++
 .../opcua/protocol/OpcuaSubscriptionHandle.java    |  489 ++++++++
 .../opcua/protocol/OpcuaSubsriptionHandle.java     |   92 --
 .../apache/plc4x/java/opcua/ManualPLC4XOpcua.java  |  135 ++-
 .../plc4x/java/opcua/OpcuaPlcDriverTest.java       |   48 +-
 .../connection/OpcuaTcpPlcConnectionTest.java      |   40 +-
 .../plc4x/java/opcua/protocol/OpcuaFieldTest.java  |    2 +-
 .../protocol/OpcuaSubscriptionHandleTest.java      |  511 ++++++++-
 .../opcua/src/test/resources/log4j.properties}     |    2 +-
 .../opcua/src/test/resources/logback.xml}          |   14 +-
 .../plc4x/java/examples/helloplc4x/HelloPlc4x.java |    1 +
 .../apache/plc4x/java/opcuaserver/UtilsTest.java   |   40 -
 .../apache/plc4x/java/spi/ConversationContext.java |    3 +
 .../apache/plc4x/java/spi/Plc4xNettyWrapper.java   |   20 +-
 .../apache/plc4x/java/spi/Plc4xProtocolBase.java   |    4 +
 .../spi/connection/DefaultNettyPlcConnection.java  |   38 +-
 .../java/spi/connection/GeneratedDriverBase.java   |   13 +-
 .../{ConnectEvent.java => DiscoverEvent.java}      |    2 +-
 .../{ConnectedEvent.java => DiscoveredEvent.java}  |   12 +-
 .../java/spi/generation/WriteBufferByteBased.java  |    4 +
 .../test/driver/internal/DriverTestsuite.java      |   28 +-
 .../internal/DriverTestsuiteConfiguration.java     |   14 +-
 .../handlers/IncomingPlcMessageHandler.java        |    2 +-
 .../handlers/OutgoingPlcMessageHandler.java        |    2 +-
 .../plc4x/test/migration/MessageResolver.java      |   92 +-
 .../migration/MessageValidatorAndMigrator.java     |   25 +-
 .../ParserSerializerTestsuiteRunner.java           |   20 +-
 .../model/ParserSerializerTestsuite.java           |    9 +-
 .../test/parserserializer/model/Testcase.java      |    1 +
 .../java/org/apache/plc4x/test/xml/XmlHelper.java  |   53 +
 .../main/resources/schemas/driver-testsuite.xsd    |   39 +-
 .../schemas/parser-serializer-testsuite.xsd        |   22 +
 protocols/opcua/pom.xml                            |  204 ++++
 .../apache/plc4x/protocol/opcua/OpcuaProtocol.java |   35 +-
 protocols/opcua/src/main/xslt/opc-common.xsl       |  500 ++++++++
 protocols/opcua/src/main/xslt/opc-manual.xsl       |  436 +++++++
 protocols/opcua/src/main/xslt/opc-services.xsl     |   62 +
 protocols/opcua/src/main/xslt/opc-status.xsl       |   58 +
 protocols/opcua/src/main/xslt/opc-types.xsl        |   58 +
 src/site/asciidoc/users/protocols/index.adoc       |  139 ++-
 64 files changed, 6076 insertions(+), 1564 deletions(-)
 create mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/config/OpcuaConfiguration.java
 delete mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/BaseOpcuaPlcConnection.java
 delete mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/OpcuaConnectionFactory.java
 delete mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/connection/OpcuaTcpPlcConnection.java
 copy plc4j/{integrations/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver => drivers/opcua/src/main/java/org/apache/plc4x/java/opcua}/context/CertificateGenerator.java (75%)
 copy plc4j/{integrations/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver => drivers/opcua/src/main/java/org/apache/plc4x/java/opcua}/context/CertificateKeyPair.java (77%)
 create mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/EncryptionHandler.java
 create mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java
 create mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannelTransactionManager.java
 rename plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/{protocol => field}/OpcuaField.java (90%)
 rename plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/{protocol => field}/OpcuaPlcFieldHandler.java (88%)
 create mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/optimizer/OpcuaOptimizer.java
 create mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
 create mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubscriptionHandle.java
 delete mode 100644 plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubsriptionHandle.java
 copy plc4j/{integrations/apache-camel/src/test/resources/log4j2.properties => drivers/opcua/src/test/resources/log4j.properties} (97%)
 copy plc4j/{tools/scraper/README.md => drivers/opcua/src/test/resources/logback.xml} (70%)
 delete mode 100644 plc4j/integrations/opcua-server/src/test/java/org/apache/plc4x/java/opcuaserver/UtilsTest.java
 copy plc4j/spi/src/main/java/org/apache/plc4x/java/spi/events/{ConnectEvent.java => DiscoverEvent.java} (96%)
 copy plc4j/spi/src/main/java/org/apache/plc4x/java/spi/events/{ConnectedEvent.java => DiscoveredEvent.java} (74%)
 create mode 100644 plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/xml/XmlHelper.java
 create mode 100644 protocols/opcua/src/main/xslt/opc-common.xsl
 create mode 100644 protocols/opcua/src/main/xslt/opc-manual.xsl
 create mode 100644 protocols/opcua/src/main/xslt/opc-services.xsl
 create mode 100644 protocols/opcua/src/main/xslt/opc-status.xsl
 create mode 100644 protocols/opcua/src/main/xslt/opc-types.xsl

[plc4x] 01/02: PLC4X-307 Add support for custom generator options.

Posted by ld...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ldywicki pushed a commit to branch feature/PLC4X-307
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 43f239e0b2f92388a3e9445f6f0945594ca50b41
Author: Łukasz Dywicki <lu...@code-house.org>
AuthorDate: Thu Jul 29 13:19:38 2021 +0200

    PLC4X-307 Add support for custom generator options.
    
    Ships a new 'package' parameter for Java code generator which lets to specify root package of generated code.
---
 .../protocol/freemarker/FreemarkerLanguageOutput.java      | 11 +++++++----
 .../java/org/apache/plc4x/language/c/CLanguageOutput.java  |  9 ++++++++-
 .../org/apache/plc4x/language/go/GoLanguageOutput.java     |  8 +++++++-
 .../org/apache/plc4x/language/java/JavaLanguageOutput.java | 10 ++++++++--
 .../plc4x/language/java/JavaLanguageTemplateHelper.java    | 14 ++++++++++----
 5 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java
index c5d4122..ff8f076 100644
--- a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java
+++ b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java
@@ -41,7 +41,8 @@ public abstract class FreemarkerLanguageOutput implements LanguageOutput {
     private static final Logger LOGGER = LoggerFactory.getLogger(FreemarkerLanguageOutput.class);
 
     @Override
-    public void generate(File outputDir, String languageName, String protocolName, String outputFlavor, Map<String, TypeDefinition> types)
+    public void generate(File outputDir, String languageName, String protocolName, String outputFlavor, Map<String, TypeDefinition> types,
+        Map<String, String> options)
         throws GenerationException {
 
         // Configure the Freemarker template engine
@@ -70,7 +71,8 @@ public abstract class FreemarkerLanguageOutput implements LanguageOutput {
             typeContext.put("languageName", languageName);
             typeContext.put("protocolName", protocolName);
             typeContext.put("outputFlavor", outputFlavor);
-            typeContext.put("helper", getHelper(null, protocolName, outputFlavor, types));
+            typeContext.put("helper", getHelper(null, protocolName, outputFlavor, types, options));
+            typeContext.putAll(options);
 
             for (Template template : specTemplates) {
                 try {
@@ -90,7 +92,7 @@ public abstract class FreemarkerLanguageOutput implements LanguageOutput {
             typeContext.put("outputFlavor", outputFlavor);
             typeContext.put("typeName", typeEntry.getKey());
             typeContext.put("type", typeEntry.getValue());
-            typeContext.put("helper", getHelper(typeEntry.getValue(), protocolName, outputFlavor, types));
+            typeContext.put("helper", getHelper(typeEntry.getValue(), protocolName, outputFlavor, types, options));
 
             // Depending on the type, get the corresponding list of templates.
             List<Template> templateList;
@@ -179,6 +181,7 @@ public abstract class FreemarkerLanguageOutput implements LanguageOutput {
 
     protected abstract List<Template> getDataIoTemplates(Configuration freemarkerConfiguration) throws IOException;
 
-    protected abstract FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types);
+    protected abstract FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
+        Map<String, String> options);
 
 }
diff --git a/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageOutput.java b/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageOutput.java
index a32c756..e35a8ed 100644
--- a/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageOutput.java
+++ b/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageOutput.java
@@ -20,6 +20,7 @@ package org.apache.plc4x.language.c;
 
 import freemarker.template.Configuration;
 import freemarker.template.Template;
+import java.util.Set;
 import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLanguageOutput;
 import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerLanguageTemplateHelper;
 import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
@@ -38,6 +39,11 @@ public class CLanguageOutput extends FreemarkerLanguageOutput {
     }
 
     @Override
+    public Set<String> supportedOptions() {
+        return Collections.emptySet();
+    }
+
+    @Override
     public List<String> supportedOutputFlavors() {
         return Collections.singletonList("read-write");
     }
@@ -69,7 +75,8 @@ public class CLanguageOutput extends FreemarkerLanguageOutput {
     }
 
     @Override
-    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types) {
+    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
+        Map<String, String> options) {
         return new CLanguageTemplateHelper(thisType, protocolName, flavorName, types);
     }
 
diff --git a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageOutput.java b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageOutput.java
index d578b50..e73aeee 100644
--- a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageOutput.java
+++ b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageOutput.java
@@ -35,6 +35,11 @@ public class GoLanguageOutput extends FreemarkerLanguageOutput {
     }
 
     @Override
+    public Set<String> supportedOptions() {
+        return Collections.emptySet();
+    }
+
+    @Override
     public List<String> supportedOutputFlavors() {
         return Arrays.asList("read-write", "read-only", "passive");
     }
@@ -65,7 +70,8 @@ public class GoLanguageOutput extends FreemarkerLanguageOutput {
     }
 
     @Override
-    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types) {
+    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
+        Map<String, String> options) {
         return new GoLanguageTemplateHelper(thisType, protocolName, flavorName, types);
     }
 
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
index a6d5457..f859dd4 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageOutput.java
@@ -35,6 +35,11 @@ public class JavaLanguageOutput extends FreemarkerLanguageOutput {
     }
 
     @Override
+    public Set<String> supportedOptions() {
+        return Collections.singleton("package");
+    }
+
+    @Override
     public List<String> supportedOutputFlavors() {
         return Arrays.asList("read-write", "read-only", "passive");
     }
@@ -65,8 +70,9 @@ public class JavaLanguageOutput extends FreemarkerLanguageOutput {
     }
 
     @Override
-    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types) {
-        return new JavaLanguageTemplateHelper(thisType, protocolName, flavorName, types);
+    protected FreemarkerLanguageTemplateHelper getHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
+        Map<String, String> options) {
+        return new JavaLanguageTemplateHelper(thisType, protocolName, flavorName, types, options);
     }
 
 }
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index bdddcbf..a5158b3 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -19,6 +19,7 @@
 
 package org.apache.plc4x.language.java;
 
+import java.util.Optional;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.commons.text.WordUtils;
@@ -34,14 +35,19 @@ import java.util.function.Function;
 @SuppressWarnings({"unused", "WeakerAccess"})
 public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelper {
 
-    public JavaLanguageTemplateHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types) {
+    private final Map<String, String> options;
+
+    public JavaLanguageTemplateHelper(TypeDefinition thisType, String protocolName, String flavorName, Map<String, TypeDefinition> types,
+        Map<String, String> options) {
         super(thisType, protocolName, flavorName, types);
+        this.options = options;
     }
 
     public String packageName(String protocolName, String languageName, String languageFlavorName) {
-        return "org.apache.plc4x." + String.join("", languageName.split("\\-")) + "." +
-            String.join("", protocolName.split("\\-")) + "." +
-            String.join("", languageFlavorName.split("\\-"));
+        return Optional.ofNullable(options.get("package")).orElseGet(() ->
+            "org.apache.plc4x." + String.join("", languageName.split("\\-")) + "." +
+                String.join("", protocolName.split("\\-")) + "." +
+                String.join("", languageFlavorName.split("\\-")));
     }
 
     @Override

[plc4x] 02/02: PLC4X-307 Provide configuration options for test framework.

Posted by ld...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ldywicki pushed a commit to branch feature/PLC4X-307
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 8c7672885ee3090ddbef9d782f8579e35da31827
Author: Łukasz Dywicki <lu...@code-house.org>
AuthorDate: Thu Jul 29 15:19:19 2021 +0200

    PLC4X-307 Provide configuration options for test framework.
    
    In case if types for serializer ot driver test suite are in custom package they might be pointed via 'package' option.
    By default above will always fallback to 'org.apache.plc4x' packages to keep backward compatybility.
---
 .../test/driver/internal/DriverTestsuite.java      | 28 ++-----
 .../internal/DriverTestsuiteConfiguration.java     | 14 +++-
 .../handlers/IncomingPlcMessageHandler.java        |  2 +-
 .../handlers/OutgoingPlcMessageHandler.java        |  2 +-
 .../plc4x/test/migration/MessageResolver.java      | 92 +++++++++++++---------
 .../migration/MessageValidatorAndMigrator.java     | 25 +++---
 .../ParserSerializerTestsuiteRunner.java           | 20 +++--
 .../model/ParserSerializerTestsuite.java           |  9 ++-
 .../test/parserserializer/model/Testcase.java      |  1 +
 .../java/org/apache/plc4x/test/xml/XmlHelper.java  | 53 +++++++++++++
 .../main/resources/schemas/driver-testsuite.xsd    | 39 +++++----
 .../schemas/parser-serializer-testsuite.xsd        | 22 ++++++
 12 files changed, 214 insertions(+), 93 deletions(-)

diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/DriverTestsuite.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/DriverTestsuite.java
index bb290e2..8a4a350 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/DriverTestsuite.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/DriverTestsuite.java
@@ -18,6 +18,8 @@ under the License.
 */
 package org.apache.plc4x.test.driver.internal;
 
+import static org.apache.plc4x.test.xml.XmlHelper.*;
+
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.test.dom4j.LocationAwareDocumentFactory;
 import org.apache.plc4x.test.dom4j.LocationAwareElement;
@@ -126,6 +128,8 @@ public class DriverTestsuite {
 
         private final String driverName;
 
+        private final Element optionsElement;
+
         private final Element driverParametersElement;
 
         private final boolean bigEndian;
@@ -140,6 +144,7 @@ public class DriverTestsuite {
             this.protocolName = extractText(testsuiteXml, "protocolName");
             this.outputFlavor = extractText(testsuiteXml, "outputFlavor");
             this.driverName = extractText(testsuiteXml, "driver-name");
+            this.optionsElement = testsuiteXml.element("options");
             this.driverParametersElement = testsuiteXml.element(new QName("driver-parameters"));
             this.bigEndian = !"false".equals(testsuiteXml.attributeValue("bigEndian"));
             this.autoMigrate = autoMigrate;
@@ -152,7 +157,8 @@ public class DriverTestsuite {
                 protocolName,
                 outputFlavor,
                 driverName,
-                parseDriverParameters(driverParametersElement),
+                parseParameters(optionsElement),
+                parseParameters(driverParametersElement),
                 autoMigrate,
                 bigEndian
             );
@@ -163,14 +169,6 @@ public class DriverTestsuite {
             return driverTestsuite;
         }
 
-        private String extractText(Element testsuiteXml, String name) {
-            Element element = testsuiteXml.element(new QName(name));
-            if (element == null) {
-                throw new RuntimeException("Required element " + name + " not present");
-            }
-            return element.getTextTrim();
-        }
-
         private List<Testcase> parseTestCases(DriverTestsuite driverTestsuite) {
             List<Testcase> testcases = testsuiteXml.elements(new QName("testcase")).stream()
                 .map(testcaseXml -> {
@@ -219,18 +217,6 @@ public class DriverTestsuite {
                 .collect(Collectors.toCollection(LinkedList::new));
         }
 
-        private Map<String, String> parseDriverParameters(Element driverParametersElement) {
-            if (driverParametersElement == null) {
-                return Collections.emptyMap();
-            }
-            Map<String, String> driverParameters = new HashMap<>();
-            for (Element parameter : driverParametersElement.elements(new QName("parameter"))) {
-                String parameterName = extractText(parameter, "name");
-                String parameterValue = extractText(parameter, "value");
-                driverParameters.put(parameterName, parameterValue);
-            }
-            return driverParameters;
-        }
     }
 
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/DriverTestsuiteConfiguration.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/DriverTestsuiteConfiguration.java
index 591cc05..7395545 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/DriverTestsuiteConfiguration.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/DriverTestsuiteConfiguration.java
@@ -19,6 +19,8 @@ under the License.
 package org.apache.plc4x.test.driver.internal;
 
 import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class DriverTestsuiteConfiguration {
@@ -27,16 +29,22 @@ public class DriverTestsuiteConfiguration {
     private final String protocolName;
     private final String outputFlavor;
     private final String driverName;
+    private final Map<String, String> options;
     private final Map<String, String> driverParameters;
     private final boolean autoMigrate;
     private final boolean bigEndian;
 
-    public DriverTestsuiteConfiguration(URI suiteUri, String testSuiteName, String protocolName, String outputFlavor, String driverName, Map<String, String> driverParameters, boolean autoMigrate, boolean bigEndian) {
+    public DriverTestsuiteConfiguration(URI suiteUri, String testSuiteName, String protocolName, String outputFlavor,
+        String driverName, Map<String, String> options, Map<String, String> driverParameters, boolean autoMigrate, boolean bigEndian) {
         this.suiteUri = suiteUri;
         this.testSuiteName = testSuiteName;
         this.protocolName = protocolName;
         this.outputFlavor = outputFlavor;
         this.driverName = driverName;
+        this.options = new HashMap<>(options);
+        this.options.put("protocolName", protocolName);
+        this.options.put("outputFlavor", outputFlavor);
+        this.options.put("driverName", driverName);
         // TODO: convert to immutable map
         this.driverParameters = driverParameters;
         this.autoMigrate = autoMigrate;
@@ -63,6 +71,10 @@ public class DriverTestsuiteConfiguration {
         return driverName;
     }
 
+    public Map<String, String> getOptions() {
+        return options;
+    }
+
     public Map<String, String> getDriverParameters() {
         return driverParameters;
     }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/handlers/IncomingPlcMessageHandler.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/handlers/IncomingPlcMessageHandler.java
index 7f4c253..49adc32 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/handlers/IncomingPlcMessageHandler.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/handlers/IncomingPlcMessageHandler.java
@@ -56,7 +56,7 @@ public class IncomingPlcMessageHandler {
     @SuppressWarnings({"rawtypes", "unchecked"})
     public byte[] getBytesFromXml(Element referenceXml, boolean bigEndian) throws DriverTestsuiteException {
         final WriteBufferByteBased writeBuffer = new WriteBufferByteBased(1024, !bigEndian);
-        MessageIO messageIO = MessageResolver.getMessageIO(driverTestsuiteConfiguration.getProtocolName(), driverTestsuiteConfiguration.getOutputFlavor(), referenceXml.getName());
+        MessageIO messageIO = MessageResolver.getMessageIO(driverTestsuiteConfiguration.getOptions(), referenceXml.getName());
         // Get Message and Validate
         Message message = MessageValidatorAndMigrator.validateInboundMessageAndGet(messageIO, referenceXml, parserArguments);
 
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/handlers/OutgoingPlcMessageHandler.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/handlers/OutgoingPlcMessageHandler.java
index e01fbd5..c1eeaa0 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/handlers/OutgoingPlcMessageHandler.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/internal/handlers/OutgoingPlcMessageHandler.java
@@ -47,6 +47,6 @@ public class OutgoingPlcMessageHandler {
         // Prepare a ByteBuf that contains the data which would have been sent to the PLC.
         final byte[] data = ChannelUtil.getOutboundBytes(embeddedChannel);
         // Validate the data actually matches the expected message.
-        MessageValidatorAndMigrator.validateOutboundMessageAndMigrate("TODO: insert testcase name here",driverTestsuiteConfiguration.getProtocolName(), driverTestsuiteConfiguration.getOutputFlavor(), payload, parserArguments, data, bigEndian, driverTestsuiteConfiguration.isAutoMigrate(), driverTestsuiteConfiguration.getSuiteUri());
+        MessageValidatorAndMigrator.validateOutboundMessageAndMigrate("TODO: insert testcase name here", driverTestsuiteConfiguration.getOptions(), payload, parserArguments, data, bigEndian, driverTestsuiteConfiguration.isAutoMigrate(), driverTestsuiteConfiguration.getSuiteUri());
     }
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/migration/MessageResolver.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/migration/MessageResolver.java
index 88a408a..7cf05e0 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/migration/MessageResolver.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/migration/MessageResolver.java
@@ -19,6 +19,7 @@
 
 package org.apache.plc4x.test.migration;
 
+import java.util.Map;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.plc4x.java.spi.generation.MessageIO;
 import org.apache.plc4x.java.spi.generation.ParseException;
@@ -40,43 +41,28 @@ public class MessageResolver {
     private final static Logger LOGGER = LoggerFactory.getLogger(MessageResolver.class);
 
     /**
-     * Returns the messageIO class based on a convention out of {@code protocolName} {@code outputFlavor} and {@code name}.
+     * Returns the messageIO class based on a configured package. convention out of {@code protocolName} {@code outputFlavor} and {@code name}.
      * If this fails its tries a fallback using the deprecated attribute {@code className}
      *
-     * @param protocolName name of the protocol
-     * @param outputFlavor flavor of the output (e.g read-write)
-     * @param name         name of the message
+     * @param options Test framework options
+     * @param name    name of the message
      * @return the found MessageIO
      * @throws DriverTestsuiteException if a MessageIO couldn't be found.
      */
     @SuppressWarnings("rawtypes")
-    public static MessageIO getMessageIO(String protocolName, String outputFlavor, String name) throws DriverTestsuiteException {
+    public static MessageIO getMessageIO(Map<String, String> options, String name) throws DriverTestsuiteException {
         try {
-            return MessageResolver.getMessageIOType(protocolName, outputFlavor, name).newInstance();
+            return MessageResolver.getMessageIOType(options, name).getMessageIo().newInstance();
         } catch (InstantiationException | IllegalAccessException e) {
             throw new DriverTestsuiteException(e);
         }
     }
 
-    public static MessageIO getMessageIOStaticLinked(String protocolName, String outputFlavor, String typeName) throws ParserSerializerTestsuiteException {
-        String ioClassName, ioRootClassName;
-        String classPackage = String.format("org.apache.plc4x.java.%s.%s", protocolName, StringUtils.replace(outputFlavor, "-", ""));
-        try {
-            Package.getPackage(classPackage);
-        } catch (RuntimeException e) {
-            throw new DriverTestsuiteException("fallback to old", e);
-        }
-        ioRootClassName = classPackage + "." + typeName;
-        ioClassName = classPackage + ".io." + typeName + "IO";
-        try {
-            Class.forName(ioRootClassName);
-            Class.forName(ioClassName);
-        } catch (ClassNotFoundException e) {
-            throw new ParserSerializerTestsuiteException(e);
-        }
+    public static MessageIO getMessageIOStaticLinked(Map<String, String> options, String typeName) throws ParserSerializerTestsuiteException {
         try {
-            Class<?> ioRootClass = Class.forName(ioRootClassName);
-            Class<?> ioClass = Class.forName(ioClassName);
+            TypePair typePair = getMessageIOType(options, typeName);
+            Class<?> ioRootClass = typePair.getType();
+            Class<?> ioClass = typePair.getMessageIo();
             Method staticParseMethod = null;
             Method staticSerializeMethod = null;
             final List<Class<?>> parameterTypes = new LinkedList<>();
@@ -149,26 +135,60 @@ public class MessageResolver {
                     }
                 }
             };
-        } catch (ClassNotFoundException e) {
-            throw new ParserSerializerTestsuiteException("Unable to instantiate IO component", e);
+        } catch (DriverTestsuiteException e) {
+            throw new ParserSerializerTestsuiteException("Unable to instantiate IO component", e.getCause());
         }
     }
 
     @SuppressWarnings("unchecked")
-    private static Class<? extends MessageIO<?, ?>> getMessageIOType(String protocolName, String outputFlavor, String typeName) throws DriverTestsuiteException {
+    private static TypePair getMessageIOType(Map<String, String> options, String typeName) throws DriverTestsuiteException {
+        String extraMessage = "";
+        if (options.containsKey("package")) {
+            try {
+                return lookup(options.get("package"), typeName);
+            } catch (ClassNotFoundException e) {
+                extraMessage = "custom package '" + options.get("package") + "' and ";
+            }
+        }
+
+        String protocolName = options.get("protocolName");
+        String outputFlavor = options.get("outputFlavor");
         String classPackage = String.format("org.apache.plc4x.java.%s.%s", protocolName, StringUtils.replace(outputFlavor, "-", ""));
         try {
-            Package.getPackage(classPackage);
-        } catch (RuntimeException e) {
-            throw new DriverTestsuiteException(e);
+            return lookup(classPackage, typeName);
+        } catch (ClassNotFoundException e) {
+            throw new DriverTestsuiteException("Could not find " + typeName + " in " + extraMessage + "standard package '" + classPackage + "'");
         }
-        String ioRootClassName = classPackage + "." + typeName;
-        String ioClassName = classPackage + ".io." + typeName + "IO";
+    }
+
+    private static TypePair lookup(String driverPackage, String typeName) throws ClassNotFoundException {
         try {
-            Class.forName(ioRootClassName);
-            return (Class<? extends MessageIO<?, ?>>) Class.forName(ioClassName);
-        } catch (ClassNotFoundException e) {
-            throw new DriverTestsuiteException(e);
+            Package.getPackage(driverPackage);
+        } catch (RuntimeException e) {
+            throw new DriverTestsuiteException("Invalid or non existent package detected: " + driverPackage, e);
+        }
+        String ioRootClassName = driverPackage + "." + typeName;
+        String ioClassName = driverPackage + ".io." + typeName + "IO";
+        // make sure both type and it's IO are present
+        return new TypePair(
+            Class.forName(ioRootClassName),
+            (Class<? extends MessageIO<?, ?>>) Class.forName(ioClassName)
+        );
+    }
+
+    static class TypePair {
+        private final Class<?> type;
+        private final Class<? extends MessageIO<?, ?>> messageIo;
+
+        TypePair(Class<?> type, Class<? extends MessageIO<?, ?>> messageIo) {
+            this.type = type;
+            this.messageIo = messageIo;
+        }
+        Class<?> getType() {
+            return type;
+        }
+        Class<? extends MessageIO<?, ?>> getMessageIo() {
+            return messageIo;
         }
     }
 
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/migration/MessageValidatorAndMigrator.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/migration/MessageValidatorAndMigrator.java
index f5823de..fbdf0d3 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/migration/MessageValidatorAndMigrator.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/migration/MessageValidatorAndMigrator.java
@@ -19,6 +19,7 @@
 
 package org.apache.plc4x.test.migration;
 
+import java.util.Map;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.plc4x.java.spi.generation.*;
 import org.apache.plc4x.test.driver.exceptions.DriverTestsuiteException;
@@ -43,11 +44,14 @@ public class MessageValidatorAndMigrator {
     private final static Logger LOGGER = LoggerFactory.getLogger(MessageValidatorAndMigrator.class);
 
     /**
-     * Validates a outbound message and migrates it to the expectation if the parameter {@code autoMigrate} is set to true
+     * Validates a outbound message and migrates it to the expectation if the parameter {@code autoMigrate} is set to true.
+     *
+     * Passed options should contain a single 'package' option or 'protocolName' and 'outputFlavor'.
+     * In case if package is not specified then protocol name and output flavor (e.g read-write) are
+     * used to construct lookup package.
      *
      * @param testCaseName    name of the testcase
-     * @param protocolName    name of the protocol
-     * @param outputFlavor    flavor of the output (e.g read-write)
+     * @param options         map with specific test/lookup options.
      * @param referenceXml    the xml we expect the outbound message to be
      * @param parserArguments the parser arguments to create an instance of the message
      * @param data            the bytes of the message
@@ -57,8 +61,8 @@ public class MessageValidatorAndMigrator {
      * @throws DriverTestsuiteException if something goes wrong
      */
     @SuppressWarnings({"rawtypes", "unchecked"})
-    public static void validateOutboundMessageAndMigrate(String testCaseName, String protocolName, String outputFlavor, Element referenceXml, List<String> parserArguments, byte[] data, boolean bigEndian, boolean autoMigrate, URI siteURI) throws DriverTestsuiteException {
-        MessageIO messageIO = MessageResolver.getMessageIO(protocolName, outputFlavor, referenceXml.getName());
+    public static void validateOutboundMessageAndMigrate(String testCaseName, Map<String, String> options, Element referenceXml, List<String> parserArguments, byte[] data, boolean bigEndian, boolean autoMigrate, URI siteURI) throws DriverTestsuiteException {
+        MessageIO messageIO = MessageResolver.getMessageIO(options, referenceXml.getName());
         validateOutboundMessageAndMigrate(testCaseName, messageIO, referenceXml, parserArguments, data, bigEndian, autoMigrate, siteURI);
     }
 
@@ -157,15 +161,16 @@ public class MessageValidatorAndMigrator {
     /**
      * Validates a inbound message and migrates it to the expectation if the parameter {@code autoMigrate} is set to true
      *
-     * @param protocolName    name of the protocol
-     * @param outputFlavor    flavor of the output (e.g read-write)
-     * @param referenceXml    the xml we expect the outbound messag
+     * @param options         Options which contain custom 'package' name or keys 'protocolName' (name of the protocol)
+     *                        and 'outputFlavor' (flavor of the output e.g read-write) which are used to construct
+     *                        class lookup root package.
+     * @param referenceXml    the xml we expect the outbound message
      * @param parserArguments the parser arguments to create an instance of the message
      * @return the message if all went well
      */
     @SuppressWarnings("rawtypes")
-    public static Message validateInboundMessageAndGet(String protocolName, String outputFlavor, Element referenceXml, List<String> parserArguments) {
-        MessageIO messageIO = MessageResolver.getMessageIO(protocolName, outputFlavor, referenceXml.getName());
+    public static Message validateInboundMessageAndGet(Map<String, String> options, Element referenceXml, List<String> parserArguments) {
+        MessageIO messageIO = MessageResolver.getMessageIO(options, referenceXml.getName());
         return validateInboundMessageAndGet(messageIO, referenceXml, parserArguments);
     }
 
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/ParserSerializerTestsuiteRunner.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/ParserSerializerTestsuiteRunner.java
index c7769f2..523c9cf 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/ParserSerializerTestsuiteRunner.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/ParserSerializerTestsuiteRunner.java
@@ -31,6 +31,7 @@ import org.apache.plc4x.test.migration.MessageValidatorAndMigrator;
 import org.apache.plc4x.test.parserserializer.exceptions.ParserSerializerTestsuiteException;
 import org.apache.plc4x.test.parserserializer.model.ParserSerializerTestsuite;
 import org.apache.plc4x.test.parserserializer.model.Testcase;
+import org.apache.plc4x.test.xml.XmlHelper;
 import org.dom4j.Document;
 import org.dom4j.DocumentException;
 import org.dom4j.Element;
@@ -91,9 +92,15 @@ public class ParserSerializerTestsuiteRunner extends XmlTestsuiteLoader {
             Document document = reader.read(testsuiteDocumentXml);
             Element testsuiteXml = document.getRootElement();
             boolean littleEndian = !"true".equals(testsuiteXml.attributeValue("bigEndian"));
-            Element testsuiteName = testsuiteXml.element(new QName("name"));
-            Element protocolName = testsuiteXml.element(new QName("protocolName"));
-            Element outputFlavor = testsuiteXml.element(new QName("outputFlavor"));
+            String testsuiteName = testsuiteXml.element(new QName("name")).getStringValue();
+            String protocolName = testsuiteXml.element(new QName("protocolName")).getStringValue();
+            String outputFlavor = testsuiteXml.element(new QName("outputFlavor")).getStringValue();
+
+            Element optionsElement = testsuiteXml.element(new QName("options"));;
+            Map<String, String> options = new HashMap<>(XmlHelper.parseParameters(optionsElement));
+            options.put("protocolName", protocolName);
+            options.put("outputFlavor", outputFlavor);
+
             List<Element> testcasesXml = testsuiteXml.elements(new QName("testcase"));
             List<Testcase> testcases = new ArrayList<>(testcasesXml.size());
             for (Element testcaseXml : testcasesXml) {
@@ -116,7 +123,7 @@ public class ParserSerializerTestsuiteRunner extends XmlTestsuiteLoader {
                         parserArguments.add(element.getTextTrim());
                     }
                 }
-                Testcase testcase = new Testcase(testsuiteName.getStringValue(), protocolName.getStringValue(), outputFlavor.getStringValue(), name, description, raw, rootType, parserArguments, xmlElement);
+                Testcase testcase = new Testcase(testsuiteName, protocolName, outputFlavor, name, description, raw, rootType, parserArguments, xmlElement);
                 if (testcaseXml instanceof LocationAwareElement) {
                     // pass source location to test
                     testcase.setLocation(((LocationAwareElement) testcaseXml).getLocation());
@@ -124,7 +131,7 @@ public class ParserSerializerTestsuiteRunner extends XmlTestsuiteLoader {
                 testcases.add(testcase);
             }
             LOGGER.info(String.format("Found %d testcases.", testcases.size()));
-            return new ParserSerializerTestsuite(testsuiteName.getTextTrim(), testcases, littleEndian);
+            return new ParserSerializerTestsuite(testsuiteName, testcases, littleEndian, options);
         } catch (DocumentException e) {
             throw new ParserSerializerTestsuiteException("Error parsing testsuite xml", e);
         } catch (DecoderException e) {
@@ -137,8 +144,7 @@ public class ParserSerializerTestsuiteRunner extends XmlTestsuiteLoader {
 
         try {
             MessageIO messageIO = MessageResolver.getMessageIOStaticLinked(
-                testcase.getProtocolName(),
-                testcase.getOutputFlavor(),
+                testSuite.getOptions(),
                 testcase.getXml().elements().get(0).getName()
             );
             Object parsedOutput = messageIO.parse(readBuffer, testcase.getParserArguments().toArray());
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/model/ParserSerializerTestsuite.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/model/ParserSerializerTestsuite.java
index 2178ed1..30dd4a7 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/model/ParserSerializerTestsuite.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/model/ParserSerializerTestsuite.java
@@ -20,17 +20,20 @@
 package org.apache.plc4x.test.parserserializer.model;
 
 import java.util.List;
+import java.util.Map;
 
 public class ParserSerializerTestsuite {
 
     private final String name;
     private final List<Testcase> testcases;
     private final boolean littleEndian;
+    private final Map<String, String> options;
 
-    public ParserSerializerTestsuite(String name, List<Testcase> testcases, boolean littleEndian) {
+    public ParserSerializerTestsuite(String name, List<Testcase> testcases, boolean littleEndian, Map<String, String> options) {
         this.name = name;
         this.testcases = testcases;
         this.littleEndian = littleEndian;
+        this.options = options;
     }
 
     public String getName() {
@@ -45,4 +48,8 @@ public class ParserSerializerTestsuite {
         return littleEndian;
     }
 
+    public Map<String, String> getOptions() {
+        return options;
+    }
+
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/model/Testcase.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/model/Testcase.java
index 8414dd6..156bd5d 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/model/Testcase.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/parserserializer/model/Testcase.java
@@ -19,6 +19,7 @@
 
 package org.apache.plc4x.test.parserserializer.model;
 
+import java.util.Map;
 import org.apache.plc4x.test.model.Location;
 import org.apache.plc4x.test.model.LocationAware;
 import org.dom4j.Element;
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/xml/XmlHelper.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/xml/XmlHelper.java
new file mode 100644
index 0000000..eecc8d2
--- /dev/null
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/xml/XmlHelper.java
@@ -0,0 +1,53 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.test.xml;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.dom4j.Element;
+import org.dom4j.QName;
+
+/**
+ * Common XML processing helpers used in driver and serializer test suites.
+ */
+public class XmlHelper {
+
+    public static String extractText(Element element, String name) {
+        Element child = element.element(new QName(name));
+        if (child == null) {
+            throw new RuntimeException("Required element " + name + " not present");
+        }
+        return child.getTextTrim();
+    }
+
+    // generic parser block for <parameter> tag with name/value tags
+    public static Map<String, String> parseParameters(Element driverParametersElement) {
+        if (driverParametersElement == null) {
+            return Collections.emptyMap();
+        }
+        Map<String, String> driverParameters = new HashMap<>();
+        for (Element parameter : driverParametersElement.elements(new QName("parameter"))) {
+            String parameterName = extractText(parameter, "name");
+            String parameterValue = extractText(parameter, "value");
+            driverParameters.put(parameterName, parameterValue);
+        }
+        return driverParameters;
+    }
+}
diff --git a/plc4j/utils/test-utils/src/main/resources/schemas/driver-testsuite.xsd b/plc4j/utils/test-utils/src/main/resources/schemas/driver-testsuite.xsd
index 1406cc7..b0bd6d0 100644
--- a/plc4j/utils/test-utils/src/main/resources/schemas/driver-testsuite.xsd
+++ b/plc4j/utils/test-utils/src/main/resources/schemas/driver-testsuite.xsd
@@ -18,7 +18,7 @@
   under the License.
   -->
 <xs:schema targetNamespace="https://plc4x.apache.org/schemas/driver-testsuite.xsd"
-           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 
     <xs:element name="driver-testsuite">
         <xs:complexType>
@@ -30,23 +30,19 @@
                 <!-- The outputFlavor of the protocol-->
                 <xs:element name="outputFlavor" type="xs:string"/>
 
+                <xs:element name="options" minOccurs="0" maxOccurs="1" type="parameterList">
+                    <xs:annotation>
+                        <xs:documentation>
+                            List of options which are specific to execution of test or environment.
+                            This might be used ie. to influence test framework lookup strategies.
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:element>
+
                 <!-- The name of the driver we want to test (as it's used in the connection-string) -->
                 <xs:element name="driver-name" type="xs:string"/>
                 <!-- Additional parameters passed to the driver in the connection-string -->
-                <xs:element name="driver-parameters" minOccurs="0" maxOccurs="1">
-                    <xs:complexType>
-                        <xs:sequence minOccurs="1" maxOccurs="unbounded">
-                            <xs:element name="parameter">
-                                <xs:complexType>
-                                    <xs:sequence>
-                                        <xs:element name="name" type="xs:string"/>
-                                        <xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="1"/>
-                                    </xs:sequence>
-                                </xs:complexType>
-                            </xs:element>
-                        </xs:sequence>
-                    </xs:complexType>
-                </xs:element>
+                <xs:element name="driver-parameters" minOccurs="0" maxOccurs="1" type="parameterList" />
 
                 <!-- Interaction which is performed to initiate the driver connection -->
                 <xs:element name="setup" minOccurs="0" maxOccurs="1">
@@ -133,4 +129,17 @@
         </xs:simpleContent>
     </xs:complexType>
 
+    <xs:complexType name="parameterList">
+        <xs:sequence minOccurs="1" maxOccurs="unbounded">
+            <xs:element name="parameter">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="name" type="xs:string" />
+                        <xs:element name="value" type="xs:string" minOccurs="0" />
+                    </xs:sequence>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
 </xs:schema>
\ No newline at end of file
diff --git a/plc4j/utils/test-utils/src/main/resources/schemas/parser-serializer-testsuite.xsd b/plc4j/utils/test-utils/src/main/resources/schemas/parser-serializer-testsuite.xsd
index 8a906d7..a1b17c1 100644
--- a/plc4j/utils/test-utils/src/main/resources/schemas/parser-serializer-testsuite.xsd
+++ b/plc4j/utils/test-utils/src/main/resources/schemas/parser-serializer-testsuite.xsd
@@ -29,6 +29,15 @@
                 <xs:element name="protocolName" type="xs:string"/>
                 <!-- The outputFlavor of the protocol-->
                 <xs:element name="outputFlavor" type="xs:string"/>
+
+                <xs:element name="options" minOccurs="0" maxOccurs="1" type="parameterList">
+                    <xs:annotation>
+                        <xs:documentation>
+                            List of options which are specific to execution of test or environment.
+                            This might be used ie. to influence test framework lookup strategies.
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:element>
                 <!--
                     Each testcase is a set of hexadecimal input and expected output.
                     A test will parse the binary input and compare the parsed result
@@ -65,4 +74,17 @@
         </xs:complexType>
     </xs:element>
 
+    <xs:complexType name="parameterList">
+        <xs:sequence minOccurs="1" maxOccurs="unbounded">
+            <xs:element name="parameter">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="name" type="xs:string" />
+                        <xs:element name="value" type="xs:string" minOccurs="0" />
+                    </xs:sequence>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
 </xs:schema>
\ No newline at end of file