Repository: apache/streampipes
Pull request #2945 (2024-06-18 15:57:00)

fix: update broken links
<!--
  ~ 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.
  ~
  -->
  
  <!--
Thanks for contributing! Here are some tips you can follow to help us incorporate your contribution quickly and easily:
1. If this is your first time, please read our contributor guidelines:
    - https://streampipes.apache.org/getinvolved.html
    - https://cwiki.apache.org/confluence/display/STREAMPIPES/Getting+Started
2. Make sure the PR title is formatted like: `[#<GitHub issue id>] PR title ...`
3. If the PR is unfinished, add '[WIP]' in your PR title, e.g., `[WIP][#<GitHub issue id>] PR title ...`.
4. Please write your PR title to summarize what this PR proposes/fixes.
5. Link the PR to the corresponding GitHub issue (if present) in the `Development` section in the right menu bar. 
6. Be sure to keep the PR description updated to reflect all changes.
7. If possible, provide a concise example to reproduce the issue for a faster review.
8. Make sure tests pass via `mvn clean install`.
9. (Optional) If the contribution is large, please file an Apache ICLA
    - http://apache.org/licenses/icla.pdf
-->

### Purpose
<!--
Please clarify what changes you are proposing and describe how those changes will address the issue.
Furthermore, describe potential consequences the changes might have.
-->
Inspired by the recent pull request, I wrote a simple python script dedicated to identifying broken links in project documentation. I also completed attempts to fix the broken links.

In addition, I noticed that there are extra spaces at the end of some lines. Maybe we can add markdown lint CI to standardize and improve quality? If that feature is acceptable, I'd be willing to do that part and use it to familiarize with the docs.

### Remarks
<!--
Is there anything left we need to pay attention on?
Are there some references that might be important? E.g. links to Confluence, or discussions
on the mailing list or GitHub.
-->
PR introduces (a) breaking change(s): <yes/no>
no
PR introduces (a) deprecation(s): <yes/no>
no


Patch:
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 48fdf4a6c5..52ffa7f9a8 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -15,16 +15,16 @@
   ~ limitations under the License.
   ~
   -->
-  
+
   <!--
 Thanks for contributing! Here are some tips you can follow to help us incorporate your contribution quickly and easily:
 1. If this is your first time, please read our contributor guidelines:
-    - https://streampipes.apache.org/getinvolved.html
+    - https://streampipes.apache.org/community/get-involved/
     - https://cwiki.apache.org/confluence/display/STREAMPIPES/Getting+Started
 2. Make sure the PR title is formatted like: `[#<GitHub issue id>] PR title ...`
 3. If the PR is unfinished, add '[WIP]' in your PR title, e.g., `[WIP][#<GitHub issue id>] PR title ...`.
 4. Please write your PR title to summarize what this PR proposes/fixes.
-5. Link the PR to the corresponding GitHub issue (if present) in the `Development` section in the right menu bar. 
+5. Link the PR to the corresponding GitHub issue (if present) in the `Development` section in the right menu bar.
 6. Be sure to keep the PR description updated to reflect all changes.
 7. If possible, provide a concise example to reproduce the issue for a faster review.
 8. Make sure tests pass via `mvn clean install`.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6d7d95f95a..fe34d5a5cc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -18,7 +18,7 @@
 
 ## Contributing to StreamPipes
 
