You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by jf...@apache.org on 2019/04/21 11:52:49 UTC

[incubator-plc4x] branch feature/PLC4X-111-interop-server updated (2d24599 -> 87ddc84)

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

jfeinauer pushed a change to branch feature/PLC4X-111-interop-server
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git.


    from 2d24599  PLC4X-111 Add initial implementation of the interop server.
     new 11b7f14  PLC4X-111 Imported Python support for the Interop Server. Currently possible for S7.
     new 87ddc84  PLC4X-111 Added Readme and renamed the INIT Script.

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


Summary of changes:
 plc4j/utils/interop/pom.xml                        |  63 ++-
 .../org/apache/plc4x/interop/impl/Handler.java     |   6 +-
 .../java/org/apache/plc4x/interop/impl/Server.java |  58 +-
 plc4py/README.md                                   |  38 ++
 .../gen-py/org/apache/plc4x => plc4py}/__init__.py |   0
 plc4py/generate_thrift.sh                          |   8 +
 plc4py/initialize_interop_server.sh                |   7 +
 plc4py/lib/log4j2.xml                              |  13 +
 .../org/apache/plc4x => plc4py/org}/__init__.py    |   0
 .../apache/plc4x => plc4py/org/apache}/__init__.py |   0
 plc4py/org/apache/plc4x/InteropClient.py           |  29 +
 plc4py/org/apache/plc4x/PlcConnection.py           |  58 ++
 plc4py/org/apache/plc4x/PlcDriverManager.py        |  62 +++
 .../gen-py => plc4py}/org/apache/plc4x/__init__.py |   0
 .../org/apache/plc4x/interop/InteropServer-remote  |  99 ++++
 plc4py/org/apache/plc4x/interop/InteropServer.py   | 593 +++++++++++++++++++++
 .../org/apache/plc4x/interop/__init__.py           |   0
 plc4py/org/apache/plc4x/interop/constants.py       |   9 +
 plc4py/org/apache/plc4x/interop/ttypes.py          | 429 +++++++++++++++
 .../org/apache/plc4x => plc4py/test}/__init__.py   |   0
 plc4py/test/test_PlcDriverManager.py               |  95 ++++
 21 files changed, 1529 insertions(+), 38 deletions(-)
 create mode 100644 plc4py/README.md
 copy {plc4j/utils/interop/src/main/thrift/gen-py/org/apache/plc4x => plc4py}/__init__.py (100%)
 create mode 100644 plc4py/generate_thrift.sh
 create mode 100755 plc4py/initialize_interop_server.sh
 create mode 100644 plc4py/lib/log4j2.xml
 copy {plc4j/utils/interop/src/main/thrift/gen-py/org/apache/plc4x => plc4py/org}/__init__.py (100%)
 copy {plc4j/utils/interop/src/main/thrift/gen-py/org/apache/plc4x => plc4py/org/apache}/__init__.py (100%)
 create mode 100644 plc4py/org/apache/plc4x/InteropClient.py
 create mode 100644 plc4py/org/apache/plc4x/PlcConnection.py
 create mode 100644 plc4py/org/apache/plc4x/PlcDriverManager.py
 copy {plc4j/utils/interop/src/main/thrift/gen-py => plc4py}/org/apache/plc4x/__init__.py (100%)
 create mode 100755 plc4py/org/apache/plc4x/interop/InteropServer-remote
 create mode 100644 plc4py/org/apache/plc4x/interop/InteropServer.py
 copy {plc4j/utils/interop/src/main/thrift/gen-py => plc4py}/org/apache/plc4x/interop/__init__.py (100%)
 create mode 100644 plc4py/org/apache/plc4x/interop/constants.py
 create mode 100644 plc4py/org/apache/plc4x/interop/ttypes.py
 copy {plc4j/utils/interop/src/main/thrift/gen-py/org/apache/plc4x => plc4py/test}/__init__.py (100%)
 create mode 100644 plc4py/test/test_PlcDriverManager.py


[incubator-plc4x] 01/02: PLC4X-111 Imported Python support for the Interop Server. Currently possible for S7.

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

jfeinauer pushed a commit to branch feature/PLC4X-111-interop-server
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git

commit 11b7f14f905c42a506de99c0e12defd82cbe6863
Author: julian <j....@pragmaticminds.de>
AuthorDate: Sun Apr 21 13:45:50 2019 +0200

    PLC4X-111 Imported Python support for the Interop Server. Currently possible for S7.
---
 plc4j/utils/interop/pom.xml                        |  63 ++-
 .../org/apache/plc4x/interop/impl/Handler.java     |   6 +-
 .../java/org/apache/plc4x/interop/impl/Server.java |  58 +-
 plc4py/__init__.py                                 |   0
 plc4py/copy_server.sh                              |   4 +
 plc4py/generate_thrift.sh                          |   8 +
 plc4py/lib/log4j2.xml                              |  13 +
 plc4py/org/__init__.py                             |   0
 plc4py/org/apache/__init__.py                      |   0
 plc4py/org/apache/plc4x/InteropClient.py           |  29 +
 plc4py/org/apache/plc4x/PlcConnection.py           |  58 ++
 plc4py/org/apache/plc4x/PlcDriverManager.py        |  62 +++
 plc4py/org/apache/plc4x/__init__.py                |   0
 .../org/apache/plc4x/interop/InteropServer-remote  |  99 ++++
 plc4py/org/apache/plc4x/interop/InteropServer.py   | 593 +++++++++++++++++++++
 plc4py/org/apache/plc4x/interop/__init__.py        |   1 +
 plc4py/org/apache/plc4x/interop/constants.py       |   9 +
 plc4py/org/apache/plc4x/interop/ttypes.py          | 429 +++++++++++++++
 plc4py/test/__init__.py                            |   0
 plc4py/test/test_PlcDriverManager.py               |  95 ++++
 20 files changed, 1489 insertions(+), 38 deletions(-)

diff --git a/plc4j/utils/interop/pom.xml b/plc4j/utils/interop/pom.xml
index 41136de..7aa8957 100644
--- a/plc4j/utils/interop/pom.xml
+++ b/plc4j/utils/interop/pom.xml
@@ -21,26 +21,73 @@
       <groupId>org.apache.plc4x</groupId>
       <artifactId>plc4j-api</artifactId>
       <version>0.4.0-SNAPSHOT</version>
