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

[plc4x] 03/05: - Worked on implementing the basics of Discovery in API and SPI - Refactored the driver.getDriver function to operate on the driver-code and added a second getDriverForUrl

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

cdutz pushed a commit to branch feature/profinet-chris
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit ad9580309f592419743deb619026bdec11ca271a
Author: cdutz <ch...@c-ware.de>
AuthorDate: Fri Jul 2 10:16:33 2021 +0200

    - Worked on implementing the basics of Discovery in API and SPI
    - Refactored the driver.getDriver function to operate on the driver-code and added a second getDriverForUrl
---
 .../org/apache/plc4x/java/PlcDriverManager.java    |  36 ++++--
 .../java/org/apache/plc4x/java/api/PlcDriver.java  |  14 +++
 .../plc4x/java/api/messages/PlcDiscoveryItem.java  |  38 ++++++
 .../plc4x/java/api/metadata/PlcDriverMetadata.java |  31 +++++
 .../apache/plc4x/java/profinet/ProfinetDriver.java |  29 ++++-
 plc4j/examples/hello-discovery/pom.xml             |  79 ++++++++++++
 .../java/examples/hellodiscovery/CliOptions.java   |  73 +++++++++++
 .../examples/hellodiscovery/HelloDiscovery.java    |  70 +++++++++++
 .../hello-discovery/src/main/resources/logback.xml |  36 ++++++
 plc4j/examples/pom.xml                             |   8 ++
 .../java/org/apache/plc4x/kafka/config/Sink.java   |   2 +-
 .../java/org/apache/plc4x/kafka/config/Source.java |   2 +-
 .../opcuaserver/backend/Plc4xCommunication.java    |   2 +-
 .../java/spi/messages/DefaultPlcDiscoveryItem.java | 133 +++++++++++++++++++++
 .../spi/messages/DefaultPlcDiscoveryRequest.java   |  67 +++++++++++
 .../spi/messages/DefaultPlcDiscoveryResponse.java  |  68 +++++++++++
 .../plc4x/java/spi/messages/PlcDiscoverer.java     |  39 ++++++
 .../triggerhandler/TriggerConfiguration.java       |   2 +-
 18 files changed, 715 insertions(+), 14 deletions(-)

diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java b/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java
index 7b3652c..af4ee11 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/PlcDriverManager.java
@@ -31,6 +31,7 @@ import java.net.URISyntaxException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.ServiceLoader;
+import java.util.Set;
 
 public class PlcDriverManager {
 
@@ -91,21 +92,38 @@ public class PlcDriverManager {
     }
 
     /**
-     * Returns suitble driver for protocol or throws an Exception.
-     * @param url Uri to use
+     * Returns the codes of all of the drivers which are currently registered at the PlcDriverManager
+     * @return Set of driver codes for all drivers registered
+     */
+    public Set<String> listDrivers() {
+        return driverMap.keySet();
+    }
+
+    /**
+     * Returns suitable driver for protocol or throws an Exception.
+     * @param protocolCode protocol code identifying the driver
      * @return Driver instance for the given protocol
      * @throws PlcConnectionException If no Suitable Driver can be found
      */
-    @Experimental
-    public PlcDriver getDriver(String url) throws PlcConnectionException {
+    public PlcDriver getDriver(String protocolCode) throws PlcConnectionException {
+        PlcDriver driver = driverMap.get(protocolCode);
+        if (driver == null) {
+            throw new PlcConnectionException("Unable to find driver for protocol '" + protocolCode + "'");
+        }
+        return driver;
+    }
+
+    /**
+     * Returns suitable driver for a given plc4x connection url or throws an Exception.
+     * @param url Uri to use
+     * @return Driver instance for the given url
+     * @throws PlcConnectionException If no Suitable Driver can be found
+     */
+    public PlcDriver getDriverForUrl(String url) throws PlcConnectionException {
         try {
             URI connectionUri = new URI(url);
             String protocol = connectionUri.getScheme();
-            PlcDriver driver = driverMap.get(protocol);
-            if (driver == null) {
-                throw new PlcConnectionException("Unable to find driver for protocol '" + protocol + "'");
-            }
-            return driver;
+            return getDriver(protocol);
         } catch (URISyntaxException e) {
             throw new PlcConnectionException("Invalid plc4j connection string '" + url + "'", e);
         }
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcDriver.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcDriver.java
index bc8c0b3..6d99d17 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcDriver.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/PlcDriver.java
@@ -23,6 +23,8 @@ import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.exceptions.PlcNotImplementedException;
 import org.apache.plc4x.java.api.exceptions.PlcUnsupportedOperationException;
 import org.apache.plc4x.java.api.messages.PlcDiscoveryRequest;
+import org.apache.plc4x.java.api.metadata.PlcConnectionMetadata;
+import org.apache.plc4x.java.api.metadata.PlcDriverMetadata;
 import org.apache.plc4x.java.api.model.PlcField;
 
 /**
@@ -45,6 +47,18 @@ public interface PlcDriver {
     String getProtocolName();
 
     /**
+     * Provides driver metadata.
+     */
+    default PlcDriverMetadata getMetadata() {
+        return new PlcDriverMetadata() {
+            @Override
+            public boolean canDiscover() {
+                return false;
+            }
+        };
+    }
+
+    /**
      * Connects to a PLC using the given plc connection string.
      *
      * @param url plc connection string.
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcDiscoveryItem.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcDiscoveryItem.java
new file mode 100644
index 0000000..b0692e0
--- /dev/null
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcDiscoveryItem.java
@@ -0,0 +1,38 @@
+package org.apache.plc4x.java.api.messages;
+
+import java.net.URL;
+import java.util.Map;
+
+public interface PlcDiscoveryItem {
+
+    /**
+     * @return returns the protocol-code part of the url (s7, modbus, ads, ...)
+     */
+    String getProtocolCode();
+
+    /**
+     * @return returns the transport part of the url (tcp, udp, serial, raw, ...)
+     */
+    String getTransportCode();
+
+    /**
+     * @return returns the part of the url, the given transport needs in order to connect (plc.mycompany.de, 192.168.42.23, /dev/serial, COM1)
+     */
+    URL getTransportUrl();
+
+    /**
+     * @return returns a map of all configuration options (usually encoded after the transport url's "?" character (rack=1&slot=1, little-endian=true, ...)
+     */
+    Map<String, String> getOptions();
+
+    /**
+     * @return returns something I bet made sense some time, but I have forgotten why I added it to plc4go ;-)
+     */
+    String getName();
+
+    /**
+     * @return returns a plc4x connection string that can be used in any PLC4X driver to connect to the given device (Generally just a concatenation of the other parts of this object)
+     */
+    String getConnectionUrl();
+
+}
diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/metadata/PlcDriverMetadata.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/metadata/PlcDriverMetadata.java
new file mode 100644
index 0000000..63b6f4e
--- /dev/null
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/metadata/PlcDriverMetadata.java
@@ -0,0 +1,31 @@
+/*
+ * 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.java.api.metadata;
+
+/**
+ * Information about driver capabilities.
+ */
+public interface PlcDriverMetadata {
+
+    /**
+     * Indicates that the driver supports discovery.
+     */
+    boolean canDiscover();
+
+}
diff --git a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
index b47d1bd..055b147 100644
--- a/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
+++ b/plc4j/drivers/profinet/src/main/java/org/apache/plc4x/java/profinet/ProfinetDriver.java
@@ -19,6 +19,9 @@ under the License.
 package org.apache.plc4x.java.profinet;
 
 import io.netty.buffer.ByteBuf;
+import org.apache.plc4x.java.api.messages.PlcDiscoveryRequest;
+import org.apache.plc4x.java.api.messages.PlcDiscoveryResponse;
+import org.apache.plc4x.java.api.metadata.PlcDriverMetadata;
 import org.apache.plc4x.java.profinet.config.ProfinetConfiguration;
 import org.apache.plc4x.java.profinet.field.ProfinetField;
 import org.apache.plc4x.java.profinet.field.ProfinetFieldHandler;
@@ -27,6 +30,9 @@ import org.apache.plc4x.java.profinet.readwrite.EthernetFrame;
 import org.apache.plc4x.java.profinet.readwrite.io.EthernetFrameIO;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
+import org.apache.plc4x.java.spi.messages.DefaultPlcDiscoveryRequest;
+import org.apache.plc4x.java.spi.messages.DefaultPlcWriteRequest;
+import org.apache.plc4x.java.spi.messages.PlcDiscoverer;
 import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.configuration.Configuration;
@@ -34,9 +40,10 @@ import org.apache.plc4x.java.spi.connection.SingleProtocolStackConfigurer;
 import org.apache.plc4x.java.spi.optimizer.BaseOptimizer;
 import org.apache.plc4x.java.spi.optimizer.SingleFieldOptimizer;
 
+import java.util.concurrent.CompletableFuture;
 import java.util.function.ToIntFunction;
 
-public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> {
+public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> implements PlcDiscoverer {
 
     @Override
     public String getProtocolCode() {
@@ -49,6 +56,21 @@ public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> {
     }
 
     @Override
+    public PlcDriverMetadata getMetadata() {
+        return new PlcDriverMetadata() {
+            @Override
+            public boolean canDiscover() {
+                return true;
+            }
+        };
+    }
+
+    @Override
+    public PlcDiscoveryRequest.Builder discoveryRequestBuilder() {
+        return new DefaultPlcDiscoveryRequest.Builder(this);
+    }
+
+    @Override
     protected Class<? extends Configuration> getConfigurationType() {
         return ProfinetConfiguration.class;
     }
@@ -127,4 +149,9 @@ public class ProfinetDriver extends GeneratedDriverBase<EthernetFrame> {
         return ProfinetField.of(query);
     }
 
+    @Override
+    public CompletableFuture<PlcDiscoveryResponse> discover(PlcDiscoveryRequest discoveryRequest) {
+        return null;
+    }
+
 }
diff --git a/plc4j/examples/hello-discovery/pom.xml b/plc4j/examples/hello-discovery/pom.xml
new file mode 100644
index 0000000..18e4dd0
--- /dev/null
+++ b/plc4j/examples/hello-discovery/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+  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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x.examples</groupId>
+    <artifactId>plc4j-examples</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>plc4j-hello-discovery</artifactId>
+  <name>PLC4J: Examples: Hello Discovery</name>
+  <description>Hello world application for PLC4X demonstrating the Discovery API.</description>
+
+  <properties>
+    <app.main.class>org.apache.plc4x.java.examples.hellodiscovery.HelloDiscovery</app.main.class>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-api</artifactId>
+      <version>0.9.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-cli</groupId>
+      <artifactId>commons-cli</artifactId>
+      <version>1.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>log4j-over-slf4j</artifactId>
+      <version>1.7.25</version>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <configuration>
+          <usedDependencies combine.children="append">
+            <usedDependency>org.slf4j:log4j-over-slf4j</usedDependency>
+          </usedDependencies>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
\ No newline at end of file
diff --git a/plc4j/examples/hello-discovery/src/main/java/org/apache/plc4x/java/examples/hellodiscovery/CliOptions.java b/plc4j/examples/hello-discovery/src/main/java/org/apache/plc4x/java/examples/hellodiscovery/CliOptions.java
new file mode 100644
index 0000000..78e20ca
--- /dev/null
+++ b/plc4j/examples/hello-discovery/src/main/java/org/apache/plc4x/java/examples/hellodiscovery/CliOptions.java
@@ -0,0 +1,73 @@
+/*
+ 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.java.examples.hellodiscovery;
+
+import org.apache.commons.cli.*;
+
+public class CliOptions {
+
+    private static Options options;
+
+    public static CliOptions fromArgs(String[] args) {
+        options = new Options();
+        // Required arguments
+/*
+        options.addOption(
+            Option.builder()
+                .type(String.class)
+                .longOpt("connection-string")
+                .hasArg()
+                .desc("Connection String")
+                .required()
+                .build());
+        options.addOption(
+            Option.builder()
+                .type(String.class)
+                .longOpt("field-addresses")
+                .hasArgs()
+                .desc("Field Addresses (Space separated).")
+                .required()
+                .build());
+*/
+
+        CommandLineParser parser = new DefaultParser();
+        CommandLine commandLine;
+        try {
+            commandLine = parser.parse(options, args);
+
+/*            String connectionString = commandLine.getOptionValue("connection-string");
+            String[] fieldAddress = commandLine.getOptionValues("field-addresses");
+*/
+            return new CliOptions(/*connectionString, fieldAddress*/);
+        } catch (ParseException e) {
+            System.err.println(e.getMessage());
+            return null;
+        }
+    }
+
+    public static void printHelp() {
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printHelp("HelloPlc4x", options);
+    }
+
+    public CliOptions() {
+    }
+
+}
diff --git a/plc4j/examples/hello-discovery/src/main/java/org/apache/plc4x/java/examples/hellodiscovery/HelloDiscovery.java b/plc4j/examples/hello-discovery/src/main/java/org/apache/plc4x/java/examples/hellodiscovery/HelloDiscovery.java
new file mode 100644
index 0000000..c2cfdb4
--- /dev/null
+++ b/plc4j/examples/hello-discovery/src/main/java/org/apache/plc4x/java/examples/hellodiscovery/HelloDiscovery.java
@@ -0,0 +1,70 @@
+/*
+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.java.examples.hellodiscovery;
+
+import org.apache.plc4x.java.PlcDriverManager;
+import org.apache.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.PlcDriver;
+import org.apache.plc4x.java.api.messages.PlcDiscoveryRequest;
+import org.apache.plc4x.java.api.messages.PlcDiscoveryResponse;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+public class HelloDiscovery {
+
+    private static final Logger logger = LoggerFactory.getLogger(HelloDiscovery.class);
+
+    /**
+     * Example code do demonstrate using PLC4X's discovery API.
+     *
+     * @param args ignored.
+     */
+    public static void main(String[] args) throws Exception {
+        CliOptions options = CliOptions.fromArgs(args);
+        if (options == null) {
+            CliOptions.printHelp();
+            // Could not parse.
+            System.exit(1);
+        }
+
+        PlcDriverManager plcDriverManager = new PlcDriverManager();
+        Set<String> driverCodes = plcDriverManager.listDrivers();
+        for (String driverCode : driverCodes) {
+            logger.info(String.format("Executing Discovery for Driver: %s", driverCode));
+            PlcDriver driver = plcDriverManager.getDriver(driverCode);
+
+            // Check if this driver supports discovery.
+            if(driver.getMetadata().canDiscover()) {
+                PlcDiscoveryRequest discoveryRequest = driver.discoveryRequestBuilder().build();
+                discoveryRequest.execute();
+            } else {
+                logger.info("This driver doesn't support discovery");
+            }
+        }
+
+    }
+
+}
diff --git a/plc4j/examples/hello-discovery/src/main/resources/logback.xml b/plc4j/examples/hello-discovery/src/main/resources/logback.xml
new file mode 100644
index 0000000..a8ddebb
--- /dev/null
+++ b/plc4j/examples/hello-discovery/src/main/resources/logback.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+  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.
+
+-->
+<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <!-- encoders are assigned the type
+         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <root level="trace">
+    <appender-ref ref="STDOUT" />
+  </root>
+
+</configuration>
\ No newline at end of file
diff --git a/plc4j/examples/pom.xml b/plc4j/examples/pom.xml
index 5a974cb..e9a8145 100644
--- a/plc4j/examples/pom.xml
+++ b/plc4j/examples/pom.xml
@@ -43,6 +43,7 @@
     <module>hello-cloud-azure</module>
     <module>hello-cloud-google</module>
     <module>hello-connectivity-kafka</module>
+    <module>hello-discovery</module>
     <module>hello-connectivity-mqtt</module>
     <module>hello-influx-data-collection</module>
     <module>hello-integration-edgent</module>
@@ -101,6 +102,7 @@
             <usedDependency>org.apache.plc4x:plc4j-driver-knxnetip</usedDependency>
             <usedDependency>org.apache.plc4x:plc4j-driver-modbus</usedDependency>
             <usedDependency>org.apache.plc4x:plc4j-driver-opcua</usedDependency>
+            <usedDependency>org.apache.plc4x:plc4j-driver-profinet</usedDependency>
             <usedDependency>org.apache.plc4x:plc4j-driver-s7</usedDependency>
             <usedDependency>org.apache.plc4x:plc4j-driver-simulated</usedDependency>
           </usedDependencies>
@@ -191,6 +193,12 @@
     </dependency>
     <dependency>
       <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-driver-profinet</artifactId>
+      <version>0.9.0-SNAPSHOT</version>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
       <artifactId>plc4j-driver-s7</artifactId>
       <version>0.9.0-SNAPSHOT</version>
       <scope>runtime</scope>
diff --git a/plc4j/integrations/apache-kafka/src/main/java/org/apache/plc4x/kafka/config/Sink.java b/plc4j/integrations/apache-kafka/src/main/java/org/apache/plc4x/kafka/config/Sink.java
index 72edcc4..60a1abd 100644
--- a/plc4j/integrations/apache-kafka/src/main/java/org/apache/plc4x/kafka/config/Sink.java
+++ b/plc4j/integrations/apache-kafka/src/main/java/org/apache/plc4x/kafka/config/Sink.java
@@ -58,7 +58,7 @@ public class Sink extends AbstractConfig{
                 String.format("Connection string shouldn't be null for source %s ", this.name));
         }
         try {
-            new PlcDriverManager().getDriver(connectionString);
+            new PlcDriverManager().getDriverForUrl(connectionString);
         } catch (Exception e) {
             throw new ConfigException(
                 String.format("Connection String format is incorrect %s ", Constants.SINKS_CONFIG + "." + this.name + "." + Constants.CONNECTION_STRING_CONFIG + "=" + connectionString));
diff --git a/plc4j/integrations/apache-kafka/src/main/java/org/apache/plc4x/kafka/config/Source.java b/plc4j/integrations/apache-kafka/src/main/java/org/apache/plc4x/kafka/config/Source.java
index 42dc14a..aab9b3f 100644
--- a/plc4j/integrations/apache-kafka/src/main/java/org/apache/plc4x/kafka/config/Source.java
+++ b/plc4j/integrations/apache-kafka/src/main/java/org/apache/plc4x/kafka/config/Source.java
@@ -73,7 +73,7 @@ public class Source extends AbstractConfig{
                 String.format("Connection string shouldn't be null for source %s ", this.name));
         }
         try {
-            new PlcDriverManager().getDriver(connectionString);
+            new PlcDriverManager().getDriverForUrl(connectionString);
         } catch (Exception e) {
             throw new ConfigException(
                 String.format("Connection String format is incorrect %s ", SOURCES_CONFIG + "." + this.name + "." + CONNECTION_STRING_CONFIG + "=" + connectionString));
diff --git a/plc4j/integrations/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java b/plc4j/integrations/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java
index 6740d45..14814f2 100644
--- a/plc4j/integrations/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java
+++ b/plc4j/integrations/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java
@@ -94,7 +94,7 @@ public class Plc4xCommunication extends AbstractLifecycle {
     }
 
     public PlcField getField(String tag, String connectionString) throws PlcConnectionException {
-        return driverManager.getDriver(connectionString).prepareField(tag);
+        return driverManager.getDriverForUrl(connectionString).prepareField(tag);
     }
 
     public void addField(DataItem item) {
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcDiscoveryItem.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcDiscoveryItem.java
new file mode 100644
index 0000000..1516793
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcDiscoveryItem.java
@@ -0,0 +1,133 @@
+/*
+ * 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.java.spi.messages;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import org.apache.plc4x.java.api.messages.PlcDiscoveryItem;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.net.URL;
+import java.util.Map;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
+public class DefaultPlcDiscoveryItem implements PlcDiscoveryItem, XmlSerializable {
+
+    private final String protocolCode;
+    private final String transportCode;
+    private final URL transportUrl;
+    private final Map<String, String> options;
+    private final String name;
+
+    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
+    public DefaultPlcDiscoveryItem(@JsonProperty("protocolCode") String protocolCode,
+                                   @JsonProperty("transportCode") String transportCode,
+                                   @JsonProperty("transportUrl") URL transportUrl,
+                                   @JsonProperty("options") Map<String, String> options,
+                                   @JsonProperty("name") String name) {
+        this.protocolCode = protocolCode;
+        this.transportCode = transportCode;
+        this.transportUrl = transportUrl;
+        this.options = options;
+        this.name = name;
+    }
+
+    @Override
+    public String getProtocolCode() {
+        return protocolCode;
+    }
+
+    @Override
+    public String getTransportCode() {
+        return transportCode;
+    }
+
+    @Override
+    public URL getTransportUrl() {
+        return transportUrl;
+    }
+
+    @Override
+    public Map<String, String> getOptions() {
+        return options;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getConnectionUrl() {
+        StringBuilder sb = new StringBuilder(String.format("%s:%s://%s",
+            protocolCode, transportCode, transportUrl.toString()));
+        if(options != null && !options.isEmpty()) {
+            boolean first = true;
+            for (Map.Entry<String, String> optionEntry : options.entrySet()) {
+                if(first) {
+                    first = false;
+                } else {
+                    sb.append("&");
+                }
+                sb.append(optionEntry.getKey()).append("=").append(optionEntry.getValue());
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement("PlcDiscoveryItem");
+
+        Element protocolCodeElement = doc.createElement("protocolCode");
+        protocolCodeElement.appendChild(doc.createTextNode(protocolCode));
+        messageElement.appendChild(protocolCodeElement);
+
+        Element transportCodeElement = doc.createElement("transportCode");
+        transportCodeElement.appendChild(doc.createTextNode(transportCode));
+        messageElement.appendChild(transportCodeElement);
+
+        Element transportUrlElement = doc.createElement("transportUrl");
+        transportUrlElement.appendChild(doc.createTextNode(transportUrl.toString()));
+        messageElement.appendChild(transportUrlElement);
+
+        if(options != null && !options.isEmpty()) {
+            Element optionsElement = doc.createElement("options");
+            for (Map.Entry<String, String> optionEntry : options.entrySet()) {
+                Element optionElement = doc.createElement(optionEntry.getKey());
+                optionElement.appendChild(doc.createTextNode(optionEntry.getValue()));
+                optionsElement.appendChild(optionElement);
+            }
+            messageElement.appendChild(optionsElement);
+        }
+
+        if(name != null && !name.isEmpty()) {
+            Element nameElement = doc.createElement("name");
+            nameElement.appendChild(doc.createTextNode(name));
+            messageElement.appendChild(nameElement);
+        }
+
+        parent.appendChild(messageElement);
+    }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcDiscoveryRequest.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcDiscoveryRequest.java
new file mode 100644
index 0000000..fa97866
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcDiscoveryRequest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.java.spi.messages;
+
+import com.fasterxml.jackson.annotation.*;
+import org.apache.plc4x.java.api.messages.*;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.concurrent.CompletableFuture;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
+public class DefaultPlcDiscoveryRequest implements PlcDiscoveryRequest, XmlSerializable {
+
+    private final PlcDiscoverer discoverer;
+
+    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
+    public DefaultPlcDiscoveryRequest(@JsonProperty("discoverer") PlcDiscoverer discoverer) {
+        this.discoverer = discoverer;
+    }
+
+    @Override
+    public CompletableFuture<? extends PlcDiscoveryResponse> execute() {
+        return discoverer.discover(this);
+    }
+
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement("PlcDiscoveryRequest");
+        parent.appendChild(messageElement);
+        // TODO: Implement
+    }
+
+    public static class Builder implements PlcDiscoveryRequest.Builder {
+
+        private final PlcDiscoverer discoverer;
+
+        public Builder(PlcDiscoverer discoverer) {
+            this.discoverer = discoverer;
+        }
+
+        @Override
+        public PlcDiscoveryRequest build() {
+            return new DefaultPlcDiscoveryRequest(discoverer);
+        }
+
+    }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcDiscoveryResponse.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcDiscoveryResponse.java
new file mode 100644
index 0000000..8b0a59e
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/DefaultPlcDiscoveryResponse.java
@@ -0,0 +1,68 @@
+/*
+ * 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.java.spi.messages;
+
+import com.fasterxml.jackson.annotation.*;
+import org.apache.plc4x.java.api.messages.*;
+import org.apache.plc4x.java.spi.utils.XmlSerializable;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.util.*;
+
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "className")
+public class DefaultPlcDiscoveryResponse implements PlcDiscoveryResponse, XmlSerializable {
+
+    private final PlcDiscoveryRequest request;
+    private final List<PlcDiscoveryItem> values;
+
+    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
+    public DefaultPlcDiscoveryResponse(@JsonProperty("request") PlcDiscoveryRequest request,
+                                       @JsonProperty("values") List<PlcDiscoveryItem> values) {
+        this.request = request;
+        this.values = values;
+    }
+
+    @Override
+    public PlcDiscoveryRequest getRequest() {
+        return request;
+    }
+
+    public List<PlcDiscoveryItem> getValues() {
+        return values;
+    }
+
+    @Override
+    public void xmlSerialize(Element parent) {
+        Document doc = parent.getOwnerDocument();
+        Element messageElement = doc.createElement("PlcDiscoveryResponse");
+        if(request instanceof XmlSerializable) {
+            ((XmlSerializable) request).xmlSerialize(messageElement);
+        }
+        Element valuesElement = doc.createElement("values");
+        messageElement.appendChild(valuesElement);
+        for (PlcDiscoveryItem value : values) {
+            if(value instanceof XmlSerializable) {
+                ((XmlSerializable) value).xmlSerialize(messageElement);
+            }
+        }
+        parent.appendChild(messageElement);
+    }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcDiscoverer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcDiscoverer.java
new file mode 100644
index 0000000..28ace34
--- /dev/null
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/messages/PlcDiscoverer.java
@@ -0,0 +1,39 @@
+/*
+ * 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.java.spi.messages;
+
+import org.apache.plc4x.java.api.messages.PlcDiscoveryRequest;
+import org.apache.plc4x.java.api.messages.PlcDiscoveryResponse;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Interface implemented by all PlcConnections that are able to read from remote resources.
+ */
+public interface PlcDiscoverer {
+
+    /**
+     * Executes a discovery operation
+     *
+     * @param discoveryRequest object describing the parameters of the discovery.
+     * @return a {@link CompletableFuture} giving async access to the returned value.
+     */
+    CompletableFuture<PlcDiscoveryResponse> discover(PlcDiscoveryRequest discoveryRequest);
+
+}
diff --git a/plc4j/tools/scraper/src/main/java/org/apache/plc4x/java/scraper/triggeredscraper/triggerhandler/TriggerConfiguration.java b/plc4j/tools/scraper/src/main/java/org/apache/plc4x/java/scraper/triggeredscraper/triggerhandler/TriggerConfiguration.java
index 8035270..7291613 100644
--- a/plc4j/tools/scraper/src/main/java/org/apache/plc4x/java/scraper/triggeredscraper/triggerhandler/TriggerConfiguration.java
+++ b/plc4j/tools/scraper/src/main/java/org/apache/plc4x/java/scraper/triggeredscraper/triggerhandler/TriggerConfiguration.java
@@ -561,7 +561,7 @@ public class TriggerConfiguration{
         //So I need to create the field using the connection string here
         private PlcField prepareField(String fieldQuery) throws PlcConnectionException {
             PlcDriverManager driverManager = new PlcDriverManager();
-            PlcDriver driver = driverManager.getDriver(plcConnectionString);
+            PlcDriver driver = driverManager.getDriverForUrl(plcConnectionString);
             return driver.prepareField(fieldQuery);
         }