-*Before opening a pull request*, review the [Get Involved](https://streampipes.apache.org/getinvolved.html) page.
+*Before opening a pull request*, review the [Get Involved](https://streampipes.apache.org/community/get-involved/) page.
 It lists information that is required for contributing to StreamPipes.
 
 When you contribute code, you affirm that the contribution is your original work and that you
diff --git a/README.md b/README.md
index 66fa337b79..6e86241c41 100644
--- a/README.md
+++ b/README.md
@@ -32,14 +32,14 @@
 
 <h1 align="center">
   <br>
-   <img src="https://streampipes.apache.org/img/sp-logo-color.png" 
+   <img src="https://streampipes.apache.org/img/sp-logo-color.png"
    alt="StreamPipes Logo" title="Apache StreamPipes Logo" width="50%"/>
   <br>
 </h1>
 <h3 align="center">Self-Service Data Analytics for the (Industrial) IoT</h3>
 <h4 align="center">StreamPipes is a self-service (Industrial) IoT toolbox to enable non-technical users to connect
 , analyze and explore IoT data streams. </h4>
-<p align="center">  
+<p align="center">
     <img src="https://raw.githubusercontent.com/apache/streampipes/dev/images/streampipes-overview.png" alt="StreamPipes Overview"/>
 </p>
 
@@ -53,7 +53,7 @@
   * [Installation](#installation)
   * [Documentation](#documentation)
   * [Building StreamPipes](#building-streampipes)
-  * [Pipeline Elements](#pipeline-elements)  
+  * [Pipeline Elements](#pipeline-elements)
   * [Extending StreamPipes](#extending-streampipes)
   * [Bugs and Feature Requests](#bugs-and-feature-requests)
   * [Get help](#get-help)
@@ -67,7 +67,7 @@
 
 Apache StreamPipes makes industrial data analytics easy!
 
-StreamPipes is an end-to-end toolbox for the industrial IoT. 
+StreamPipes is an end-to-end toolbox for the industrial IoT.
 It comes with a rich graphical user interface targeted at non-technical users and provides the following features:
 
 
@@ -77,8 +77,8 @@ It comes with a rich graphical user interface targeted at non-technical users an
 * A live dashboard to display real-time data from data sources and pipelines, e.g., for shopfloor monitoring.
 
 
-StreamPipes is highly extensible and includes a Java SDK to create new 
-pipeline elements and adapters. Python support is available in an early development stage - stay tuned!  
+StreamPipes is highly extensible and includes a Java SDK to create new
+pipeline elements and adapters. Python support is available in an early development stage - stay tuned!
 Pipeline elements are standalone microservices that can run anywhere -
 centrally on your server or close at the edge.
 You want to employ your own machine learning model on live data?
@@ -108,13 +108,13 @@ Besides that, StreamPipes includes features for production deployments:
 
 ## Installation
 
-The quickest way to run StreamPipes including the latest extensions (adapters, pipeline elements) is by using our Docker-based [installation & operation options](installer), namely: 
+The quickest way to run StreamPipes including the latest extensions (adapters, pipeline elements) is by using our Docker-based [installation & operation options](installer), namely:
 
 * **[StreamPipes Compose](installer/compose)** - The User's Choice
 * **[StreamPipes CLI](installer/cli)** - The Developer's Favorite
 * **[StreamPipes k8s](installer/k8s)** - The Operator's Dream
 
-> [!IMPORTANT] 
+> [!IMPORTANT]
 > StreamPipes CLI & k8s are highly recommended for developers or operators. Standard users should stick to StreamPipes Compose.
 
 Please follow the instructions provided in the corresponding `README.md` to get started.
@@ -168,14 +168,14 @@ You can also use the installer or CLI as described in the ``Installation`` secti
 
 ## Pipeline Elements
 StreamPipes includes a repository of extensions for adapters and pipeline elements:
-* **Connect adapters** for a variety of IoT data sources as well as 
-* **Data Processors** and **Data Sinks** as ready-to-use pipeline elements. 
+* **Connect adapters** for a variety of IoT data sources as well as
+* **Data Processors** and **Data Sinks** as ready-to-use pipeline elements.
 
 The source code of all included pipeline elements and adapters can be found [here](https://github.com/apache/streampipes/tree/dev/streampipes-extensions).
 
 ## Extending StreamPipes
 
-You can easily add your own data streams, processors or sinks. A [Java-based SDK](https://streampipes.apache.org/docs/extend-tutorial-data-processors.html) can be used to integrate your existing processing logic into StreamPipes. 
+You can easily add your own data streams, processors or sinks. A [Java-based SDK](https://streampipes.apache.org/docs/extend-tutorial-data-processors.html) can be used to integrate your existing processing logic into StreamPipes.
 Pipeline elements are packaged as Docker images and can be installed at runtime, whenever your requirements change.
 
 👉 Check our [developer guide](https://streampipes.apache.org/docs/extend-setup.html).
@@ -189,10 +189,10 @@ If you've found a bug or have a feature that you'd love to see in StreamPipes, f
 
 ## Get help
 
-If you have any problems during the installation or questions around StreamPipes, you'll get help through one of our 
+If you have any problems during the installation or questions around StreamPipes, you'll get help through one of our
 community channels:
 
-👉 [Mailing Lists](https://streampipes.apache.org/mailinglists.html)
+👉 [Mailing Lists](https://streampipes.apache.org/community/mailing-lists/)
 
 Or directly subscribe to [users-subscribe@streampipes.apache.org](mailto:users-subscribe@streampipes.apache.org)!
 
diff --git a/archetypes/streampipes-archetype-extensions-jvm/src/main/resources/archetype-resources/src/main/java/Init.java b/archetypes/streampipes-archetype-extensions-jvm/src/main/resources/archetype-resources/src/main/java/Init.java
index d1b9cd51e7..b467203177 100644
--- a/archetypes/streampipes-archetype-extensions-jvm/src/main/resources/archetype-resources/src/main/java/Init.java
+++ b/archetypes/streampipes-archetype-extensions-jvm/src/main/resources/archetype-resources/src/main/java/Init.java
@@ -32,7 +32,7 @@ import org.apache.streampipes.messaging.kafka.SpKafkaProtocolFactory;
 import org.apache.streampipes.messaging.mqtt.SpMqttProtocolFactory;
 import org.apache.streampipes.messaging.nats.SpNatsProtocolFactory;
 import org.apache.streampipes.messaging.pulsar.SpPulsarProtocolFactory;
-import org.apache.streampipes.service.extensions.ExtensionsModelSubmitter;
+import org.apache.streampipes.service.extensions.StreamPipesExtensionsServiceBase;
 import org.apache.streampipes.wrapper.standalone.runtime.StandaloneStreamPipesRuntimeProvider;
 
 import ${package}.pe.${packageName}.${classNamePrefix}DataProcessor;
@@ -40,7 +40,7 @@ import ${package}.pe.${packageName}.${classNamePrefix}DataSink;
 import ${package}.pe.${packageName}.${classNamePrefix}GenericAdapter;
 import ${package}.pe.${packageName}.${classNamePrefix}SpecificAdapter;
 
-public class Init extends ExtensionsModelSubmitter {
+public class Init extends StreamPipesExtensionsServiceBase {
 
   public static void main(String[] args) {
     new Init().init();
diff --git a/archetypes/streampipes-archetype-pe-processors-flink/src/main/resources/archetype-resources/src/main/java/Init.java b/archetypes/streampipes-archetype-pe-processors-flink/src/main/resources/archetype-resources/src/main/java/Init.java
index 58f30bf004..71e371dc77 100644
--- a/archetypes/streampipes-archetype-pe-processors-flink/src/main/resources/archetype-resources/src/main/java/Init.java
+++ b/archetypes/streampipes-archetype-pe-processors-flink/src/main/resources/archetype-resources/src/main/java/Init.java
@@ -36,9 +36,9 @@ import org.apache.streampipes.messaging.kafka.SpKafkaProtocolFactory;
 import org.apache.streampipes.messaging.mqtt.SpMqttProtocolFactory;
 import org.apache.streampipes.messaging.pulsar.SpPulsarProtocolFactory;
 import org.apache.streampipes.messaging.nats.SpNatsProtocolFactory;
-import org.apache.streampipes.service.extensions.ExtensionsModelSubmitter;
+import org.apache.streampipes.service.extensions.StreamPipesExtensionsServiceBase;
 
-public class Init extends ExtensionsModelSubmitter {
+public class Init extends StreamPipesExtensionsServiceBase {
 
   public static void main(String[] args) throws Exception {
 	  new Init().init();
diff --git a/archetypes/streampipes-archetype-pe-sinks-flink/src/main/resources/archetype-resources/src/main/java/Init.java b/archetypes/streampipes-archetype-pe-sinks-flink/src/main/resources/archetype-resources/src/main/java/Init.java
index f0258d8ffc..b320c7a3ca 100644
--- a/archetypes/streampipes-archetype-pe-sinks-flink/src/main/resources/archetype-resources/src/main/java/Init.java
+++ b/archetypes/streampipes-archetype-pe-sinks-flink/src/main/resources/archetype-resources/src/main/java/Init.java
@@ -32,12 +32,12 @@ import org.apache.streampipes.messaging.kafka.SpKafkaProtocolFactory;
 import org.apache.streampipes.messaging.mqtt.SpMqttProtocolFactory;
 import org.apache.streampipes.messaging.pulsar.SpPulsarProtocolFactory;
 import org.apache.streampipes.messaging.nats.SpNatsProtocolFactory;
-import org.apache.streampipes.service.extensions.ExtensionsModelSubmitter;
+import org.apache.streampipes.service.extensions.StreamPipesExtensionsServiceBase;
 
 import ${package}.config.ConfigKeys;
 import ${package}.pe.sink.${packageName}.${classNamePrefix}Controller;
 
-public class Init extends ExtensionsModelSubmitter {
+public class Init extends StreamPipesExtensionsServiceBase {
 
   public static void main(String[] args) throws Exception {
     new Init().init();
diff --git a/installer/cli/README.md b/installer/cli/README.md
index 504b9882db..ebbd8edfac 100644
--- a/installer/cli/README.md
+++ b/installer/cli/README.md
@@ -107,7 +107,7 @@ streampipes up -d
 ```
 Now you're good to go to write your new pipeline element :tada: :tada: :tada:
 
-> **HINT for extensions**: Use our [Maven archetypes](https://streampipes.apache.org/docs/docs/dev-guide-archetype/) to setup a project skeleton and use your IDE of choice for development. However, we do recommend using IntelliJ.
+> **HINT for extensions**: Use our [Maven archetypes](https://streampipes.apache.org/docs/extend-archetypes/) to setup a project skeleton and use your IDE of choice for development. However, we do recommend using IntelliJ.
 
 > **HINT for core**: To work on `backend` or `ui` features you need to set the template to `backend` and clone the core repository [streampipes](https://github.com/apache/streampipes) - check the prerequisites there for more information.
 
@@ -163,7 +163,7 @@ streampipes start extensions-all-jvm
 **Restart** existing services
 ```bash
 # restart backend couchdb container
-streampipes restart backend couchdb 
+streampipes restart backend couchdb
 # restart existing services by removing and recreating container instance
 streampipes restart --force-create extensions-all-jvm
 ```
@@ -263,7 +263,7 @@ If you've found a bug or have a feature that you'd love to see in StreamPipes, f
 If you have any problems during the installation or questions around StreamPipes, you'll get help through one of our community channels:
 
 - [Slack](https://slack.streampipes.org)
-- [Mailing Lists](https://streampipes.apache.org/mailinglists.html)
+- [Mailing Lists](https://streampipes.apache.org/community/mailing-lists/)
 
 And don't forget to follow us on [Twitter](https://twitter.com/streampipes)!
 
diff --git a/installer/compose/README.md b/installer/compose/README.md
index 7c11ec22f9..7d04ebd46d 100644
--- a/installer/compose/README.md
+++ b/installer/compose/README.md
@@ -29,7 +29,7 @@ StreamPipes Compose is a simple collection of user-friendly `docker-compose` fil
 ```bash
 docker-compose up -d
 ```
-Go to http://localhost to finish the installation in the browser. Once finished, switch to the pipeline editor and start the interactive tour or check the [online tour](https://streampipes.apache.org/docs/docs/user-guide-tour/) to learn how to create your first pipeline!
+Go to http://localhost to finish the installation in the browser. Once finished, switch to the pipeline editor and start the interactive tour or check the [online tour](https://streampipes.apache.org/docs/user-guide-tour/) to learn how to create your first pipeline!
 
 ## Prerequisite
 * Docker >= 17.06.0
@@ -50,7 +50,7 @@ We provide three options to get you going:
 - **full**:  contains experimental Flink wrappers
 - **quickstart**:  contains pre-configured sample assets, including pipelines, dashboards, and data views. We recommend first-time StreamPipes users to use the Quickstart mode to experience the convenience of StreamPipes in IIoT! （Recommended for first-time users)
 
-The ``nats`` version will become the default version in a later release. You can already try it for new installations, 
+The ``nats`` version will become the default version in a later release. You can already try it for new installations,
 but there's not yet an automatic migration from current Kafka-based installations to Nats.
 
 **Starting** the **default** option is as easy as simply running:
@@ -60,7 +60,7 @@ but there's not yet an automatic migration from current Kafka-based installation
 docker-compose up -d
 # go to `http://localhost` after all services are started
 ```
-After all containers are successfully started just got to your browser and visit http://localhost to finish the installation. Once finished, switch to the pipeline editor and start the interactive tour or check the [documentation](https://streampipes.apache.org/docs/docs/user-guide-introduction.html) to learn more about StreamPipes!
+After all containers are successfully started just got to your browser and visit http://localhost to finish the installation. Once finished, switch to the pipeline editor and start the interactive tour or check the [documentation](https://streampipes.apache.org/docs/user-guide-introduction/) to learn more about StreamPipes!
 
 **Stopping** the **default** option is similarly easy:
 ```bash
@@ -123,7 +123,7 @@ Since we purely levarage Docker Compose, please see their [documentation](https:
 If you have any problems during the installation or questions around StreamPipes, you'll get help through one of our community channels:
 
 - [Slack](https://slack.streampipes.org)
-- [Mailing Lists](https://streampipes.apache.org/mailinglists.html)
+- [Mailing Lists](https://streampipes.apache.org/community/mailing-lists/)
 
 And don't forget to follow us on [Twitter](https://twitter.com/streampipes)!
 
diff --git a/installer/k8s/README.md b/installer/k8s/README.md
index 3d1c0563d0..598e034ce9 100644
--- a/installer/k8s/README.md
+++ b/installer/k8s/README.md
@@ -314,7 +314,7 @@ If you have any problems during the installation or questions around StreamPipes
 community channels:
 
 - [Slack](https://slack.streampipes.org)
-- [Mailing Lists](https://streampipes.apache.org/mailinglists.html)
+- [Mailing Lists](https://streampipes.apache.org/community/mailing-lists/)
 
 And don't forget to follow us on [Twitter](https://twitter.com/streampipes)!
 
diff --git a/streampipes-client-python/docs/getting-started/developing.md b/streampipes-client-python/docs/getting-started/developing.md
index 10708dda96..59e96cf568 100644
--- a/streampipes-client-python/docs/getting-started/developing.md
+++ b/streampipes-client-python/docs/getting-started/developing.md
@@ -24,7 +24,7 @@ This document describes how to easily set up your local dev environment to work
 
 1) **Set up your Python environment**
 
-Create a virtual Python environment using a tool of your choice. 
+Create a virtual Python environment using a tool of your choice.
 To manage dependencies, we use [Poetry](https://python-poetry.org/), so please install poetry in your local environment, e.g. via
 ```bash
 pip install poetry
@@ -44,7 +44,7 @@ poetry install --with dev,stubs,docs  # install all optional dependencies relate
 
 The pre-commit hook is run before every commit and takes care about code style,
 linting, type hints, import sorting, etc. It will stop your commit in case the changes do not apply the expected format.
-Always check to have the recent version of the pre-commit hook installed otherwise the CI build might fail. 
+Always check to have the recent version of the pre-commit hook installed otherwise the CI build might fail.
 If you are interested, you can have a deeper look on the underlying library: [pre-commit](https://pre-commit.com/).
 
 ```bash
@@ -67,7 +67,7 @@ Please stick to the `numpy` [style](https://numpydoc.readthedocs.io/en/latest/fo
 2) **Provide tests** ✅ <br>
 We are aiming for broad test coverage for the Python package and
 have therefore set a requirement of at least 90% unit test coverage.
-Therefore, please remember to write (unit) tests already during development. 
+Therefore, please remember to write (unit) tests already during development.
 If you have problems with writing tests, don't hesitate to ask us for help directly in the PR or
 even before that via our mailing list (see above).
 
@@ -127,7 +127,7 @@ Stay tuned!
 
 ---
 ## 👨‍💻 Contributing
-*Before opening a pull request*, review the [Get Involved](https://streampipes.apache.org/getinvolved.html) page.
+*Before opening a pull request*, review the [Get Involved](https://streampipes.apache.org/community/get-involved/) page.
 It lists information that is required for contributing to StreamPipes.
 
 When you contribute code, you affirm that the contribution is your original work and that you
@@ -136,4 +136,4 @@ state this explicitly, by submitting any copyrighted material via pull request,
 other means you agree to license the material under the project's open source license and
 warrant that you have the legal authority to do so.
 
----
\ No newline at end of file
+---
diff --git a/streampipes-client-python/docs/getting-started/first-steps.md b/streampipes-client-python/docs/getting-started/first-steps.md
index a8f0288b42..81df71eeac 100644
--- a/streampipes-client-python/docs/getting-started/first-steps.md
+++ b/streampipes-client-python/docs/getting-started/first-steps.md
@@ -48,11 +48,11 @@ CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
 ...            ...       ...       ...       ...       ...       ...
 ```
 Otherwise, you need to start docker first.
-Please read the full guide on how to start StreamPipes with `docker compose` [here](https://streampipes.apache.org/docs/docs/deploy-docker.html).
+Please read the full guide on how to start StreamPipes with `docker compose` [here](https://streampipes.apache.org/docs/deploy-docker/).
 
 #### Setup StreamPipes with NATS as message broker
 The following shows how you can set up a StreamPipes instance that uses [NATS](https://docs.nats.io/) as messaging layer.
-So in this scenario, we will go with `docker-compose.nats.yml`. 
+So in this scenario, we will go with `docker-compose.nats.yml`.
 Thereby, when running locally, we need to add the following port mapping entry to `services.nats.ports`:
 ```yaml
 - 4222:4222
@@ -85,6 +85,6 @@ docker-compose -f docker-compose.yml up -d
 Once all services are started, you can access StreamPipes via `http://localhost`.
 
 In case you want to have more control over your StreamPipes setup,
-you might take a look at our [deployment CLI](https://streampipes.apache.org/docs/docs/extend-cli.html).
+you might take a look at our [deployment CLI](https://streampipes.apache.org/docs/extend-cli/).
 
 Have fun discovering StreamPipes and our Python library 🚀
diff --git a/streampipes-client-python/docs/tutorials/1-introduction-to-streampipes-python-client.ipynb b/streampipes-client-python/docs/tutorials/1-introduction-to-streampipes-python-client.ipynb
index c7efd9a81f..50eb8c3dfe 100644
--- a/streampipes-client-python/docs/tutorials/1-introduction-to-streampipes-python-client.ipynb
+++ b/streampipes-client-python/docs/tutorials/1-introduction-to-streampipes-python-client.ipynb
@@ -7,9 +7,9 @@
     "\n",
     "### Why there is an extra Python library for StreamPipes?\n",
     "[Apache StreamPipes](https://streampipes.apache.org/) aims to enable non-technical users to connect and analyze IoT data streams.\n",
-    "To this end, it provides an easy-to-use and convenient user interface that allows one to connect to an IoT data source and create some visual\n",
+    "To achieve this, it provides an easy-to-use and convenient user interface that allows one to connect to an IoT data source and create some visual\n",
     "graphs within a few minutes. <br>\n",
-    "Although this is the main use case of Apache StreamPipes, it can also provide great value for people who are eager to work on data analysis or data science with IoT data, but don't we do get in touch with all the hassle associated with extracting data from devices in a suitable format.\n",
+    "While this is the primary use case for Apache StreamPipes, it also offers significant value to those interested in data analysis or data science with IoT data, without the need to handle the complexities of extracting data from devices in a suitable format.\n",
     "In this scenario, StreamPipes helps you connect to your data source and extract the data for you.\n",
     "You then can make the data available outside StreamPipes by writing it into an external source, such as a database, Kafka, etc.\n",
     "While this requires another component, you can also extract your data directly from StreamPipes programmatically using the StreamPipes API.\n",
@@ -87,7 +87,7 @@
    "source": [
     "### How to configure the Python client\n",
     "In order to access the resources available in StreamPipes, one must be able to authenticate against the backend.\n",
-    "For this purpose, the client sofar only supports the authentication via an API token that can be generated via the StreamPipes UI, as you see below.\n",
+    "For this purpose, the client so far only supports the authentication via an API token that can be generated via the StreamPipes UI, as you can see below.\n",
     "\n",
     "![how-to-get-api-key](https://raw.githubusercontent.com/apache/streampipes/dev/streampipes-client-python/docs/img/how-to-get-api-key.gif)\n",
     "\n",
@@ -159,7 +159,7 @@
    "cell_type": "markdown",
    "source": [
     "To ensure that the above code works, you must set the environment variables as expected.\n",
-    "This can be done like following:"
+    "This can be done as follows:"
    ],
    "metadata": {
     "collapsed": false
diff --git a/streampipes-client-python/docs/tutorials/2-extracting-data-from-the-streampipes-data-lake.ipynb b/streampipes-client-python/docs/tutorials/2-extracting-data-from-the-streampipes-data-lake.ipynb
index 000f6fa96f..af3c0dc4b9 100644
--- a/streampipes-client-python/docs/tutorials/2-extracting-data-from-the-streampipes-data-lake.ipynb
+++ b/streampipes-client-python/docs/tutorials/2-extracting-data-from-the-streampipes-data-lake.ipynb
@@ -121,7 +121,7 @@
   {
    "cell_type": "markdown",
    "source": [
-    "So let's see how many measures are available"
+    "So let's see how many measures are available:"
    ],
    "metadata": {
     "collapsed": false
@@ -179,7 +179,7 @@
   {
    "cell_type": "markdown",
    "source": [
-    "To get a more comprehensive overview, you can take a look at the [`pandas`](https://pandas.pydata.org/) representation"
+    "To get a more comprehensive overview, you can take a look at the [`pandas`](https://pandas.pydata.org/) representation:"
    ],
    "metadata": {
     "collapsed": false
@@ -318,7 +318,7 @@
   {
    "cell_type": "markdown",
    "source": [
-    "As a final step, we want to create a plot of both attributes"
+    "As a final step, we want to create a plot of both attributes."
    ],
    "metadata": {
     "collapsed": false
@@ -469,10 +469,10 @@
   {
    "cell_type": "markdown",
    "source": [
-    "... from this point on we leave all future processing of the data up to your creativity.\n",
+    "... from this point on, we leave all future processing of the data up to your creativity.\n",
     "Keep in mind: the general syntax used in this tutorial (`all()`, `to_pandas()`, `get()`) applies to all endpoints and associated resources of the StreamPipes Python client.\n",
     "\n",
-    "If you get further and create exiting stuff with data extracted from StreamPipes please [let us know](https://github.com/apache/streampipes/discussions/categories/show-and-tell).\n",
+    "If you get further and create exciting stuff with data extracted from StreamPipes please [let us know](https://github.com/apache/streampipes/discussions/categories/show-and-tell).\n",
     "We are thrilled to see what you as a community will build with the provided client.\n",
     "Furthermore, don't hesitate to discuss [feature requests](https://github.com/apache/streampipes/discussions/812) to extend the current functionality with us."
    ],
@@ -483,7 +483,7 @@
   {
    "cell_type": "markdown",
    "source": [
-    "For now, that's all about the StreamPipes client. Read the next tutorial ([Getting live data from the StreamPipes data stream](../3-getting-live-data-from-the-streampipes-data-stream)) if you are interested in making use of the powerful [StreamPipes functions](https://streampipes.apache.org/docs/docs/extend-sdk-functions.html) to interact with StreamPipes event-based."
+    "For now, that's all about the StreamPipes client. Read the next tutorial ([Getting live data from the StreamPipes data stream](../3-getting-live-data-from-the-streampipes-data-stream)) if you are interested in making use of the powerful [StreamPipes functions](https://streampipes.apache.org/docs/extend-sdk-functions.html) to interact with StreamPipes in an event-based manner."
    ],
    "metadata": {
     "collapsed": false
diff --git a/streampipes-client-python/docs/tutorials/5-applying-interoperable-machine-learning-in-streampipes.ipynb b/streampipes-client-python/docs/tutorials/5-applying-interoperable-machine-learning-in-streampipes.ipynb
index f1b055aed4..70cff543a5 100644
--- a/streampipes-client-python/docs/tutorials/5-applying-interoperable-machine-learning-in-streampipes.ipynb
+++ b/streampipes-client-python/docs/tutorials/5-applying-interoperable-machine-learning-in-streampipes.ipynb
@@ -381,7 +381,7 @@
    "source": [
     "Let's dive a little deeper into the different parts of the function\n",
     "\n",
-    "- **`__init__`**: First, we need to take care about the data stream that is required to send the predictions from our function to StreamPipes. Thus, we create a dedicated output data stream which we need to provide with the attributes our event will consist of (a timestamp attribute is always added automatically). This output data stream needs to be registered at the function definition which is to be passed to the parent class. Lastly, we need to define some instance variables that are mainly required for the ONNX runtime.\n",
+    "- **`__init__`**: First, we need to take care of the data stream that is required to send the predictions from our function to StreamPipes. Thus, we create a dedicated output data stream which we need to provide with the attributes our event will consist of (a timestamp attribute is always added automatically). This output data stream needs to be registered at the function definition which is to be passed to the parent class. Lastly, we need to define some instance variables that are mainly required for the ONNX runtime.\n",
     "\n",
     "- **`onServiceStarted`**: Here we prepare the ONNX runtime session by creating an `InferenceSession` and retrieving the corresponding configuration parameters.\n",
     "\n",
diff --git a/streampipes-client-python/streampipes/client/client.py b/streampipes-client-python/streampipes/client/client.py
index 047e52cc89..c150b6d24c 100644
--- a/streampipes-client-python/streampipes/client/client.py
+++ b/streampipes-client-python/streampipes/client/client.py
@@ -230,7 +230,7 @@ class StreamPipesClient:
         Returns
         -------
         http_headers: Dict[str, str]
-            header information for HTTP requests as string key-value pairs.
+            Header information for HTTP requests as string key-value pairs.
         """
 
         # create HTTP headers from credential provider and add additional headers needed
diff --git a/streampipes-client-python/streampipes/client/credential_provider.py b/streampipes-client-python/streampipes/client/credential_provider.py
index d7493b40c2..f2fd843b4d 100644
--- a/streampipes-client-python/streampipes/client/credential_provider.py
+++ b/streampipes-client-python/streampipes/client/credential_provider.py
@@ -112,7 +112,7 @@ class StreamPipesApiKeyCredentials(CredentialProvider):
     def from_env(cls, username_env: str, api_key_env: str) -> StreamPipesApiKeyCredentials:
         """DEPRECATED - use the class constructor instead
 
-        Returns an api key provider parameterized via environment variables.
+        Returns an API key provider parameterized via environment variables.
 
         Parameters
         ----------
diff --git a/streampipes-client-python/streampipes/endpoint/api/data_lake_measure.py b/streampipes-client-python/streampipes/endpoint/api/data_lake_measure.py
index 0bdf256002..7751334052 100644
--- a/streampipes-client-python/streampipes/endpoint/api/data_lake_measure.py
+++ b/streampipes-client-python/streampipes/endpoint/api/data_lake_measure.py
@@ -55,7 +55,7 @@ class MeasurementGetQueryConfig(BaseModel):
         If provided, the returned data only consists of the given columns.<br>
         Please be aware that the column `time` as an index is always included.
     end_date: Optional[datetime]
-        Restricts queried data to be younger than the specified time.
+        Limits the queried data to only include data that is older than the specified time. In other words, any data that occurred after the end_date will not be included in the query results.
     limit: Optional[int]
         Amount of records returned at maximum (default: `1000`) <br>
         This needs to be at least `1`
@@ -69,7 +69,7 @@ class MeasurementGetQueryConfig(BaseModel):
         Page number used for paging operation <br>
         This needs to be at least `1`
     start_date: Optional[datetime]
-        Restricts queried data to be older than the specified time
+        Limits the queried data to only include data that is newer than the specified time. In other words, any data that occurred before the start_date will not be included in the query results.
     """
 
     _regex_comma_separated_string = r"^[0-9a-zA-Z\_]+(,[0-9a-zA-Z\_]+)*$"
@@ -344,14 +344,14 @@ class DataLakeMeasureEndpoint(APIEndpoint):
         identifier: str
             The identifier of the data lake measure to be queried.
         **kwargs: Dict[str, Any]
-            keyword arguments can be used to provide additional query parameters.
+            Keyword arguments can be used to provide additional query parameters.
             The available query parameters are defined by the
             [MeasurementGetQueryConfig][streampipes.endpoint.api.data_lake_measure.MeasurementGetQueryConfig].
 
         Returns
         -------
         measurement: DataLakeMeasures
-            the specified data lake measure
+            The specified data lake measure
 
         Examples
         --------
diff --git a/streampipes-client-python/streampipes/endpoint/api/version.py b/streampipes-client-python/streampipes/endpoint/api/version.py
index fb06583e3a..0b21544850 100644
--- a/streampipes-client-python/streampipes/endpoint/api/version.py
+++ b/streampipes-client-python/streampipes/endpoint/api/version.py
@@ -105,7 +105,7 @@ class VersionEndpoint(APIEndpoint):
         Raises
         ------
         NotImplementedError
-            this endpoint does not return multiple entries, therefore this method is not available
+            This endpoint does not return multiple entries, therefore this method is not available.
 
         """
         raise NotImplementedError("The `all()` method is not supported by this endpoint.")
@@ -147,7 +147,7 @@ class VersionEndpoint(APIEndpoint):
         Raises
         ------
         NotImplementedError
-            this endpoint does not allow for POST requests, therefore this method is not available
+            This endpoint does not allow for POST requests, therefore this method is not available.
 
         """
         raise NotImplementedError("The `post()` method is not supported by this endpoint.")
diff --git a/streampipes-client-python/streampipes/endpoint/endpoint.py b/streampipes-client-python/streampipes/endpoint/endpoint.py
index fb70fbf41a..2c491c6dd1 100644
--- a/streampipes-client-python/streampipes/endpoint/endpoint.py
+++ b/streampipes-client-python/streampipes/endpoint/endpoint.py
@@ -18,7 +18,7 @@
 """
 General implementation for an endpoint.
 Provided classes and assets are aimed to be used for developing endpoints.
-An endpoint provides all options to communicate with ad dedicated part of StreamPipes in a handy way.
+An endpoint provides all options to communicate with a dedicated part of StreamPipes in a handy way.
 """
 
 import json
@@ -184,7 +184,7 @@ class APIEndpoint(Endpoint):
         Returns
         -------
         container: ResourceContainer
-             container element that bundles the returned resources
+             Container element that bundles the returned resources
         """
 
         response = self._make_request(
@@ -284,7 +284,7 @@ class MessagingEndpoint(Endpoint):
         """Configures the message endpoint by setting the broker instance to be used.
 
         This configuration step is required before the endpoint can be actually used.
-        The based `broker` instance is passed to an internal property
+        The based `broker` instance is passed to an internal property.
 
         Parameters
         ----------
diff --git a/streampipes-client-python/streampipes/endpoint/exceptions.py b/streampipes-client-python/streampipes/endpoint/exceptions.py
index 6465146f92..6803a836f4 100644
--- a/streampipes-client-python/streampipes/endpoint/exceptions.py
+++ b/streampipes-client-python/streampipes/endpoint/exceptions.py
@@ -16,7 +16,7 @@
 #
 
 """
-Custom exceptions dedicated for the endpoints module
+Custom exceptions dedicated to the endpoints module.
 """
 
 __all__ = [
diff --git a/streampipes-client-python/streampipes/functions/streampipes_function.py b/streampipes-client-python/streampipes/functions/streampipes_function.py
index 90521f1934..8d3c063768 100644
--- a/streampipes-client-python/streampipes/functions/streampipes_function.py
+++ b/streampipes-client-python/streampipes/functions/streampipes_function.py
@@ -34,7 +34,7 @@ class StreamPipesFunction(ABC):
     Parameters
     ----------
     function_definition: FunctionDefinition
-        the definition of the function that contains metadata about the connected function
+        The definition of the function that contains metadata about the connected function
 
     Attributes
     ----------
@@ -50,7 +50,7 @@ class StreamPipesFunction(ABC):
         }
 
     def add_output(self, stream_id: str, event: Dict[str, Any]):
-        """Send an event via an output data stream to StreamPipes
+        """Send an event via an output data stream to StreamPipes.
 
         Parameters
         ----------
@@ -78,7 +78,7 @@ class StreamPipesFunction(ABC):
         return self.function_definition.function_id
 
     def stop(self) -> None:
-        """Stops the function and disconnects from the output streams"""
+        """Stops the function and disconnects from the output streams."""
 
         for collector in self.output_collectors.values():
             collector.disconnect()
@@ -96,12 +96,12 @@ class StreamPipesFunction(ABC):
 
     @abstractmethod
     def onServiceStarted(self, context: FunctionContext) -> None:
-        """Is called when the function gets started.
+        """Is called when the function is started.
 
         Parameters
         ----------
         context: FunctionContext
-            The context in which the function gets started.
+            The context in which the function is started.
 
         Returns
         -------
@@ -128,7 +128,7 @@ class StreamPipesFunction(ABC):
 
     @abstractmethod
     def onServiceStopped(self) -> None:
-        """Is called when the function gets stopped.
+        """Is called when the function is stopped.
 
         Returns
         -------
diff --git a/streampipes-client-python/streampipes/model/common.py b/streampipes-client-python/streampipes/model/common.py
index 49cd58caad..f1e36225c7 100644
--- a/streampipes-client-python/streampipes/model/common.py
+++ b/streampipes-client-python/streampipes/model/common.py
@@ -82,14 +82,14 @@ class BasicModel(BaseModel):
 
 
 class BaseElement(BasicModel):
-    """Structure of a basic element in the StreamPipes backend"""
+    """Structure of a basic element in the StreamPipes Backend."""
 
     element_id: Optional[StrictStr]
 
 
 class ValueSpecification(BasicModel):
     """
-    Data model of an `ValueSpecification` in compliance to the StreamPipes Backend.
+    Data model of an `ValueSpecification` in compliance with the StreamPipes Backend.
     """
 
     class_name: Optional[StrictStr] = Field(alias="@class")
@@ -101,7 +101,7 @@ class ValueSpecification(BasicModel):
 
 class EventProperty(BasicModel):
     """
-    Data model of an `EventProperty` in compliance to the StreamPipes Backend.
+    Data model of an `EventProperty` in compliance with the StreamPipes Backend.
     """
 
     class_name: StrictStr = Field(alias="@class", default="org.apache.streampipes.model.schema.EventPropertyPrimitive")
@@ -121,7 +121,7 @@ class EventProperty(BasicModel):
 
 class EventSchema(BasicModel):
     """
-    Data model of an `EventSchema` in compliance to the StreamPipes Backend.
+    Data model of an `EventSchema` in compliance with the StreamPipes Backend.
     """
 
     event_properties: List[EventProperty]
@@ -129,7 +129,7 @@ class EventSchema(BasicModel):
 
 class ApplicationLink(BasicModel):
     """
-    Data model of an `ApplicationLink` in compliance to the StreamPipes Backend.
+    Data model of an `ApplicationLink` in compliance with the StreamPipes Backend.
     """
 
     class_name: Optional[StrictStr] = Field(alias="@class")
@@ -143,7 +143,7 @@ class ApplicationLink(BasicModel):
 
 class TopicDefinition(BasicModel):
     """
-    Data model of a `TopicDefinition` in compliance to the StreamPipes Backend.
+    Data model of a `TopicDefinition` in compliance with the StreamPipes Backend.
     """
 
     class_name: Optional[StrictStr] = Field(
@@ -154,7 +154,7 @@ class TopicDefinition(BasicModel):
 
 class TransportProtocol(BasicModel):
     """
-    Data model of a `TransportProtocol` in compliance to the StreamPipes Backend.
+    Data model of a `TransportProtocol` in compliance with the StreamPipes Backend.
     """
 
     class_name: StrictStr = Field(
@@ -168,7 +168,7 @@ class TransportProtocol(BasicModel):
 
 class TransportFormat(BasicModel):
     """
-    Data model of a `TransportFormat` in compliance to the StreamPipes Backend.
+    Data model of a `TransportFormat` in compliance with the StreamPipes Backend.
     """
 
     rdf_type: List[StrictStr] = Field(default=["http://sepa.event-processing.org/sepa#json"])
@@ -176,7 +176,7 @@ class TransportFormat(BasicModel):
 
 class EventGrounding(BasicModel):
     """
-    Data model of an `EventGrounding` in compliance to the StreamPipes Backend.
+    Data model of an `EventGrounding` in compliance to with StreamPipes Backend.
     """
 
     transport_protocols: List[TransportProtocol] = Field(default_factory=lambda: [TransportProtocol()])
@@ -185,7 +185,7 @@ class EventGrounding(BasicModel):
 
 class MeasurementCapability(BasicModel):
     """
-    Data model of a `MeasurementCapability` in compliance to the StreamPipes Backend.
+    Data model of a `MeasurementCapability` in compliance with the StreamPipes Backend.
     """
 
     capability: Optional[StrictStr]
@@ -194,7 +194,7 @@ class MeasurementCapability(BasicModel):
 
 class MeasurementObject(BasicModel):
     """
-    Data model of a `MeasurementObject` in compliance to the StreamPipes Backend.
+    Data model of a `MeasurementObject` in compliance with the StreamPipes Backend.
     """
 
     element_id: Optional[StrictStr]
diff --git a/streampipes-client-python/streampipes/model/container/resource_container.py b/streampipes-client-python/streampipes/model/container/resource_container.py
index b86a0c5ff8..03c017319e 100644
--- a/streampipes-client-python/streampipes/model/container/resource_container.py
+++ b/streampipes-client-python/streampipes/model/container/resource_container.py
@@ -166,7 +166,7 @@ class ResourceContainer(ABC):
         Returns
         -------
         container: ResourceContainer
-            instance of the container derived from the JSON definition
+            Instance of the container derived from the JSON definition
 
         Raises
         ------
diff --git a/streampipes-extensions/streampipes-connectors-plc/pom.xml b/streampipes-extensions/streampipes-connectors-plc/pom.xml
index a1d3857ff9..5c63b63023 100644
--- a/streampipes-extensions/streampipes-connectors-plc/pom.xml
+++ b/streampipes-extensions/streampipes-connectors-plc/pom.xml
@@ -55,7 +55,7 @@
         <dependency>
             <groupId>org.apache.plc4x</groupId>
             <artifactId>plc4j-driver-all</artifactId>
-            <version>0.12.0</version>
+            <version>${plc4x.version}</version>
             <type>pom</type>
             <exclusions>
                 <exclusion>
@@ -72,6 +72,11 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.apache.plc4x</groupId>
+            <artifactId>plc4j-connection-cache</artifactId>
+            <version>${plc4x.version}</version>
+        </dependency>
 
 
         <!-- Test dependencies -->
diff --git a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/PlcConnectorsModuleExport.java b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/PlcConnectorsModuleExport.java
index e5ecfe14b4..1bbc1df1b2 100644
--- a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/PlcConnectorsModuleExport.java
+++ b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/PlcConnectorsModuleExport.java
@@ -28,18 +28,24 @@ import org.apache.streampipes.extensions.connectors.plc.adapter.migration.Plc4xS
 import org.apache.streampipes.extensions.connectors.plc.adapter.modbus.Plc4xModbusAdapter;
 import org.apache.streampipes.extensions.connectors.plc.adapter.s7.Plc4xS7Adapter;
 
+import org.apache.plc4x.java.api.PlcDriverManager;
+import org.apache.plc4x.java.utils.cache.CachedPlcConnectionManager;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 public class PlcConnectorsModuleExport implements IExtensionModuleExport {
+
   @Override
   public List<StreamPipesAdapter> adapters() {
-    var adapters = new ArrayList<StreamPipesAdapter>(List.of(
-        new Plc4xModbusAdapter(),
-        new Plc4xS7Adapter()
+    var driverManager = PlcDriverManager.getDefault();
+    var cachedConnectionManager =  CachedPlcConnectionManager.getBuilder().build();
+    var adapters = new ArrayList<>(List.of(
+        new Plc4xModbusAdapter(cachedConnectionManager),
+        new Plc4xS7Adapter(cachedConnectionManager)
     ));
-    adapters.addAll(new GenericAdapterGenerator().makeAvailableAdapters());
+    adapters.addAll(new GenericAdapterGenerator().makeAvailableAdapters(driverManager, cachedConnectionManager));
     return adapters;
   }
 
diff --git a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/GenericAdapterGenerator.java b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/GenericAdapterGenerator.java
index 56f3d83095..e8a0ad2150 100644
--- a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/GenericAdapterGenerator.java
+++ b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/GenericAdapterGenerator.java
@@ -21,6 +21,7 @@ package org.apache.streampipes.extensions.connectors.plc.adapter;
 import org.apache.streampipes.extensions.api.connect.StreamPipesAdapter;
 import org.apache.streampipes.extensions.connectors.plc.adapter.generic.GenericPlc4xAdapter;
 
+import org.apache.plc4x.java.api.PlcConnectionManager;
 import org.apache.plc4x.java.api.PlcDriverManager;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.slf4j.Logger;
@@ -41,11 +42,10 @@ public class GenericAdapterGenerator {
   );
 
 
-  public List<StreamPipesAdapter> makeAvailableAdapters() {
+  public List<StreamPipesAdapter> makeAvailableAdapters(PlcDriverManager driverManager,
+                                                        PlcConnectionManager connectionManager) {
     var adapters = new ArrayList<StreamPipesAdapter>();
-    var protocolCodes = getDrivers();
-    var driverManager = PlcDriverManager.getDefault();
-    var connectionManager = driverManager.getConnectionManager();
+    var protocolCodes = getDrivers(driverManager);
     protocolCodes
         .stream()
         .filter(pc -> !excludedDrivers.contains(pc))
@@ -60,9 +60,8 @@ public class GenericAdapterGenerator {
     return adapters;
   }
 
-  private Set<String> getDrivers() {
-    return PlcDriverManager
-        .getDefault()
+  private Set<String> getDrivers(PlcDriverManager driverManager) {
+    return driverManager
         .getProtocolCodes();
   }
 }
diff --git a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/GenericPlc4xAdapter.java b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/GenericPlc4xAdapter.java
index 9f8857c713..eb5a14591f 100644
--- a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/GenericPlc4xAdapter.java
+++ b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/GenericPlc4xAdapter.java
@@ -63,7 +63,6 @@ public class GenericPlc4xAdapter implements StreamPipesAdapter, SupportsRuntimeC
   private PullAdapterScheduler pullAdapterScheduler;
   private final PlcRequestProvider requestProvider;
   private final EventSchemaProvider schemaProvider;
-  private ContinuousPlcRequestReader plcRequestReader;
 
   private final PlcDriver driver;
   private final PlcConnectionManager connectionManager;
@@ -88,7 +87,7 @@ public class GenericPlc4xAdapter implements StreamPipesAdapter, SupportsRuntimeC
     var settings = new Plc4xConnectionExtractor(
         extractor.getStaticPropertyExtractor(), driver.getProtocolCode()
     ).makeSettings();
-    this.plcRequestReader = new ContinuousPlcRequestReader(connectionManager, settings, requestProvider, collector);
+    var plcRequestReader = new ContinuousPlcRequestReader(connectionManager, settings, requestProvider, collector);
     this.pullAdapterScheduler = new PullAdapterScheduler();
     this.pullAdapterScheduler.schedule(plcRequestReader, extractor.getAdapterDescription().getElementId());
   }
@@ -96,11 +95,6 @@ public class GenericPlc4xAdapter implements StreamPipesAdapter, SupportsRuntimeC
   @Override
   public void onAdapterStopped(IAdapterParameterExtractor extractor,
                                IAdapterRuntimeContext adapterRuntimeContext) {
-    try {
-      this.plcRequestReader.closeConnection();
-    } catch (Exception e) {
-      LOG.error("Error when closing connection", e);
-    }
     this.pullAdapterScheduler.shutdown();
   }
 
diff --git a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/connection/ContinuousPlcRequestReader.java b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/connection/ContinuousPlcRequestReader.java
index bb23816a16..0e724b6558 100644
--- a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/connection/ContinuousPlcRequestReader.java
+++ b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/connection/ContinuousPlcRequestReader.java
@@ -22,26 +22,23 @@ import org.apache.streampipes.extensions.api.connect.IEventCollector;
 import org.apache.streampipes.extensions.api.connect.IPollingSettings;
 import org.apache.streampipes.extensions.api.connect.IPullAdapter;
 import org.apache.streampipes.extensions.connectors.plc.adapter.generic.model.Plc4xConnectionSettings;
-import org.apache.streampipes.extensions.connectors.plc.adapter.s7.PlcReadResponseHandler;
 import org.apache.streampipes.extensions.management.connect.adapter.util.PollingSettings;
 
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.PlcConnectionManager;
-import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 public class ContinuousPlcRequestReader
-    extends OneTimePlcRequestReader implements IPullAdapter, PlcReadResponseHandler {
+    extends OneTimePlcRequestReader implements IPullAdapter {
 
   private static final Logger LOG = LoggerFactory.getLogger(ContinuousPlcRequestReader.class);
 
   private final IEventCollector collector;
-  private PlcConnection plcConnection;
 
   public ContinuousPlcRequestReader(PlcConnectionManager connectionManager,
                                     Plc4xConnectionSettings settings,
@@ -53,45 +50,26 @@ public class ContinuousPlcRequestReader
 
   @Override
   public void pullData() throws RuntimeException {
-    try {
-      var connection = getConnection();
-      readPlcData(connection, this);
+    try (PlcConnection plcConnection = connectionManager.getConnection(settings.connectionString())) {
+      if (!plcConnection.isConnected()) {
+        plcConnection.connect();
+      }
+      readPlcData(plcConnection);
     } catch (Exception e) {
       LOG.error("Error while reading from PLC with connection string {} ", settings.connectionString(), e);
     }
   }
 
-  private PlcConnection getConnection() throws PlcConnectionException {
-    if (plcConnection == null || !plcConnection.isConnected()) {
-      this.plcConnection = connectionManager.getConnection(settings.connectionString());
-    }
-    return this.plcConnection;
-  }
-
-  private void readPlcData(PlcConnection plcConnection, PlcReadResponseHandler handler) {
+  private void readPlcData(PlcConnection plcConnection)
+      throws ExecutionException, InterruptedException, TimeoutException {
     var readRequest = requestProvider.makeReadRequest(plcConnection, settings.nodes());
-    CompletableFuture<? extends PlcReadResponse> asyncResponse = readRequest.execute();
-    asyncResponse.whenComplete(handler::onReadResult);
+    var response = readRequest.execute().get(5000, TimeUnit.MILLISECONDS);
+    var event = eventGenerator.makeEvent(response);
+    collector.collect(event);
   }
 
   @Override
   public IPollingSettings getPollingInterval() {
     return PollingSettings.from(TimeUnit.MILLISECONDS, settings.pollingInterval());
   }
-
-  @Override
-  public void onReadResult(PlcReadResponse response, Throwable throwable) {
-    if (throwable != null) {
-      LOG.error(throwable.getMessage());
-    } else {
-      var event = eventGenerator.makeEvent(response);
-      collector.collect(event);
-    }
-  }
-
-  public void closeConnection() throws Exception {
-    if (this.plcConnection != null && this.plcConnection.isConnected()) {
-      this.plcConnection.close();
-    }
-  }
 }
diff --git a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/connection/OneTimePlcRequestReader.java b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/connection/OneTimePlcRequestReader.java
index e03566d99f..4961b1dc94 100644
--- a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/connection/OneTimePlcRequestReader.java
+++ b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/generic/connection/OneTimePlcRequestReader.java
@@ -18,6 +18,7 @@
 
 package org.apache.streampipes.extensions.connectors.plc.adapter.generic.connection;
 
+import org.apache.streampipes.commons.exceptions.connect.AdapterException;
 import org.apache.streampipes.extensions.connectors.plc.adapter.generic.model.Plc4xConnectionSettings;
 
 import org.apache.plc4x.java.api.PlcConnection;
@@ -46,6 +47,12 @@ public class OneTimePlcRequestReader {
   public Map<String, Object> readPlcDataSynchronized() throws Exception {
     var connectionString = settings.connectionString();
     try (PlcConnection plcConnection = connectionManager.getConnection(connectionString)) {
+      if (!plcConnection.getMetadata().isReadSupported()) {
+        throw new AdapterException("This PLC does not support reading data");
+      }
+      if (!plcConnection.isConnected()) {
+        plcConnection.connect();
+      }
       var readRequest = requestProvider.makeReadRequest(plcConnection, settings.nodes());
       var readResponse = readRequest.execute().get(5000, TimeUnit.MILLISECONDS);
       return eventGenerator.makeEvent(readResponse);
diff --git a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/modbus/Plc4xModbusAdapter.java b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/modbus/Plc4xModbusAdapter.java
index 97af4a211b..6c0673797c 100644
--- a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/modbus/Plc4xModbusAdapter.java
+++ b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/modbus/Plc4xModbusAdapter.java
@@ -32,6 +32,7 @@ import org.apache.streampipes.extensions.management.connect.PullAdapterScheduler
 import org.apache.streampipes.extensions.management.connect.adapter.util.PollingSettings;
 import org.apache.streampipes.model.AdapterType;
 import org.apache.streampipes.model.connect.guess.GuessSchema;
+import org.apache.streampipes.model.extensions.ExtensionAssetType;
 import org.apache.streampipes.model.schema.EventProperty;
 import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.model.staticproperty.CollectionStaticProperty;
@@ -44,11 +45,10 @@ import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor;
 import org.apache.streampipes.sdk.helpers.Labels;
 import org.apache.streampipes.sdk.helpers.Locales;
 import org.apache.streampipes.sdk.helpers.Options;
-import org.apache.streampipes.sdk.utils.Assets;
 import org.apache.streampipes.sdk.utils.Datatypes;
 
 import org.apache.plc4x.java.api.PlcConnection;
-import org.apache.plc4x.java.api.PlcDriverManager;
+import org.apache.plc4x.java.api.PlcConnectionManager;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
@@ -101,11 +101,9 @@ public class Plc4xModbusAdapter implements StreamPipesAdapter, IPullAdapter {
    * Connection to the PLC
    */
   private PlcConnection plcConnection;
+  private PlcConnectionManager connectionManager;
 
-  /**
-   * Empty constructor and a constructor with SpecificAdapterStreamDescription are mandatory
-   */
-  public Plc4xModbusAdapter() {
+  public Plc4xModbusAdapter(PlcConnectionManager connectionManager) {
   }
 
   /**
@@ -179,7 +177,7 @@ public class Plc4xModbusAdapter implements StreamPipesAdapter, IPullAdapter {
     getConfigurations(extractor);
 
     try {
-      this.plcConnection = PlcDriverManager.getDefault().getConnectionManager().getConnection(
+      this.plcConnection = connectionManager.getConnection(
           "modbus-tcp:tcp://" + this.ip + ":" + this.port + "?unit-identifier=" + this.slaveID);
 
       if (!this.plcConnection.getMetadata().isReadSupported()) {
@@ -213,16 +211,13 @@ public class Plc4xModbusAdapter implements StreamPipesAdapter, IPullAdapter {
     }
     PlcReadRequest readRequest = builder.build();
 
-
     // Execute the request
     PlcReadResponse response = null;
 
     try {
       response = readRequest.execute().get();
-    } catch (InterruptedException ie) {
+    } catch (InterruptedException | ExecutionException ie) {
       ie.printStackTrace();
-    } catch (ExecutionException ee) {
-      ee.printStackTrace();
     }
 
     // Create an event containing the value of the PLC
@@ -273,9 +268,9 @@ public class Plc4xModbusAdapter implements StreamPipesAdapter, IPullAdapter {
    */
   @Override
   public IAdapterConfiguration declareConfig() {
-    return AdapterConfigurationBuilder.create(ID, 1, Plc4xModbusAdapter::new)
+    return AdapterConfigurationBuilder.create(ID, 1, () -> new Plc4xModbusAdapter(connectionManager))
         .withLocales(Locales.EN)
-        .withAssets(Assets.DOCUMENTATION, Assets.ICON)
+        .withAssets(ExtensionAssetType.DOCUMENTATION, ExtensionAssetType.ICON)
         .withCategory(AdapterType.Manufacturing)
         .requiredTextParameter(Labels.withId(PLC_IP)).requiredIntegerParameter(Labels.withId(PLC_PORT))
         .requiredTextParameter(Labels.withId(PLC_NODE_ID)).requiredCollection(Labels.withId(PLC_NODES),
@@ -298,8 +293,7 @@ public class Plc4xModbusAdapter implements StreamPipesAdapter, IPullAdapter {
   }
 
   @Override
-  public void onAdapterStopped(IAdapterParameterExtractor extractor, IAdapterRuntimeContext adapterRuntimeContext)
-      throws AdapterException {
+  public void onAdapterStopped(IAdapterParameterExtractor extractor, IAdapterRuntimeContext adapterRuntimeContext) {
     this.pullAdapterScheduler.shutdown();
   }
 
diff --git a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/s7/Plc4xS7Adapter.java b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/s7/Plc4xS7Adapter.java
index 1e98d4e224..2761689b3e 100644
--- a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/s7/Plc4xS7Adapter.java
+++ b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/s7/Plc4xS7Adapter.java
@@ -22,20 +22,21 @@ package org.apache.streampipes.extensions.connectors.plc.adapter.s7;
 import org.apache.streampipes.commons.exceptions.connect.AdapterException;
 import org.apache.streampipes.extensions.api.connect.IAdapterConfiguration;
 import org.apache.streampipes.extensions.api.connect.IEventCollector;
-import org.apache.streampipes.extensions.api.connect.IPullAdapter;
 import org.apache.streampipes.extensions.api.connect.StreamPipesAdapter;
 import org.apache.streampipes.extensions.api.connect.context.IAdapterGuessSchemaContext;
 import org.apache.streampipes.extensions.api.connect.context.IAdapterRuntimeContext;
 import org.apache.streampipes.extensions.api.extractor.IAdapterParameterExtractor;
 import org.apache.streampipes.extensions.api.extractor.IStaticPropertyExtractor;
 import org.apache.streampipes.extensions.connectors.plc.adapter.generic.config.EventSchemaProvider;
-import org.apache.streampipes.extensions.connectors.plc.adapter.generic.connection.PlcEventGenerator;
+import org.apache.streampipes.extensions.connectors.plc.adapter.generic.connection.ContinuousPlcRequestReader;
+import org.apache.streampipes.extensions.connectors.plc.adapter.generic.connection.OneTimePlcRequestReader;
 import org.apache.streampipes.extensions.connectors.plc.adapter.generic.connection.PlcRequestProvider;
+import org.apache.streampipes.extensions.connectors.plc.adapter.generic.model.Plc4xConnectionSettings;
 import org.apache.streampipes.extensions.connectors.plc.adapter.s7.config.ConfigurationParser;
 import org.apache.streampipes.extensions.management.connect.PullAdapterScheduler;
-import org.apache.streampipes.extensions.management.connect.adapter.util.PollingSettings;
 import org.apache.streampipes.model.AdapterType;
 import org.apache.streampipes.model.connect.guess.GuessSchema;
+import org.apache.streampipes.model.extensions.ExtensionAssetType;
 import org.apache.streampipes.model.schema.EventProperty;
 import org.apache.streampipes.model.staticproperty.CollectionStaticProperty;
 import org.apache.streampipes.model.staticproperty.StaticProperty;
@@ -49,31 +50,21 @@ import org.apache.streampipes.sdk.helpers.CodeLanguage;
 import org.apache.streampipes.sdk.helpers.Labels;
 import org.apache.streampipes.sdk.helpers.Locales;
 import org.apache.streampipes.sdk.helpers.Options;
-import org.apache.streampipes.sdk.utils.Assets;
 
-import org.apache.plc4x.java.api.PlcConnection;
-import org.apache.plc4x.java.api.PlcDriverManager;
-import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.api.messages.PlcReadResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.plc4x.java.api.PlcConnectionManager;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
 
-public class Plc4xS7Adapter implements StreamPipesAdapter, IPullAdapter, PlcReadResponseHandler {
+public class Plc4xS7Adapter implements StreamPipesAdapter {
 
   /**
    * A unique id to identify the Plc4xS7Adapter
    */
   public static final String ID = "org.apache.streampipes.connect.iiot.adapters.plc4x.s7";
 
-  private static final Logger LOG = LoggerFactory.getLogger(Plc4xS7Adapter.class);
-
   private static final String S7_URL = "s7://";
 
   /**
@@ -102,124 +93,15 @@ public class Plc4xS7Adapter implements StreamPipesAdapter, IPullAdapter, PlcRead
       // [1] https://plc4x.apache.org/users/protocols/s7.html
       """;
 
-  /**
-   * Values of user configuration parameters
-   */
-  private String ip;
-  private int pollingInterval;
-  private Map<String, String> nodes;
-
-  private PlcDriverManager driverManager;
+  private final PlcConnectionManager connectionManager;
 
   private PullAdapterScheduler pullAdapterScheduler;
 
-  private IEventCollector collector;
-
-  private PlcEventGenerator eventGenerator;
-
   private final PlcRequestProvider requestProvider;
 
-  public Plc4xS7Adapter() {
+  public Plc4xS7Adapter(PlcConnectionManager connectionManager) {
     this.requestProvider = new PlcRequestProvider();
-  }
-
-  /**
-   * This method is executed when the adapter is started. A connection to the PLC is initialized
-   */
-  private void before(IStaticPropertyExtractor extractor) {
-    // Extract user input
-    getConfigurations(extractor);
-
-    this.driverManager = PlcDriverManager.getDefault();
-    try (PlcConnection plcConnection = this.driverManager.getConnectionManager().getConnection(S7_URL + this.ip)) {
-      if (!plcConnection.getMetadata().isReadSupported()) {
-        LOG.error("The S7 on IP: " + this.ip + " does not support reading data");
-      }
-    } catch (PlcConnectionException e) {
-      LOG.error("Could not establish connection to S7 with ip " + this.ip, e);
-    } catch (Exception e) {
-      LOG.error("Could not close connection to S7 with ip " + this.ip, e);
-    }
-  }
-
-
-  /**
-   * pullData is called iteratively according to the polling interval defined in getPollInterval.
-   */
-  @Override
-  public void pullData() {
-    // Create PLC read request
-    try (PlcConnection plcConnection = this.driverManager.getConnectionManager().getConnection(S7_URL + this.ip)) {
-      readPlcData(plcConnection, this);
-    } catch (Exception e) {
-      LOG.error("Error while reading from PLC with IP {} ", this.ip, e);
-    }
-  }
-
-  private void readPlcData(PlcConnection plcConnection, PlcReadResponseHandler handler) {
-    var readRequest = requestProvider.makeReadRequest(plcConnection, this.nodes);
-    // Execute the request
-    CompletableFuture<? extends PlcReadResponse> asyncResponse = readRequest.execute();
-    asyncResponse.whenComplete(handler::onReadResult);
-  }
-
-  private Map<String, Object> readPlcDataSynchronized() throws Exception {
-    try (PlcConnection plcConnection = this.driverManager.getConnectionManager().getConnection(S7_URL + this.ip)) {
-      var readRequest = requestProvider.makeReadRequest(plcConnection, this.nodes);
-      // Execute the request
-      var readResponse = readRequest.execute().get(5000, TimeUnit.MILLISECONDS);
-      return eventGenerator.makeEvent(readResponse);
-    }
-  }
-
-  /**
-   * Define the polling interval of this adapter. Default is to poll every second
-   *
-   * @return PollingSettings
-   */
-  @Override
-  public PollingSettings getPollingInterval() {
-    return PollingSettings.from(TimeUnit.MILLISECONDS, this.pollingInterval);
-  }
-
-  /**
-   * Extracts the user configuration from the SpecificAdapterStreamDescription and sets the local variales
-   *
-   * @param extractor StaticPropertyExtractor
-   */
-  private void getConfigurations(IStaticPropertyExtractor extractor) {
-
-    this.ip = extractor.singleValueParameter(PLC_IP, String.class);
-    this.pollingInterval = extractor.singleValueParameter(PLC_POLLING_INTERVAL, Integer.class);
-
-    this.nodes = new HashMap<>();
-
-    var selectedAlternative = extractor.selectedAlternativeInternalId(PLC_NODE_INPUT_ALTERNATIVES);
-
-    if (selectedAlternative.equals(PLC_NODE_INPUT_COLLECTION_ALTERNATIVE)) {
-      // Alternative Simple
-      var csp = (CollectionStaticProperty) extractor.getStaticPropertyByName(PLC_NODES);
-      this.nodes = getNodeInformationFromCollectionStaticProperty(csp);
-
-    } else {
-      // Alternative Advanced
-      var codePropertyInput = extractor.codeblockValue(PLC_CODE_BLOCK);
-      this.nodes = new ConfigurationParser().getNodeInformationFromCodeProperty(codePropertyInput);
-    }
-    this.eventGenerator = new PlcEventGenerator(this.nodes);
-  }
-
-
-  @Override
-  public void onReadResult(PlcReadResponse response, Throwable throwable) {
-    if (throwable != null) {
-      throwable.printStackTrace();
-      LOG.error(throwable.getMessage());
-    } else {
-      var event = eventGenerator.makeEvent(response);
-      // publish the final event
-      collector.collect(event);
-    }
+    this.connectionManager = connectionManager;
   }
 
   /**
@@ -230,9 +112,9 @@ public class Plc4xS7Adapter implements StreamPipesAdapter, IPullAdapter, PlcRead
    */
   @Override
   public IAdapterConfiguration declareConfig() {
-    return AdapterConfigurationBuilder.create(ID, 1, Plc4xS7Adapter::new)
+    return AdapterConfigurationBuilder.create(ID, 1, () -> new Plc4xS7Adapter(connectionManager))
         .withLocales(Locales.EN)
-        .withAssets(Assets.DOCUMENTATION, Assets.ICON)
+        .withAssets(ExtensionAssetType.DOCUMENTATION, ExtensionAssetType.ICON)
         .withCategory(AdapterType.Manufacturing)
         .requiredTextParameter(Labels.withId(PLC_IP))
         .requiredIntegerParameter(Labels.withId(PLC_POLLING_INTERVAL), 1000)
@@ -255,10 +137,10 @@ public class Plc4xS7Adapter implements StreamPipesAdapter, IPullAdapter, PlcRead
   public void onAdapterStarted(IAdapterParameterExtractor extractor,
                                IEventCollector collector,
                                IAdapterRuntimeContext adapterRuntimeContext) {
-    this.before(extractor.getStaticPropertyExtractor());
-    this.collector = collector;
+    var settings = getConfigurations(extractor.getStaticPropertyExtractor());
+    var plcRequestReader = new ContinuousPlcRequestReader(connectionManager, settings, requestProvider, collector);
     this.pullAdapterScheduler = new PullAdapterScheduler();
-    this.pullAdapterScheduler.schedule(this, extractor.getAdapterDescription().getElementId());
+    this.pullAdapterScheduler.schedule(plcRequestReader, extractor.getAdapterDescription().getElementId());
   }
 
   @Override
@@ -270,19 +152,18 @@ public class Plc4xS7Adapter implements StreamPipesAdapter, IPullAdapter, PlcRead
   @Override
   public GuessSchema onSchemaRequested(IAdapterParameterExtractor extractor,
                                        IAdapterGuessSchemaContext adapterGuessSchemaContext) throws AdapterException {
-    // Extract user input
     try {
-      getConfigurations(extractor.getStaticPropertyExtractor());
+      var settings = getConfigurations(extractor.getStaticPropertyExtractor());
 
-      if (this.pollingInterval < 10) {
-        throw new AdapterException("Polling interval must be higher than 10. Current value: " + this.pollingInterval);
+      if (settings.pollingInterval() < 10) {
+        throw new AdapterException(
+            String.format("Polling interval must be higher than 10. Current value: %s", settings.pollingInterval())
+        );
       }
 
       GuessSchemaBuilder builder = GuessSchemaBuilder.create();
-      List<EventProperty> allProperties = new EventSchemaProvider().makeSchema(this.nodes);
-
-      this.before(extractor.getStaticPropertyExtractor());
-      var event = readPlcDataSynchronized();
+      List<EventProperty> allProperties = new EventSchemaProvider().makeSchema(settings.nodes());
+      var event = new OneTimePlcRequestReader(connectionManager, settings, requestProvider).readPlcDataSynchronized();
 
       builder.properties(allProperties);
       builder.preview(event);
@@ -293,6 +174,34 @@ public class Plc4xS7Adapter implements StreamPipesAdapter, IPullAdapter, PlcRead
     }
   }
 
+  /**
+   * Extracts the user configuration from the SpecificAdapterStreamDescription and sets the local variales
+   *
+   * @param extractor StaticPropertyExtractor
+   */
+  private Plc4xConnectionSettings getConfigurations(IStaticPropertyExtractor extractor) {
+
+    var ip = extractor.singleValueParameter(PLC_IP, String.class);
+    var pollingInterval = extractor.singleValueParameter(PLC_POLLING_INTERVAL, Integer.class);
+
+    Map<String, String> nodes;
+
+    var selectedAlternative = extractor.selectedAlternativeInternalId(PLC_NODE_INPUT_ALTERNATIVES);
+
+    if (selectedAlternative.equals(PLC_NODE_INPUT_COLLECTION_ALTERNATIVE)) {
+      // Alternative Simple
+      var csp = (CollectionStaticProperty) extractor.getStaticPropertyByName(PLC_NODES);
+      nodes = getNodeInformationFromCollectionStaticProperty(csp);
+
+    } else {
+      // Alternative Advanced
+      var codePropertyInput = extractor.codeblockValue(PLC_CODE_BLOCK);
+      nodes = new ConfigurationParser().getNodeInformationFromCodeProperty(codePropertyInput);
+    }
+
+    return new Plc4xConnectionSettings(S7_URL + ip, pollingInterval, nodes);
+  }
+
 
   private Map<String, String> getNodeInformationFromCollectionStaticProperty(CollectionStaticProperty csp) {
     var result = new HashMap<String, String>();
diff --git a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/s7/PlcReadResponseHandler.java b/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/s7/PlcReadResponseHandler.java
deleted file mode 100644
index 2a4a44c762..0000000000
--- a/streampipes-extensions/streampipes-connectors-plc/src/main/java/org/apache/streampipes/extensions/connectors/plc/adapter/s7/PlcReadResponseHandler.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.streampipes.extensions.connectors.plc.adapter.s7;
-
-import org.apache.plc4x.java.api.messages.PlcReadResponse;
-
-public interface PlcReadResponseHandler {
-
-  void onReadResult(PlcReadResponse response,
-                    Throwable throwable);
-}
diff --git a/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java b/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java
index 34ec545b57..66187857a0 100644
--- a/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java
+++ b/streampipes-extensions/streampipes-extensions-all-iiot/src/main/java/org/apache/streampipes/extensions/all/iiot/AllExtensionsIIoTInit.java
@@ -45,14 +45,14 @@ import org.apache.streampipes.processors.enricher.jvm.EnricherExtensionModuleExp
 import org.apache.streampipes.processors.filters.jvm.FilterExtensionModuleExport;
 import org.apache.streampipes.processors.siddhi.SiddhiFilterExtensionModuleExport;
 import org.apache.streampipes.processors.transformation.jvm.TransformationExtensionModuleExport;
-import org.apache.streampipes.service.extensions.ExtensionsModelSubmitter;
+import org.apache.streampipes.service.extensions.StreamPipesExtensionsServiceBase;
 import org.apache.streampipes.sinks.brokers.jvm.BrokerSinksExtensionModuleExport;
 import org.apache.streampipes.sinks.databases.jvm.DatabaseSinksExtensionModuleExport;
 import org.apache.streampipes.sinks.internal.jvm.InternalSinksExtensionModuleExports;
 import org.apache.streampipes.sinks.notifications.jvm.NotificationsExtensionModuleExport;
 import org.apache.streampipes.wrapper.standalone.runtime.StandaloneStreamPipesRuntimeProvider;
 
-public class AllExtensionsIIoTInit extends ExtensionsModelSubmitter {
+public class AllExtensionsIIoTInit extends StreamPipesExtensionsServiceBase {
 
   public static void main(String[] args) {
     new AllExtensionsIIoTInit().init();
diff --git a/streampipes-extensions/streampipes-extensions-all-jvm/src/main/java/org/apache/streampipes/extensions/all/jvm/AllExtensionsInit.java b/streampipes-extensions/streampipes-extensions-all-jvm/src/main/java/org/apache/streampipes/extensions/all/jvm/AllExtensionsInit.java
index d5b9bf6f92..19c7e551c1 100644
--- a/streampipes-extensions/streampipes-extensions-all-jvm/src/main/java/org/apache/streampipes/extensions/all/jvm/AllExtensionsInit.java
+++ b/streampipes-extensions/streampipes-extensions-all-jvm/src/main/java/org/apache/streampipes/extensions/all/jvm/AllExtensionsInit.java
@@ -48,7 +48,7 @@ import org.apache.streampipes.processors.imageprocessing.jvm.ImageProcessingExte
 import org.apache.streampipes.processors.siddhi.SiddhiFilterExtensionModuleExport;
 import org.apache.streampipes.processors.textmining.jvm.TextMiningExtensionModuleExport;
 import org.apache.streampipes.processors.transformation.jvm.TransformationExtensionModuleExport;
-import org.apache.streampipes.service.extensions.ExtensionsModelSubmitter;
+import org.apache.streampipes.service.extensions.StreamPipesExtensionsServiceBase;
 import org.apache.streampipes.sinks.brokers.jvm.BrokerSinksExtensionModuleExport;
 import org.apache.streampipes.sinks.databases.jvm.DatabaseSinksExtensionModuleExport;
 import org.apache.streampipes.sinks.internal.jvm.InternalSinksExtensionModuleExports;
@@ -56,7 +56,7 @@ import org.apache.streampipes.sinks.notifications.jvm.NotificationsExtensionModu
 import org.apache.streampipes.wrapper.standalone.runtime.StandaloneStreamPipesRuntimeProvider;
 
 
-public class AllExtensionsInit extends ExtensionsModelSubmitter {
+public class AllExtensionsInit extends StreamPipesExtensionsServiceBase {
 
   public static void main(String[] args) {
     new AllExtensionsInit().init();
diff --git a/streampipes-extensions/streampipes-extensions-iiot-minimal/src/main/java/org/apache/streampipes/extensions/iiot/minimal/ExtensionsIIoTMinimalInit.java b/streampipes-extensions/streampipes-extensions-iiot-minimal/src/main/java/org/apache/streampipes/extensions/iiot/minimal/ExtensionsIIoTMinimalInit.java
index e609b018c7..80db365175 100644
--- a/streampipes-extensions/streampipes-extensions-iiot-minimal/src/main/java/org/apache/streampipes/extensions/iiot/minimal/ExtensionsIIoTMinimalInit.java
+++ b/streampipes-extensions/streampipes-extensions-iiot-minimal/src/main/java/org/apache/streampipes/extensions/iiot/minimal/ExtensionsIIoTMinimalInit.java
@@ -37,14 +37,14 @@ import org.apache.streampipes.processors.enricher.jvm.EnricherExtensionModuleExp
 import org.apache.streampipes.processors.filters.jvm.FilterExtensionModuleExport;
 import org.apache.streampipes.processors.siddhi.SiddhiFilterExtensionModuleExport;
 import org.apache.streampipes.processors.transformation.jvm.TransformationExtensionModuleExport;
-import org.apache.streampipes.service.extensions.ExtensionsModelSubmitter;
+import org.apache.streampipes.service.extensions.StreamPipesExtensionsServiceBase;
 import org.apache.streampipes.sinks.brokers.jvm.BrokerSinksExtensionModuleExport;
 import org.apache.streampipes.sinks.databases.jvm.DatabaseSinksExtensionModuleExport;
 import org.apache.streampipes.sinks.internal.jvm.InternalSinksExtensionModuleExports;
 import org.apache.streampipes.sinks.notifications.jvm.NotificationsExtensionModuleExport;
 import org.apache.streampipes.wrapper.standalone.runtime.StandaloneStreamPipesRuntimeProvider;
 
-public class ExtensionsIIoTMinimalInit extends ExtensionsModelSubmitter {
+public class ExtensionsIIoTMinimalInit extends StreamPipesExtensionsServiceBase {
 
   public static void main(String[] args) {
     new ExtensionsIIoTMinimalInit().init();
diff --git a/streampipes-extensions/streampipes-pipeline-elements-experimental-flink/src/main/java/org/apache/streampipes/pe/flink/AllFlinkPipelineElementsInit.java b/streampipes-extensions/streampipes-pipeline-elements-experimental-flink/src/main/java/org/apache/streampipes/pe/flink/AllFlinkPipelineElementsInit.java
index 47e568367f..033e658399 100644
--- a/streampipes-extensions/streampipes-pipeline-elements-experimental-flink/src/main/java/org/apache/streampipes/pe/flink/AllFlinkPipelineElementsInit.java
+++ b/streampipes-extensions/streampipes-pipeline-elements-experimental-flink/src/main/java/org/apache/streampipes/pe/flink/AllFlinkPipelineElementsInit.java
@@ -47,11 +47,11 @@ import org.apache.streampipes.pe.flink.processor.timestamp.TimestampController;
 import org.apache.streampipes.pe.flink.processor.urldereferencing.UrlDereferencingController;
 import org.apache.streampipes.pe.flink.processor.wordcount.WordCountController;
 import org.apache.streampipes.pe.flink.sink.elasticsearch.ElasticSearchController;
-import org.apache.streampipes.service.extensions.ExtensionsModelSubmitter;
+import org.apache.streampipes.service.extensions.StreamPipesExtensionsServiceBase;
 import org.apache.streampipes.wrapper.flink.FlinkRuntimeProvider;
 
 
-public class AllFlinkPipelineElementsInit extends ExtensionsModelSubmitter {
+public class AllFlinkPipelineElementsInit extends StreamPipesExtensionsServiceBase {
 
   public static void main(String[] args) {
     new AllFlinkPipelineElementsInit().init();
diff --git a/streampipes-maven-plugin/README.md b/streampipes-maven-plugin/README.md
index 70c9fffb5b..6e1ea1b260 100644
--- a/streampipes-maven-plugin/README.md
+++ b/streampipes-maven-plugin/README.md
@@ -31,7 +31,7 @@ The streampipes-maven-plugin can either be started from the command line or embe
 
 ### Prerequisites
 
-The plugin must be started from a module which contains an `Init` class which inherits `ExtensionsModelSubmitter`.
+The plugin must be started from a module which contains an `Init` class which inherits `StreamPipesExtensionsServiceBase`.
 By default, the goal runs in the `package` phase.
 
 ### Command line
diff --git a/streampipes-maven-plugin/pom.xml b/streampipes-maven-plugin/pom.xml
index cae67d384e..95cb99b4c1 100644
--- a/streampipes-maven-plugin/pom.xml
+++ b/streampipes-maven-plugin/pom.xml
@@ -39,7 +39,7 @@
         <maven-clean-plugin.version>3.3.2</maven-clean-plugin.version>
         <maven-deploy-plugin.version>3.1.0</maven-deploy-plugin.version>
         <maven-install-plugin.version>3.1.1</maven-install-plugin.version>
-        <maven-invoker-plugin.version>3.6.0</maven-invoker-plugin.version>
+        <maven-invoker-plugin.version>3.7.0</maven-invoker-plugin.version>
         <maven-jar-plugin.version>3.4.0</maven-jar-plugin.version>
         <maven-plugin-plugin.version>3.13.0</maven-plugin-plugin.version>
         <maven-resources-plugin.version>3.3.0</maven-resources-plugin.version>
diff --git a/streampipes-maven-plugin/src/main/java/org/apache/streampipes/smp/extractor/ExtensionsFinder.java b/streampipes-maven-plugin/src/main/java/org/apache/streampipes/smp/extractor/ExtensionsFinder.java
index b36abb767b..c1ac981bb4 100644
--- a/streampipes-maven-plugin/src/main/java/org/apache/streampipes/smp/extractor/ExtensionsFinder.java
+++ b/streampipes-maven-plugin/src/main/java/org/apache/streampipes/smp/extractor/ExtensionsFinder.java
@@ -23,7 +23,7 @@ import org.apache.streampipes.extensions.api.pe.config.IDataProcessorConfigurati
 import org.apache.streampipes.extensions.api.pe.config.IDataSinkConfiguration;
 import org.apache.streampipes.extensions.api.pe.config.IPipelineElementConfiguration;
 import org.apache.streampipes.extensions.management.model.SpServiceDefinition;
-import org.apache.streampipes.service.extensions.ExtensionsModelSubmitter;
+import org.apache.streampipes.service.extensions.StreamPipesExtensionsServiceBase;
 import org.apache.streampipes.smp.constants.PeType;
 import org.apache.streampipes.smp.model.AssetModel;
 
@@ -39,17 +39,23 @@ public class ExtensionsFinder {
   private final ClassLoader loader;
   private final String initClass;
 
-  public ExtensionsFinder(ClassLoader loader,
-                          String initClass) {
+  public ExtensionsFinder(
+      ClassLoader loader,
+      String initClass
+  ) {
     this.loader = loader;
     this.initClass = initClass;
   }
 
   public List<AssetModel> findExtensions()
       throws MalformedURLException, DependencyResolutionRequiredException, ClassNotFoundException,
-      InstantiationException, IllegalAccessException {
+             InstantiationException, IllegalAccessException {
     var extensions = new ArrayList<AssetModel>();
-    var serviceDef = ((ExtensionsModelSubmitter) loader.loadClass(initClass).newInstance()).provideServiceDefinition();
+    var serviceDef = (
+        (StreamPipesExtensionsServiceBase) loader
+            .loadClass(initClass)
+            .newInstance()
+    ).provideServiceDefinition();
 
     extensions.addAll(findAdapters(serviceDef));
     extensions.addAll(findPipelineElements(serviceDef, IDataProcessorConfiguration.class, PeType.PROCESSOR));
@@ -58,20 +64,28 @@ public class ExtensionsFinder {
     return extensions;
   }
 
-  private List<AssetModel> findPipelineElements(SpServiceDefinition serviceDef,
-                                                Class<? extends IPipelineElementConfiguration<?, ?>> configType,
-                                                PeType peType) {
+  private List<AssetModel> findPipelineElements(
+      SpServiceDefinition serviceDef,
+      Class<? extends IPipelineElementConfiguration<?, ?>> configType,
+      PeType peType
+  ) {
     return serviceDef.getDeclarers()
-        .stream()
-        .map(IStreamPipesPipelineElement::declareConfig)
-        .filter(configType::isInstance)
-        .map(config -> new AssetModel(config.getDescription().getAppId(), peType)).toList();
+                     .stream()
+                     .map(IStreamPipesPipelineElement::declareConfig)
+                     .filter(configType::isInstance)
+                     .map(config -> new AssetModel(config.getDescription()
+                                                         .getAppId(), peType))
+                     .toList();
   }
 
   private Collection<? extends AssetModel> findAdapters(SpServiceDefinition serviceDef) {
-    return serviceDef.getAdapters().stream().map(adapter -> {
-      var config = adapter.declareConfig();
-      return new AssetModel(config.getAdapterDescription().getAppId(), PeType.ADAPTER);
-    }).toList();
+    return serviceDef.getAdapters()
+                     .stream()
+                     .map(adapter -> {
+                       var config = adapter.declareConfig();
+                       return new AssetModel(config.getAdapterDescription()
+                                                   .getAppId(), PeType.ADAPTER);
+                     })
+                     .toList();
   }
 }
diff --git a/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/ExtensionsModelSubmitter.java b/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/ExtensionsModelSubmitter.java
deleted file mode 100644
index 29b60bd186..0000000000
--- a/streampipes-service-extensions/src/main/java/org/apache/streampipes/service/extensions/ExtensionsModelSubmitter.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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.streampipes.service.extensions;
-
-/**
- * @deprecated Use {@link StreamPipesExtensionsServiceBase} instead
- */
-@Deprecated(forRemoval = true, since = "0.95.0")
-public abstract class ExtensionsModelSubmitter extends StreamPipesExtensionsServiceBase {
-}


Test patch:
diff --git a/streampipes-extensions/streampipes-connectors-plc/src/test/java/org/apache/streampipes/extensions/connectors/plc/adapter/migration/config/Plc4xModbusAdapterVersionedConfig.java b/streampipes-extensions/streampipes-connectors-plc/src/test/java/org/apache/streampipes/extensions/connectors/plc/adapter/migration/config/Plc4xModbusAdapterVersionedConfig.java
index 11509f5d5d..d88fbbb923 100644
--- a/streampipes-extensions/streampipes-connectors-plc/src/test/java/org/apache/streampipes/extensions/connectors/plc/adapter/migration/config/Plc4xModbusAdapterVersionedConfig.java
+++ b/streampipes-extensions/streampipes-connectors-plc/src/test/java/org/apache/streampipes/extensions/connectors/plc/adapter/migration/config/Plc4xModbusAdapterVersionedConfig.java
@@ -21,12 +21,12 @@ package org.apache.streampipes.extensions.connectors.plc.adapter.migration.confi
 import org.apache.streampipes.extensions.connectors.plc.adapter.modbus.Plc4xModbusAdapter;
 import org.apache.streampipes.model.AdapterType;
 import org.apache.streampipes.model.connect.adapter.AdapterDescription;
+import org.apache.streampipes.model.extensions.ExtensionAssetType;
 import org.apache.streampipes.sdk.StaticProperties;
 import org.apache.streampipes.sdk.builder.adapter.AdapterConfigurationBuilder;
 import org.apache.streampipes.sdk.helpers.Labels;
 import org.apache.streampipes.sdk.helpers.Locales;
 import org.apache.streampipes.sdk.helpers.Options;
-import org.apache.streampipes.sdk.utils.Assets;
 
 import static org.apache.streampipes.extensions.connectors.plc.adapter.modbus.Plc4xModbusAdapter.ID;
 import static org.apache.streampipes.extensions.connectors.plc.adapter.modbus.Plc4xModbusAdapter.PLC_IP;
@@ -40,9 +40,9 @@ import static org.apache.streampipes.extensions.connectors.plc.adapter.modbus.Pl
 public class Plc4xModbusAdapterVersionedConfig {
 
   public static AdapterDescription getPlc4xModbusAdapterDescriptionV0() {
-    return AdapterConfigurationBuilder.create(ID, 0, Plc4xModbusAdapter::new)
+    return AdapterConfigurationBuilder.create(ID, 0, () -> new Plc4xModbusAdapter(null))
                                       .withLocales(Locales.EN)
-                                      .withAssets(Assets.DOCUMENTATION, Assets.ICON)
+                                      .withAssets(ExtensionAssetType.DOCUMENTATION, ExtensionAssetType.ICON)
                                       .withCategory(AdapterType.Manufacturing)
                                       .requiredTextParameter(Labels.withId(PLC_IP))
                                       .requiredTextParameter(Labels.withId(PLC_PORT))