-      <scope>compile</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.plc4x</groupId>
-      <artifactId>plc4j-protocol-driver-base-test</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
     </dependency>
+<!--    <dependency>-->
+<!--      <groupId>org.apache.plc4x</groupId>-->
+<!--      <artifactId>plc4j-protocol-driver-base-test</artifactId>-->
+<!--      <version>0.4.0-SNAPSHOT</version>-->
+<!--    </dependency>-->
     <dependency>
       <groupId>org.apache.plc4x</groupId>
       <artifactId>plc4j-driver-s7</artifactId>
       <version>0.4.0-SNAPSHOT</version>
-      <scope>runtime</scope>
+      <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>commons-lang</groupId>
       <artifactId>commons-lang</artifactId>
       <version>20030203.000129</version>
-      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <version>2.11.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <version>2.11.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <version>2.11.2</version>
     </dependency>
   </dependencies>
 
+  <build>
+    <plugins>
+      <!-- Create a fat jar -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.4.1</version>
+        <configuration>
+          <!-- get all project dependencies -->
+          <descriptorRefs>
+            <descriptorRef>jar-with-dependencies</descriptorRef>
+          </descriptorRefs>
+          <!-- MainClass in mainfest make a executable jar -->
+          <archive>
+            <manifest>
+              <mainClass>org.apache.plc4x.interop.impl.Server</mainClass>
+            </manifest>
+          </archive>
+
+        </configuration>
+        <executions>
+          <execution>
+            <id>make-assembly</id>
+            <!-- bind to the packaging phase -->
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
 
 </project>
\ No newline at end of file
diff --git a/plc4j/utils/interop/src/main/java/org/apache/plc4x/interop/impl/Handler.java b/plc4j/utils/interop/src/main/java/org/apache/plc4x/interop/impl/Handler.java
index 02ed94d..7d1e111 100644
--- a/plc4j/utils/interop/src/main/java/org/apache/plc4x/interop/impl/Handler.java
+++ b/plc4j/utils/interop/src/main/java/org/apache/plc4x/interop/impl/Handler.java
@@ -63,11 +63,15 @@ public class Handler implements InteropServer.Iface {
 
     @Override public void close(ConnectionHandle handle) throws TException {
         LOGGER.debug("Receiving new close request for handle {}", handle.getConnectionId());
+        if (!connections.containsKey(handle)) {
+            LOGGER.warn("Handle for close request {} does not exist. Perhaps already closed?", handle.getConnectionId());
+            return;
+        }
         try {
             connections.get(handle).close();
             connections.remove(handle);
         } catch (Exception e) {
-            e.printStackTrace();
+            LOGGER.warn("Unable to close the conn / remove the handle", e);
         }
 
     }
diff --git a/plc4j/utils/interop/src/main/java/org/apache/plc4x/interop/impl/Server.java b/plc4j/utils/interop/src/main/java/org/apache/plc4x/interop/impl/Server.java
index 01274ae..e697c2b 100644
--- a/plc4j/utils/interop/src/main/java/org/apache/plc4x/interop/impl/Server.java
+++ b/plc4j/utils/interop/src/main/java/org/apache/plc4x/interop/impl/Server.java
@@ -10,8 +10,8 @@ import org.apache.plc4x.java.api.model.PlcSubscriptionHandle;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
 import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem;
 import org.apache.plc4x.java.base.messages.items.DefaultLongFieldItem;
-import org.apache.plc4x.java.mock.MockDevice;
-import org.apache.plc4x.java.mock.PlcMockConnection;
+//import org.apache.plc4x.java.mock.MockDevice;
+//import org.apache.plc4x.java.mock.PlcMockConnection;
 import org.apache.thrift.server.TServer;
 import org.apache.thrift.server.TSimpleServer;
 import org.apache.thrift.transport.TServerSocket;
@@ -26,9 +26,9 @@ public class Server {
         final PlcDriverManager driverManager = new PlcDriverManager();
 
         // Do some mocking
-        final PlcMockConnection mockConnection = (PlcMockConnection) driverManager.getConnection("mock:a");
+//        final PlcMockConnection mockConnection = (PlcMockConnection) driverManager.getConnection("mock:a");
 
-        mockConnection.setDevice(new MyMockDevice());
+//        mockConnection.setDevice(new MyMockDevice());
 
         final Handler handler = new Handler(driverManager);
         final InteropServer.Processor<Handler> processor = new InteropServer.Processor<>(handler);
@@ -44,29 +44,29 @@ public class Server {
         }
     }
 
-    private static class MyMockDevice implements MockDevice {
-        @Override public Pair<PlcResponseCode, BaseDefaultFieldItem> read(String fieldQuery) {
-            return Pair.of(PlcResponseCode.OK, new DefaultLongFieldItem(100L));
-        }
-
-        @Override public PlcResponseCode write(String fieldQuery, Object value) {
-            return null;
-        }
-
-        @Override public Pair<PlcResponseCode, PlcSubscriptionHandle> subscribe(String fieldQuery) {
-            return null;
-        }
-
-        @Override public void unsubscribe() {
-
-        }
-
-        @Override public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer, Collection<PlcSubscriptionHandle> handles) {
-            return null;
-        }
-
-        @Override public void unregister(PlcConsumerRegistration registration) {
-
-        }
-    }
+//    private static class MyMockDevice implements MockDevice {
+//        @Override public Pair<PlcResponseCode, BaseDefaultFieldItem> read(String fieldQuery) {
+//            return Pair.of(PlcResponseCode.OK, new DefaultLongFieldItem(100L));
+//        }
+//
+//        @Override public PlcResponseCode write(String fieldQuery, Object value) {
+//            return null;
+//        }
+//
+//        @Override public Pair<PlcResponseCode, PlcSubscriptionHandle> subscribe(String fieldQuery) {
+//            return null;
+//        }
+//
+//        @Override public void unsubscribe() {
+//
+//        }
+//
+//        @Override public PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer, Collection<PlcSubscriptionHandle> handles) {
+//            return null;
+//        }
+//
+//        @Override public void unregister(PlcConsumerRegistration registration) {
+//
+//        }
+//    }
 }
diff --git a/plc4py/__init__.py b/plc4py/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/plc4py/copy_server.sh b/plc4py/copy_server.sh
new file mode 100755
index 0000000..57f7f27
--- /dev/null
+++ b/plc4py/copy_server.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+# Moves the server from the target folder here
+cp ../plc4j/utils/interop/target/apache-plc4x-incubating-* lib/
\ No newline at end of file
diff --git a/plc4py/generate_thrift.sh b/plc4py/generate_thrift.sh
new file mode 100644
index 0000000..d687fa7
--- /dev/null
+++ b/plc4py/generate_thrift.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+# Requires thrift 0.12.0
+# Generates the "generated" files in the right dir structure
+
+# Please be cautious with this, as there was some manual fixing necessary to get everything running (for me at least)
+
+thrift --gen py:python3 -out ./ ../plc4j/utils/interop/src/main/thrift/interop.thrift
\ No newline at end of file
diff --git a/plc4py/lib/log4j2.xml b/plc4py/lib/log4j2.xml
new file mode 100644
index 0000000..c537397
--- /dev/null
+++ b/plc4py/lib/log4j2.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Root level="WARN">
+            <AppenderRef ref="Console"/>
+        </Root>
+    </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/plc4py/org/__init__.py b/plc4py/org/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/plc4py/org/apache/__init__.py b/plc4py/org/apache/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/plc4py/org/apache/plc4x/InteropClient.py b/plc4py/org/apache/plc4x/InteropClient.py
new file mode 100644
index 0000000..6ac1073
--- /dev/null
+++ b/plc4py/org/apache/plc4x/InteropClient.py
@@ -0,0 +1,29 @@
+from thrift.protocol import TBinaryProtocol
+from thrift.transport import TSocket, TTransport
+from thrift.transport.TTransport import TTransportException
+
+from org.apache.plc4x.interop.InteropServer import Client, PlcException
+from org.apache.plc4x.interop.ttypes import Request
+
+transport = TSocket.TSocket('localhost', 9090)
+transport = TTransport.TBufferedTransport(transport)
+protocol = TBinaryProtocol.TBinaryProtocol(transport)
+
+client = Client(protocol)
+
+try:
+    transport.open()
+    connect = None
+    try:
+        connect = client.connect("mock:a")
+
+        res = client.execute(connect, Request(fields={"field1": "asdf"}))
+
+        print(res)
+    finally:
+        if connect is not None:
+            client.close(connect)
+except TTransportException:
+    print("Unable to connect to the Interop Server, is the Server really running???")
+finally:
+    transport.close()
diff --git a/plc4py/org/apache/plc4x/PlcConnection.py b/plc4py/org/apache/plc4x/PlcConnection.py
new file mode 100644
index 0000000..010187e
--- /dev/null
+++ b/plc4py/org/apache/plc4x/PlcConnection.py
@@ -0,0 +1,58 @@
+from org.apache.plc4x.interop.ttypes import PlcException, FieldResponse
+
+
+class PlcConnection:
+
+    def __init__(self, client, url):
+        self.client = client
+        # Try to get a handle
+        try:
+            self.handle = self.client.connect(url)
+        except:
+            raise PlcException("Unable to connect to the given url " + url)
+
+    def execute(self, request):
+        response = self.client.execute(self.handle, request)
+        return PlcResponse(response)
+
+    def close(self):
+        self.client.close(self.handle)
+
+
+class PlcResponse:
+    fields: dict
+
+    def __init__(self, response):
+        self.fields = response.fields
+
+    def get_fields(self):
+        return list(self.fields.keys())
+
+    def get_field(self, field_name):
+        if field_name in self.fields:
+            return PlcResponseItem(self.fields.get(field_name))
+        else:
+            raise Exception("A field with name '" + field_name + "' is not contained in the response");
+
+
+class PlcResponseItem:
+
+    fieldResponse: FieldResponse
+
+    def __init__(self, fieldResponse):
+        self.fieldResponse = fieldResponse
+
+    def get_response_code(self):
+        return self.fieldResponse.responseCode
+
+    def get_int_value(self):
+        return self.fieldResponse.longValue
+
+    def get_bool_value(self):
+        return self.fieldResponse.boolValue
+
+    def get_double_value(self):
+        return self.fieldResponse.doubleValue
+
+    def get_string_value(self):
+        return self.fieldResponse.stringValue
\ No newline at end of file
diff --git a/plc4py/org/apache/plc4x/PlcDriverManager.py b/plc4py/org/apache/plc4x/PlcDriverManager.py
new file mode 100644
index 0000000..14557fc
--- /dev/null
+++ b/plc4py/org/apache/plc4x/PlcDriverManager.py
@@ -0,0 +1,62 @@
+import subprocess
+import time
+import warnings
+
+from thrift.protocol import TBinaryProtocol
+from thrift.transport import TSocket, TTransport
+from thrift.transport.TTransport import TTransportException
+
+from org.apache.plc4x.PlcConnection import PlcConnection
+from org.apache.plc4x.interop.InteropServer import Client, PlcException
+
+
+class PlcDriverManager:
+
+    """
+    constructor, initialize the server
+    """
+    def __init__(self, embedded_server=True):
+        self.embedded_server = embedded_server
+        # Start the Server in the background
+        if embedded_server:
+            self.interop_proc = subprocess.Popen(
+                ["java", "-Dlog4j.configurationFile=../lib/log4j2.xml",
+                 "-jar", "../lib/apache-plc4x-incubating-0.4.0-SNAPSHOT-jar-with-dependencies.jar"])
+            try:
+                print("Started server under pid " + str(self.interop_proc.pid))
+            except:
+                print("Encountered an Exception while starting Interop Server")
+                raise PlcException("Unable to start the Interop Server!")
+
+            time.sleep(2)
+            poll = self.interop_proc.poll()
+            if poll is None:
+                print("Sucesfully started the Interop Server...")
+            else:
+                warnings.warn("Interop Server died after starting up...")
+                raise PlcException(
+                    "Unable to start the Interop Server. Is another Server still running under the same port?")
+
+        self.transport = TSocket.TSocket('localhost', 9090)
+        self.transport = TTransport.TBufferedTransport(self.transport)
+
+        self.protocol = TBinaryProtocol.TBinaryProtocol(self.transport)
+
+        try:
+            self.transport.open()
+        except TTransportException:
+            raise PlcException("Unable to connect to the Interop Server, is the Server really running???")
+
+    def _get_client(self):
+        return Client(self.protocol)
+
+    def get_connection(self, url):
+        return PlcConnection(self._get_client(), url)
+
+    def close(self):
+        print("Closing the Interop Server")
+        try:
+            self.transport.close()
+        finally:
+            if self.embedded_server:
+                self.interop_proc.terminate()
diff --git a/plc4py/org/apache/plc4x/__init__.py b/plc4py/org/apache/plc4x/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/plc4py/org/apache/plc4x/interop/InteropServer-remote b/plc4py/org/apache/plc4x/interop/InteropServer-remote
new file mode 100755
index 0000000..1f8f8c2
--- /dev/null
+++ b/plc4py/org/apache/plc4x/interop/InteropServer-remote
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+#
+# Autogenerated by Thrift Compiler (0.7.0)
+#
+# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+#
+
+import sys
+import pprint
+from urlparse import urlparse
+from thrift.transport import TTransport
+from thrift.transport import TSocket
+from thrift.transport import THttpClient
+from thrift.protocol import TBinaryProtocol
+
+import InteropServer
+from ttypes import *
+
+if len(sys.argv) <= 1 or sys.argv[1] == '--help':
+  print ''
+  print 'Usage: ' + sys.argv[0] + ' [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]'
+  print ''
+  print 'Functions:'
+  print '  ConnectionHandle connect(string connectionString)'
+  print '  Response execute(ConnectionHandle handle, Request request)'
+  print '  void close(ConnectionHandle handle)'
+  print ''
+  sys.exit(0)
+
+pp = pprint.PrettyPrinter(indent = 2)
+host = 'localhost'
+port = 9090
+uri = ''
+framed = False
+http = False
+argi = 1
+
+if sys.argv[argi] == '-h':
+  parts = sys.argv[argi+1].split(':')
+  host = parts[0]
+  port = int(parts[1])
+  argi += 2
+
+if sys.argv[argi] == '-u':
+  url = urlparse(sys.argv[argi+1])
+  parts = url[1].split(':')
+  host = parts[0]
+  if len(parts) > 1:
+    port = int(parts[1])
+  else:
+    port = 80
+  uri = url[2]
+  if url[4]:
+    uri += '?%s' % url[4]
+  http = True
+  argi += 2
+
+if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':
+  framed = True
+  argi += 1
+
+cmd = sys.argv[argi]
+args = sys.argv[argi+1:]
+
+if http:
+  transport = THttpClient.THttpClient(host, port, uri)
+else:
+  socket = TSocket.TSocket(host, port)
+  if framed:
+    transport = TTransport.TFramedTransport(socket)
+  else:
+    transport = TTransport.TBufferedTransport(socket)
+protocol = TBinaryProtocol.TBinaryProtocol(transport)
+client = InteropServer.Client(protocol)
+transport.open()
+
+if cmd == 'connect':
+  if len(args) != 1:
+    print 'connect requires 1 args'
+    sys.exit(1)
+  pp.pprint(client.connect(args[0],))
+
+elif cmd == 'execute':
+  if len(args) != 2:
+    print 'execute requires 2 args'
+    sys.exit(1)
+  pp.pprint(client.execute(eval(args[0]),eval(args[1]),))
+
+elif cmd == 'close':
+  if len(args) != 1:
+    print 'close requires 1 args'
+    sys.exit(1)
+  pp.pprint(client.close(eval(args[0]),))
+
+else:
+  print 'Unrecognized method %s' % cmd
+  sys.exit(1)
+
+transport.close()
diff --git a/plc4py/org/apache/plc4x/interop/InteropServer.py b/plc4py/org/apache/plc4x/interop/InteropServer.py
new file mode 100644
index 0000000..a1d646e
--- /dev/null
+++ b/plc4py/org/apache/plc4x/interop/InteropServer.py
@@ -0,0 +1,593 @@
+#
+# Autogenerated by Thrift Compiler (0.7.0)
+#
+# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+#
+
+from thrift.Thrift import *
+from org.apache.plc4x.interop.ttypes import *
+from thrift.Thrift import TProcessor
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol, TProtocol
+
+from org.apache.plc4x.interop.ttypes import PlcException, ConnectionHandle, Request
+
+try:
+  from thrift.protocol import fastbinary
+except:
+  fastbinary = None
+
+
+class Iface:
+  def connect(self, connectionString):
+    """
+    Parameters:
+     - connectionString
+    """
+    pass
+
+  def execute(self, handle, request):
+    """
+    Parameters:
+     - handle
+     - request
+    """
+    pass
+
+  def close(self, handle):
+    """
+    Parameters:
+     - handle
+    """
+    pass
+
+
+class Client(Iface):
+  def __init__(self, iprot, oprot=None):
+    self._iprot = self._oprot = iprot
+    if oprot is not None:
+      self._oprot = oprot
+    self._seqid = 0
+
+  def connect(self, connectionString):
+    """
+    Parameters:
+     - connectionString
+    """
+    self.send_connect(connectionString)
+    return self.recv_connect()
+
+  def send_connect(self, connectionString):
+    self._oprot.writeMessageBegin('connect', TMessageType.CALL, self._seqid)
+    args = connect_args()
+    args.connectionString = connectionString
+    args.write(self._oprot)
+    self._oprot.writeMessageEnd()
+    self._oprot.trans.flush()
+
+  def recv_connect(self, ):
+    (fname, mtype, rseqid) = self._iprot.readMessageBegin()
+    if mtype == TMessageType.EXCEPTION:
+      x = TApplicationException()
+      x.read(self._iprot)
+      self._iprot.readMessageEnd()
+      raise x
+    result = connect_result()
+    result.read(self._iprot)
+    self._iprot.readMessageEnd()
+    if result.success is not None:
+      return result.success
+    if result.connectionException is not None:
+      raise result.connectionException
+    raise TApplicationException(TApplicationException.MISSING_RESULT, "connect failed: unknown result");
+
+  def execute(self, handle, request):
+    """
+    Parameters:
+     - handle
+     - request
+    """
+    self.send_execute(handle, request)
+    return self.recv_execute()
+
+  def send_execute(self, handle, request):
+    self._oprot.writeMessageBegin('execute', TMessageType.CALL, self._seqid)
+    args = execute_args()
+    args.handle = handle
+    args.request = request
+    args.write(self._oprot)
+    self._oprot.writeMessageEnd()
+    self._oprot.trans.flush()
+
+  def recv_execute(self, ):
+    (fname, mtype, rseqid) = self._iprot.readMessageBegin()
+    if mtype == TMessageType.EXCEPTION:
+      x = TApplicationException()
+      x.read(self._iprot)
+      self._iprot.readMessageEnd()
+      raise x
+    result = execute_result()
+    result.read(self._iprot)
+    self._iprot.readMessageEnd()
+    if result.success is not None:
+      return result.success
+    if result.executionException is not None:
+      raise result.executionException
+    raise TApplicationException(TApplicationException.MISSING_RESULT, "execute failed: unknown result");
+
+  def close(self, handle):
+    """
+    Parameters:
+     - handle
+    """
+    self.send_close(handle)
+    self.recv_close()
+
+  def send_close(self, handle):
+    self._oprot.writeMessageBegin('close', TMessageType.CALL, self._seqid)
+    args = close_args()
+    args.handle = handle
+    args.write(self._oprot)
+    self._oprot.writeMessageEnd()
+    self._oprot.trans.flush()
+
+  def recv_close(self, ):
+    (fname, mtype, rseqid) = self._iprot.readMessageBegin()
+    if mtype == TMessageType.EXCEPTION:
+      x = TApplicationException()
+      x.read(self._iprot)
+      self._iprot.readMessageEnd()
+      raise x
+    result = close_result()
+    result.read(self._iprot)
+    self._iprot.readMessageEnd()
+    return
+
+
+class Processor(Iface, TProcessor):
+  def __init__(self, handler):
+    self._handler = handler
+    self._processMap = {}
+    self._processMap["connect"] = Processor.process_connect
+    self._processMap["execute"] = Processor.process_execute
+    self._processMap["close"] = Processor.process_close
+
+  def process(self, iprot, oprot):
+    (name, type, seqid) = iprot.readMessageBegin()
+    if name not in self._processMap:
+      iprot.skip(TType.STRUCT)
+      iprot.readMessageEnd()
+      x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown function %s' % (name))
+      oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)
+      x.write(oprot)
+      oprot.writeMessageEnd()
+      oprot.trans.flush()
+      return
+    else:
+      self._processMap[name](self, seqid, iprot, oprot)
+    return True
+
+  def process_connect(self, seqid, iprot, oprot):
+    args = connect_args()
+    args.read(iprot)
+    iprot.readMessageEnd()
+    result = connect_result()
+    try:
+      result.success = self._handler.connect(args.connectionString)
+    except PlcException as connectionException:
+      result.connectionException = connectionException
+    oprot.writeMessageBegin("connect", TMessageType.REPLY, seqid)
+    result.write(oprot)
+    oprot.writeMessageEnd()
+    oprot.trans.flush()
+
+  def process_execute(self, seqid, iprot, oprot):
+    args = execute_args()
+    args.read(iprot)
+    iprot.readMessageEnd()
+    result = execute_result()
+    try:
+      result.success = self._handler.execute(args.handle, args.request)
+    except PlcException as executionException:
+      result.executionException = executionException
+    oprot.writeMessageBegin("execute", TMessageType.REPLY, seqid)
+    result.write(oprot)
+    oprot.writeMessageEnd()
+    oprot.trans.flush()
+
+  def process_close(self, seqid, iprot, oprot):
+    args = close_args()
+    args.read(iprot)
+    iprot.readMessageEnd()
+    result = close_result()
+    self._handler.close(args.handle)
+    oprot.writeMessageBegin("close", TMessageType.REPLY, seqid)
+    result.write(oprot)
+    oprot.writeMessageEnd()
+    oprot.trans.flush()
+
+
+# HELPER FUNCTIONS AND STRUCTURES
+
+class connect_args:
+  """
+  Attributes:
+   - connectionString
+  """
+
+  thrift_spec = (
+    None, # 0
+    (1, TType.STRING, 'connectionString', None, None, ), # 1
+  )
+
+  def __init__(self, connectionString=None,):
+    self.connectionString = connectionString
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 1:
+        if ftype == TType.STRING:
+          self.connectionString = iprot.readString();
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('connect_args')
+    if self.connectionString is not None:
+      oprot.writeFieldBegin('connectionString', TType.STRING, 1)
+      oprot.writeString(self.connectionString)
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.iteritems()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
+
+class connect_result:
+  """
+  Attributes:
+   - success
+   - connectionException
+  """
+
+  thrift_spec = (
+    (0, TType.STRUCT, 'success', (ConnectionHandle, ConnectionHandle.thrift_spec), None, ), # 0
+    (1, TType.STRUCT, 'connectionException', (PlcException, PlcException.thrift_spec), None, ), # 1
+  )
+
+  def __init__(self, success=None, connectionException=None,):
+    self.success = success
+    self.connectionException = connectionException
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 0:
+        if ftype == TType.STRUCT:
+          self.success = ConnectionHandle()
+          self.success.read(iprot)
+        else:
+          iprot.skip(ftype)
+      elif fid == 1:
+        if ftype == TType.STRUCT:
+          self.connectionException = PlcException()
+          self.connectionException.read(iprot)
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('connect_result')
+    if self.success is not None:
+      oprot.writeFieldBegin('success', TType.STRUCT, 0)
+      self.success.write(oprot)
+      oprot.writeFieldEnd()
+    if self.connectionException is not None:
+      oprot.writeFieldBegin('connectionException', TType.STRUCT, 1)
+      self.connectionException.write(oprot)
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.iteritems()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
+
+class execute_args:
+  """
+  Attributes:
+   - handle
+   - request
+  """
+
+  thrift_spec = (
+    None, # 0
+    (1, TType.STRUCT, 'handle', (ConnectionHandle, ConnectionHandle.thrift_spec), None, ), # 1
+    (2, TType.STRUCT, 'request', (Request, Request.thrift_spec), None, ), # 2
+  )
+
+  def __init__(self, handle=None, request=None,):
+    self.handle = handle
+    self.request = request
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 1:
+        if ftype == TType.STRUCT:
+          self.handle = ConnectionHandle()
+          self.handle.read(iprot)
+        else:
+          iprot.skip(ftype)
+      elif fid == 2:
+        if ftype == TType.STRUCT:
+          self.request = Request()
+          self.request.read(iprot)
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('execute_args')
+    if self.handle is not None:
+      oprot.writeFieldBegin('handle', TType.STRUCT, 1)
+      self.handle.write(oprot)
+      oprot.writeFieldEnd()
+    if self.request is not None:
+      oprot.writeFieldBegin('request', TType.STRUCT, 2)
+      self.request.write(oprot)
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.iteritems()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
+
+class execute_result:
+  """
+  Attributes:
+   - success
+   - executionException
+  """
+
+  thrift_spec = (
+    (0, TType.STRUCT, 'success', (Response, Response.thrift_spec), None, ), # 0
+    (1, TType.STRUCT, 'executionException', (PlcException, PlcException.thrift_spec), None, ), # 1
+  )
+
+  def __init__(self, success=None, executionException=None,):
+    self.success = success
+    self.executionException = executionException
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 0:
+        if ftype == TType.STRUCT:
+          self.success = Response()
+          self.success.read(iprot)
+        else:
+          iprot.skip(ftype)
+      elif fid == 1:
+        if ftype == TType.STRUCT:
+          self.executionException = PlcException()
+          self.executionException.read(iprot)
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('execute_result')
+    if self.success is not None:
+      oprot.writeFieldBegin('success', TType.STRUCT, 0)
+      self.success.write(oprot)
+      oprot.writeFieldEnd()
+    if self.executionException is not None:
+      oprot.writeFieldBegin('executionException', TType.STRUCT, 1)
+      self.executionException.write(oprot)
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.iteritems()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
+
+class close_args:
+  """
+  Attributes:
+   - handle
+  """
+
+  thrift_spec = (
+    None, # 0
+    (1, TType.STRUCT, 'handle', (ConnectionHandle, ConnectionHandle.thrift_spec), None, ), # 1
+  )
+
+  def __init__(self, handle=None,):
+    self.handle = handle
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 1:
+        if ftype == TType.STRUCT:
+          self.handle = ConnectionHandle()
+          self.handle.read(iprot)
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('close_args')
+    if self.handle is not None:
+      oprot.writeFieldBegin('handle', TType.STRUCT, 1)
+      self.handle.write(oprot)
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.iteritems()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
+
+class close_result:
+
+  thrift_spec = (
+  )
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('close_result')
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.iteritems()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
diff --git a/plc4py/org/apache/plc4x/interop/__init__.py b/plc4py/org/apache/plc4x/interop/__init__.py
new file mode 100644
index 0000000..d6615b7
--- /dev/null
+++ b/plc4py/org/apache/plc4x/interop/__init__.py
@@ -0,0 +1 @@
+__all__ = ['ttypes', 'constants', 'InteropServer']
diff --git a/plc4py/org/apache/plc4x/interop/constants.py b/plc4py/org/apache/plc4x/interop/constants.py
new file mode 100644
index 0000000..6816906
--- /dev/null
+++ b/plc4py/org/apache/plc4x/interop/constants.py
@@ -0,0 +1,9 @@
+#
+# Autogenerated by Thrift Compiler (0.7.0)
+#
+# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+#
+
+from thrift.Thrift import *
+from org.apache.plc4x.interop.ttypes import *
+
diff --git a/plc4py/org/apache/plc4x/interop/ttypes.py b/plc4py/org/apache/plc4x/interop/ttypes.py
new file mode 100644
index 0000000..adec8fc
--- /dev/null
+++ b/plc4py/org/apache/plc4x/interop/ttypes.py
@@ -0,0 +1,429 @@
+#
+# Autogenerated by Thrift Compiler (0.7.0)
+#
+# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+#
+from pip._vendor.urllib3.connectionpool import xrange
+from thrift.Thrift import *
+
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol, TProtocol
+try:
+  from thrift.protocol import fastbinary
+except:
+  fastbinary = None
+
+
+class RESPONSE_CODE:
+  OK = 1
+  NOT_FOUND = 2
+  ACCESS_DENIED = 3
+  INVALID_ADDRESS = 4
+  INVALID_DATATYPE = 5
+  INTERNAL_ERROR = 6
+  RESPONSE_PENDING = 7
+
+  _VALUES_TO_NAMES = {
+    1: "OK",
+    2: "NOT_FOUND",
+    3: "ACCESS_DENIED",
+    4: "INVALID_ADDRESS",
+    5: "INVALID_DATATYPE",
+    6: "INTERNAL_ERROR",
+    7: "RESPONSE_PENDING",
+  }
+
+  _NAMES_TO_VALUES = {
+    "OK": 1,
+    "NOT_FOUND": 2,
+    "ACCESS_DENIED": 3,
+    "INVALID_ADDRESS": 4,
+    "INVALID_DATATYPE": 5,
+    "INTERNAL_ERROR": 6,
+    "RESPONSE_PENDING": 7,
+  }
+
+
+class ConnectionHandle:
+  """
+  Attributes:
+   - connectionId
+  """
+
+  thrift_spec = (
+    None, # 0
+    (1, TType.I64, 'connectionId', None, None, ), # 1
+  )
+
+  def __init__(self, connectionId=None,):
+    self.connectionId = connectionId
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 1:
+        if ftype == TType.I64:
+          self.connectionId = iprot.readI64();
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('ConnectionHandle')
+    if self.connectionId is not None:
+      oprot.writeFieldBegin('connectionId', TType.I64, 1)
+      oprot.writeI64(self.connectionId)
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.iteritems()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
+
+class PlcException(Exception):
+  """
+  Attributes:
+   - url
+   - exceptionString
+  """
+
+  thrift_spec = (
+    None, # 0
+    (1, TType.STRING, 'url', None, None, ), # 1
+    (2, TType.STRING, 'exceptionString', None, None, ), # 2
+  )
+
+  def __init__(self, url=None, exceptionString=None,):
+    self.url = url
+    self.exceptionString = exceptionString
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 1:
+        if ftype == TType.STRING:
+          self.url = iprot.readString();
+        else:
+          iprot.skip(ftype)
+      elif fid == 2:
+        if ftype == TType.STRING:
+          self.exceptionString = iprot.readString();
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('PlcException')
+    if self.url is not None:
+      oprot.writeFieldBegin('url', TType.STRING, 1)
+      oprot.writeString(self.url)
+      oprot.writeFieldEnd()
+    if self.exceptionString is not None:
+      oprot.writeFieldBegin('exceptionString', TType.STRING, 2)
+      oprot.writeString(self.exceptionString)
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __str__(self):
+    return repr(self)
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.iteritems()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
+
+class Request:
+  """
+  Attributes:
+   - fields
+  """
+
+  thrift_spec = (
+    None, # 0
+    (1, TType.MAP, 'fields', (TType.STRING,None,TType.STRING,None), None, ), # 1
+  )
+
+  def __init__(self, fields=None,):
+    self.fields = fields
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 1:
+        if ftype == TType.MAP:
+          self.fields = {}
+          (_ktype1, _vtype2, _size0 ) = iprot.readMapBegin() 
+          for _i4 in xrange(_size0):
+            _key5 = iprot.readString();
+            _val6 = iprot.readString();
+            self.fields[_key5] = _val6
+          iprot.readMapEnd()
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('Request')
+    if self.fields is not None:
+      oprot.writeFieldBegin('fields', TType.MAP, 1)
+      oprot.writeMapBegin(TType.STRING, TType.STRING, len(self.fields))
+      for kiter7,viter8 in self.fields.items():
+        oprot.writeString(kiter7)
+        oprot.writeString(viter8)
+      oprot.writeMapEnd()
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.iteritems()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
+
+class FieldResponse:
+  """
+  Attributes:
+   - responseCode
+   - boolValue
+   - longValue
+   - doubleValue
+   - stringValue
+  """
+
+  thrift_spec = (
+    None, # 0
+    (1, TType.I32, 'responseCode', None, None, ), # 1
+    (2, TType.BOOL, 'boolValue', None, None, ), # 2
+    (3, TType.I64, 'longValue', None, None, ), # 3
+    (4, TType.DOUBLE, 'doubleValue', None, None, ), # 4
+    (5, TType.STRING, 'stringValue', None, None, ), # 5
+  )
+
+  def __init__(self, responseCode=None, boolValue=None, longValue=None, doubleValue=None, stringValue=None,):
+    self.responseCode = responseCode
+    self.boolValue = boolValue
+    self.longValue = longValue
+    self.doubleValue = doubleValue
+    self.stringValue = stringValue
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 1:
+        if ftype == TType.I32:
+          self.responseCode = iprot.readI32();
+        else:
+          iprot.skip(ftype)
+      elif fid == 2:
+        if ftype == TType.BOOL:
+          self.boolValue = iprot.readBool();
+        else:
+          iprot.skip(ftype)
+      elif fid == 3:
+        if ftype == TType.I64:
+          self.longValue = iprot.readI64();
+        else:
+          iprot.skip(ftype)
+      elif fid == 4:
+        if ftype == TType.DOUBLE:
+          self.doubleValue = iprot.readDouble();
+        else:
+          iprot.skip(ftype)
+      elif fid == 5:
+        if ftype == TType.STRING:
+          self.stringValue = iprot.readString();
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('FieldResponse')
+    if self.responseCode is not None:
+      oprot.writeFieldBegin('responseCode', TType.I32, 1)
+      oprot.writeI32(self.responseCode)
+      oprot.writeFieldEnd()
+    if self.boolValue is not None:
+      oprot.writeFieldBegin('boolValue', TType.BOOL, 2)
+      oprot.writeBool(self.boolValue)
+      oprot.writeFieldEnd()
+    if self.longValue is not None:
+      oprot.writeFieldBegin('longValue', TType.I64, 3)
+      oprot.writeI64(self.longValue)
+      oprot.writeFieldEnd()
+    if self.doubleValue is not None:
+      oprot.writeFieldBegin('doubleValue', TType.DOUBLE, 4)
+      oprot.writeDouble(self.doubleValue)
+      oprot.writeFieldEnd()
+    if self.stringValue is not None:
+      oprot.writeFieldBegin('stringValue', TType.STRING, 5)
+      oprot.writeString(self.stringValue)
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.items()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
+
+class Response:
+  """
+  Attributes:
+   - fields
+  """
+
+  thrift_spec = (
+    None, # 0
+    (1, TType.MAP, 'fields', (TType.STRING,None,TType.STRUCT,(FieldResponse, FieldResponse.thrift_spec)), None, ), # 1
+  )
+
+  def __init__(self, fields=None,):
+    self.fields = fields
+
+  def read(self, iprot):
+    if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
+      fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
+      return
+    iprot.readStructBegin()
+    while True:
+      (fname, ftype, fid) = iprot.readFieldBegin()
+      if ftype == TType.STOP:
+        break
+      if fid == 1:
+        if ftype == TType.MAP:
+          self.fields = {}
+          (_ktype10, _vtype11, _size9 ) = iprot.readMapBegin() 
+          for _i13 in xrange(_size9):
+            _key14 = iprot.readString();
+            _val15 = FieldResponse()
+            _val15.read(iprot)
+            self.fields[_key14] = _val15
+          iprot.readMapEnd()
+        else:
+          iprot.skip(ftype)
+      else:
+        iprot.skip(ftype)
+      iprot.readFieldEnd()
+    iprot.readStructEnd()
+
+  def write(self, oprot):
+    if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
+      oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
+      return
+    oprot.writeStructBegin('Response')
+    if self.fields is not None:
+      oprot.writeFieldBegin('fields', TType.MAP, 1)
+      oprot.writeMapBegin(TType.STRING, TType.STRUCT, len(self.fields))
+      for kiter16,viter17 in self.fields.items():
+        oprot.writeString(kiter16)
+        viter17.write(oprot)
+      oprot.writeMapEnd()
+      oprot.writeFieldEnd()
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+
+  def validate(self):
+    return
+
+
+  def __repr__(self):
+    L = ['%s=%r' % (key, value)
+      for key, value in self.__dict__.items()]
+    return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
+
+  def __ne__(self, other):
+    return not (self == other)
diff --git a/plc4py/test/__init__.py b/plc4py/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/plc4py/test/test_PlcDriverManager.py b/plc4py/test/test_PlcDriverManager.py
new file mode 100644
index 0000000..4a5e898
--- /dev/null
+++ b/plc4py/test/test_PlcDriverManager.py
@@ -0,0 +1,95 @@
+import time
+import unittest
+from subprocess import Popen
+from unittest import TestCase
+
+from org.apache.plc4x.PlcDriverManager import PlcDriverManager
+from org.apache.plc4x.interop.InteropServer import Client, Request, PlcException
+
+if __name__ == '__main__':
+    unittest.main()
+
+
+class TestPlcDriverManager(TestCase):
+
+    def test_callLib(self):
+        try:
+            proc = Popen(["java", "-jar", "../lib/apache-plc4x-incubating-0.4.0-SNAPSHOT-jar-with-dependencies.jar"])
+            print("Started server under pid " + str(proc.pid))
+            time.sleep(5)
+            poll = proc.poll()
+            if poll is None:
+                print("Still running...")
+            else:
+                print("Unable to start the Interop Server...")
+        except:
+            print("Unable to start proces")
+        finally:
+            proc.terminate()
+
+    def test_startAndStopServer(self):
+        try:
+            manager = PlcDriverManager()
+
+            ## Do some magic here
+            client = manager._get_client()
+            connection = client.connect("mock:a")
+
+            result = client.execute(connection, Request(fields={"field1": "asdf"}))
+
+            print(result)
+
+            client.close(connection)
+        finally:
+            manager.close()
+
+    def test_withPlcConnection(self):
+        try:
+            manager = PlcDriverManager()
+
+            try:
+                connection = manager.get_connection("mock:a")
+                result = connection.execute(Request(fields={"field1": "asdf"}))
+                print(result)
+            finally:
+                connection.close()
+        finally:
+            manager.close()
+
+    def test_withRealPLC_forDebug(self):
+        try:
+            manager = PlcDriverManager(embedded_server=False)
+
+            connection = None
+            try:
+                connection = manager.get_connection("s7://192.168.167.210/0/1")
+                result = connection.execute(Request(fields={"field1": "%M0:USINT"}))
+                print(result)
+            except PlcException as e:
+                raise Exception(str(e.url))
+            finally:
+                if connection is not None:
+                    connection.close()
+        finally:
+            manager.close()
+
+    def test_withRealPLC(self):
+        try:
+            manager = PlcDriverManager()
+
+            connection = None
+            try:
+                connection = manager.get_connection("s7://192.168.167.210/0/1")
+                for _ in range(100):
+                    result = connection.execute(Request(fields={"field1": "%M0:USINT"}))
+                    print("Response Code is " + str(result.get_field("field1").get_response_code()))
+                    # We now that we want to get an int...
+                    print("Response Value is " + str(result.get_field("field1").get_int_value()))
+
+            except PlcException as e:
+                raise Exception(str(e.url))
+            finally:
+                if connection is not None:
+                    connection.close()
+        finally:
+            manager.close()
\ No newline at end of file


[incubator-plc4x] 02/02: PLC4X-111 Added Readme and renamed the INIT Script.

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

jfeinauer pushed a commit to branch feature/PLC4X-111-interop-server
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git

commit 87ddc847a0b31b1ac811c8c52e10c6ee610b790f
Author: julian <j....@pragmaticminds.de>
AuthorDate: Sun Apr 21 13:52:42 2019 +0200

    PLC4X-111 Added Readme and renamed the INIT Script.
---
 plc4py/README.md                    | 38 +++++++++++++++++++++++++++++++++++++
 plc4py/copy_server.sh               |  4 ----
 plc4py/initialize_interop_server.sh |  7 +++++++
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/plc4py/README.md b/plc4py/README.md
new file mode 100644
index 0000000..e9e4eee
--- /dev/null
+++ b/plc4py/README.md
@@ -0,0 +1,38 @@
+# Python binding for the interop server
+
+This module provides the (experimental) Python support for the interop server.
+Or, simpler, a python 3 binding for PLC4X.
+
+The only thing which needs to be done as _installation_ is to run the `initialize_interop_server.sh` skript to build the interop server and copy it to `lib/`  forder.
+
+Then, you are good to go.
+
+Here is some example code:
+
+```python
+try:
+    manager = PlcDriverManager()
+
+    connection = None
+    try:
+        connection = manager.get_connection("s7://192.168.167.210/0/1")
+        for _ in range(100):
+            result = connection.execute(Request(fields={"field1": "%M0:USINT"}))
+            print("Response Code is " + str(result.get_field("field1").get_response_code()))
+            # We now that we want to get an int...
+            print("Response Value is " + str(result.get_field("field1").get_int_value()))
+
+    except PlcException as e:
+        raise Exception(str(e.url))
+    finally:
+        if connection is not None:
+            connection.close()
+finally:
+    manager.close()
+```
+
+the `PlcDriverManager` spawns an interop server in the background, thus it is important to close it afterwards.
+Otherwise this process keeps alive and you have to kill by yourself.
+
+All generated files (from thrift) are in `org.apache.plc4x.interop`.
+I built a very simple Python API in `org.apache.plc4x`.
\ No newline at end of file
diff --git a/plc4py/copy_server.sh b/plc4py/copy_server.sh
deleted file mode 100755
index 57f7f27..0000000
--- a/plc4py/copy_server.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env bash
-
-# Moves the server from the target folder here
-cp ../plc4j/utils/interop/target/apache-plc4x-incubating-* lib/
\ No newline at end of file
diff --git a/plc4py/initialize_interop_server.sh b/plc4py/initialize_interop_server.sh
new file mode 100755
index 0000000..80b0b2e
--- /dev/null
+++ b/plc4py/initialize_interop_server.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+# Builds the interop server module with maven
+mvn clean package -f ../plc4j/utils/interop/pom.xml
+
+# Moves the server from the target folder here
+cp ../plc4j/utils/interop/target/apache-plc4x-incubating-* lib/
\ No newline at end of file