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

[plc4x] branch feature/mspec-ng updated: - Continued porting OPC-UA

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

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


The following commit(s) were added to refs/heads/feature/mspec-ng by this push:
     new 963b665  - Continued porting OPC-UA
963b665 is described below

commit 963b66584ed9b4222a63da03f4b5fb98d4f6abf3
Author: cdutz <ch...@c-ware.de>
AuthorDate: Wed Oct 27 12:48:01 2021 +0200

    - Continued porting OPC-UA
---
 .../language/java/JavaLanguageTemplateHelper.java  |  35 +-
 .../apache/plc4x/java/opcua/OpcuaPlcDriver.java    |   4 -
 .../java/opcua/context/EncryptionHandler.java      |   4 +-
 .../plc4x/java/opcua/context/SecureChannel.java    | 585 +++++++++------------
 .../context/SecureChannelTransactionManager.java   |  16 +-
 .../apache/plc4x/java/opcua/field/OpcuaField.java  |   3 +-
 .../java/opcua/protocol/OpcuaProtocolLogic.java    | 292 +++++-----
 .../opcua/protocol/OpcuaSubscriptionHandle.java    |  55 +-
 .../main/resources/protocols/abeth/ab-eth.mspec    |   2 +-
 .../src/main/resources/protocols/can/canopen.mspec |   2 +-
 protocols/opcua/src/main/xslt/opc-common.xsl       |   8 +-
 protocols/opcua/src/main/xslt/opc-manual.xsl       |  32 +-
 .../s7/src/main/resources/protocols/s7/s7.mspec    |   2 +-
 13 files changed, 444 insertions(+), 596 deletions(-)

diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index aa03947..bd6f547 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -34,10 +34,7 @@ import java.math.BigInteger;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
+import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -380,16 +377,26 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
             return getDataReaderCall(simpleTypeReference);
         } else if (typeReference.isComplexTypeReference()) {
             StringBuilder sb = new StringBuilder();
-            final ComplexTypeReference complexTypeReference = typeReference.asComplexTypeReference().orElseThrow(IllegalStateException::new);
-            final Optional<List<Term>> params = complexTypeReference.getParams();
-            if(params.isPresent()) {
-                final List<Term> paramTerms = params.get();
-                for (int i = 0; i < paramTerms.size(); i++) {
-                    Term paramTerm = paramTerms.get(i);
-                    sb.append(", (").append(getLanguageTypeNameForTypeReference(getArgumentType(complexTypeReference, i), true)).append(") (").append(toParseExpression(null, paramTerm, null)).append(")");
-                }
+            ComplexTypeReference complexTypeReference = typeReference.asComplexTypeReference().orElseThrow(IllegalStateException::new);
+            TypeDefinition typeDefinition = getTypeDefinitionForTypeReference(typeReference);
+            List<Term> parentTerms = typeDefinition.isDiscriminatedChildTypeDefinition() ?
+                typeDefinition.getParentType().getTypeReference().asComplexTypeReference().orElseThrow(
+                    () -> new IllegalStateException("Shouldn't happen as the parent must be complex")).getParams().orElse(Collections.emptyList()) :
+                Collections.emptyList();
+            List<Term> childTerms = complexTypeReference.getParams().orElse(Collections.emptyList());
+            List<Term> allTerms = new ArrayList<>(parentTerms);
+            allTerms.addAll(childTerms);
+            for (int i = 0; i < allTerms.size(); i++) {
+                Term paramTerm = allTerms.get(i);
+                sb.append(", (").append(getLanguageTypeNameForTypeReference(getArgumentType(complexTypeReference, i), true))
+                    .append(") (").append(toParseExpression(null, paramTerm, null)).append(")");
+            }
+            String parserCallString = getLanguageTypeNameForTypeReference(typeReference);
+            if(typeDefinition.isDiscriminatedChildTypeDefinition()) {
+                parserCallString = "(" + getLanguageTypeNameForTypeReference(typeReference) + ") " +
+                    getLanguageTypeNameForTypeReference(typeDefinition.getParentType().getTypeReference());
             }
-            return "new DataReaderComplexDefault<>(() -> " + getLanguageTypeNameForTypeReference(typeReference) + "IO.staticParse(readBuffer" + sb + "), readBuffer)";
+            return "new DataReaderComplexDefault<>(() -> " + parserCallString + "IO.staticParse(readBuffer" + sb + "), readBuffer)";
         } else {
             throw new IllegalStateException("What is this type? " + typeReference);
         }
@@ -606,7 +613,7 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
             return tracer + ((NumericLiteral) literal).getNumber().toString();
         } else if (literal instanceof StringLiteral) {
             tracer = tracer.dive("string literal instanceOf");
-            return tracer + "\"" + ((StringLiteral) literal).getValue() + "\"";
+            return tracer + ((StringLiteral) literal).getValue();
         } else if (literal instanceof VariableLiteral) {
             tracer = tracer.dive("variable literal instanceOf");
             VariableLiteral variableLiteral = (VariableLiteral) literal;
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/OpcuaPlcDriver.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/OpcuaPlcDriver.java
index 088853c..7d3f8d5 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/OpcuaPlcDriver.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/OpcuaPlcDriver.java
@@ -36,8 +36,6 @@ import org.apache.plc4x.java.api.value.PlcValueHandler;
 import org.apache.plc4x.java.spi.configuration.Configuration;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import io.netty.buffer.ByteBuf;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.ServiceLoader;
 import java.util.regex.Matcher;
@@ -49,8 +47,6 @@ import static org.apache.plc4x.java.spi.configuration.ConfigurationFactory.confi
 
 public class OpcuaPlcDriver extends GeneratedDriverBase<OpcuaAPU> {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(OpcuaPlcDriver.class);
-
     public static final Pattern INET_ADDRESS_PATTERN = Pattern.compile("(:(?<transportCode>tcp))?://" +
                                                                         "(?<transportHost>[\\w.-]+)(:" +
                                                                         "(?<transportPort>\\d*))?");
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/EncryptionHandler.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/EncryptionHandler.java
index 6a0f58f..27755c4 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/EncryptionHandler.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/EncryptionHandler.java
@@ -96,8 +96,8 @@ public class EncryptionHandler {
             buf.setPos(tempPos);
             byte[] signature = sign(buf.getBytes(0, unencryptedLength + paddingSize + 1));
             //Write the signature to the end of the buffer
-            for (int i = 0; i < signature.length; i++) {
-                buf.writeByte(signature[i]);
+            for (byte b : signature) {
+                buf.writeByte(b);
             }
             buf.setPos(positionFirstBlock);
             encryptBlock(buf, buf.getBytes(positionFirstBlock, positionFirstBlock + preEncryptedLength));
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java
index d685288..88b3a73 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannel.java
@@ -29,7 +29,10 @@ import org.apache.plc4x.java.opcua.readwrite.io.OpcuaAPUIO;
 import org.apache.plc4x.java.opcua.readwrite.types.*;
 import org.apache.plc4x.java.spi.ConversationContext;
 import org.apache.plc4x.java.spi.context.DriverContext;
-import org.apache.plc4x.java.spi.generation.*;
+import org.apache.plc4x.java.spi.generation.ParseException;
+import org.apache.plc4x.java.spi.generation.ReadBuffer;
+import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
+import org.apache.plc4x.java.spi.generation.WriteBufferByteBased;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,6 +46,8 @@ import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateEncodingException;
 import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -65,8 +70,8 @@ public class SecureChannel {
     public static final long REQUEST_TIMEOUT_LONG = 10000L;
     private static final String PASSWORD_ENCRYPTION_ALGORITHM = "http://www.w3.org/2001/04/xmlenc#rsa-oaep";
     private static final PascalString SECURITY_POLICY_NONE = new PascalString("http://opcfoundation.org/UA/SecurityPolicy#None");
-    protected static final PascalString NULL_STRING = new PascalString( "");
-    private static final PascalByteString NULL_BYTE_STRING = new PascalByteString( -1, null);
+    protected static final PascalString NULL_STRING = new PascalString("");
+    private static final PascalByteString NULL_BYTE_STRING = new PascalByteString(-1, null);
     private static ExpandedNodeId NULL_EXPANDED_NODEID = new ExpandedNodeId(false,
         false,
         new NodeIdTwoByte((short) 0),
@@ -86,67 +91,54 @@ public class SecureChannel {
     private static final long DEFAULT_CONNECTION_LIFETIME = 36000000;
     private final String sessionName = "UaSession:" + APPLICATION_TEXT.getStringValue() + ":" + RandomStringUtils.random(20, true, true);
     private final byte[] clientNonce = RandomUtils.nextBytes(40);
-    private AtomicInteger requestHandleGenerator = new AtomicInteger(1);
+    private final AtomicInteger requestHandleGenerator = new AtomicInteger(1);
     private PascalString policyId;
-    private PascalString endpoint;
-    private boolean discovery;
-    private String username;
-    private String password;
-    private String certFile;
-    private String securityPolicy;
-    private String keyStoreFile;
-    private CertificateKeyPair ckp;
-    private PascalByteString publicCertificate;
-    private PascalByteString thumbprint;
-    private boolean isEncrypted;
+    private final PascalString endpoint;
+    private final String username;
+    private final String password;
+    private final String securityPolicy;
+    private final PascalByteString publicCertificate;
+    private final PascalByteString thumbprint;
+    private final boolean isEncrypted;
     private byte[] senderCertificate = null;
     private byte[] senderNonce = null;
-    private PascalByteString certificateThumbprint = null;
-    private boolean checkedEndpoints = false;
-    private EncryptionHandler encryptionHandler = null;
+    private EncryptionHandler encryptionHandler;
     private OpcuaConfiguration configuration;
     private AtomicInteger channelId = new AtomicInteger(1);
     private AtomicInteger tokenId = new AtomicInteger(1);
     private NodeIdTypeDefinition authenticationToken = new NodeIdTwoByte((short) 0);
-    private DriverContext driverContext;
     ConversationContext<OpcuaAPU> context;
     private SecureChannelTransactionManager channelTransactionManager = new SecureChannelTransactionManager();
     private long lifetime = DEFAULT_CONNECTION_LIFETIME;
     private CompletableFuture<Void> keepAlive;
-    private int sendBufferSize;
-    private int maxMessageSize;
     private AtomicLong senderSequenceNumber = new AtomicLong();
 
     public SecureChannel(DriverContext driverContext, OpcuaConfiguration configuration) {
-        this.driverContext = driverContext;
         this.configuration = configuration;
 
         this.endpoint = new PascalString(configuration.getEndpoint());
-        this.discovery = configuration.isDiscovery();
         this.username = configuration.getUsername();
         this.password = configuration.getPassword();
-        this.certFile = configuration.getCertDirectory();
         this.securityPolicy = "http://opcfoundation.org/UA/SecurityPolicy#" + configuration.getSecurityPolicy();
-        this.ckp = configuration.getCertificateKeyPair();
+        CertificateKeyPair ckp = configuration.getCertificateKeyPair();
 
         if (configuration.getSecurityPolicy() != null && configuration.getSecurityPolicy().equals("Basic256Sha256")) {
-            //Sender Certificate gets populated during the discover phase when encryption is enabled.
+            //Sender Certificate gets populated during the 'discover' phase when encryption is enabled.
             this.senderCertificate = configuration.getSenderCertificate();
-            this.encryptionHandler = new EncryptionHandler(this.ckp, this.senderCertificate, configuration.getSecurityPolicy());
+            this.encryptionHandler = new EncryptionHandler(ckp, this.senderCertificate, configuration.getSecurityPolicy());
             try {
-                this.publicCertificate = new PascalByteString(this.ckp.getCertificate().getEncoded().length, this.ckp.getCertificate().getEncoded());
+                this.publicCertificate = new PascalByteString(ckp.getCertificate().getEncoded().length, ckp.getCertificate().getEncoded());
                 this.isEncrypted = true;
             } catch (CertificateEncodingException e) {
                 throw new PlcRuntimeException("Failed to encode the certificate");
             }
             this.thumbprint = configuration.getThumbprint();
         } else {
-            this.encryptionHandler = new EncryptionHandler(this.ckp, this.senderCertificate, configuration.getSecurityPolicy());
+            this.encryptionHandler = new EncryptionHandler(ckp, this.senderCertificate, configuration.getSecurityPolicy());
             this.publicCertificate = NULL_BYTE_STRING;
             this.thumbprint = NULL_BYTE_STRING;
             this.isEncrypted = false;
         }
-        this.keyStoreFile = configuration.getKeyStoreFile();
     }
 
     public void submit(ConversationContext<OpcuaAPU> context, Consumer<TimeoutException> onTimeout, BiConsumer<OpcuaAPU, Throwable> error, Consumer<byte[]> consumer, WriteBufferByteBased buffer) {
@@ -170,7 +162,7 @@ public class SecureChannel {
                 apu = new OpcuaAPU(messageRequest);
             }
         } catch (ParseException e) {
-           throw new PlcRuntimeException("Unable to encrypt message before sending");
+            throw new PlcRuntimeException("Unable to encrypt message before sending");
         }
 
         Consumer<Integer> requestConsumer = t -> {
@@ -191,14 +183,10 @@ public class SecureChannel {
                                     context.fireDisconnected();
                                 }
                             } catch (IOException e) {
-                                LOGGER.debug("Failed to store incoming message in buffer {}");
+                                LOGGER.debug("Failed to store incoming message in buffer");
                                 throw new PlcRuntimeException("Error while sending message");
                             }
-                            if (p.getChunk().equals(FINAL_CHUNK)) {
-                                return true;
-                            } else {
-                                return false;
-                            }
+                            return p.getChunk().equals(FINAL_CHUNK);
                         } else {
                             return false;
                         }
@@ -208,7 +196,6 @@ public class SecureChannel {
                             tokenId.set(opcuaResponse.getSecureTokenId());
                             channelId.set(opcuaResponse.getSecureChannelId());
 
-
                             consumer.accept(messageBuffer.toByteArray());
                         }
                     });
@@ -233,17 +220,11 @@ public class SecureChannel {
             DEFAULT_MAX_CHUNK_COUNT,
             this.endpoint);
 
-        Consumer<Integer> requestConsumer = t -> {
-            context.sendRequest(new OpcuaAPU(hello))
-                .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
-                .check(p -> p.getMessage() instanceof OpcuaAcknowledgeResponse)
-                .unwrap(p -> (OpcuaAcknowledgeResponse) p.getMessage())
-                .handle(opcuaAcknowledgeResponse -> {
-                    sendBufferSize = Math.min(opcuaAcknowledgeResponse.getReceiveBufferSize(), DEFAULT_SEND_BUFFER_SIZE);
-                    maxMessageSize = Math.min(opcuaAcknowledgeResponse.getMaxMessageSize(), DEFAULT_MAX_MESSAGE_SIZE);
-                    onConnectOpenSecureChannel(context, opcuaAcknowledgeResponse);
-                });
-        };
+        Consumer<Integer> requestConsumer = t -> context.sendRequest(new OpcuaAPU(hello))
+            .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+            .check(p -> p.getMessage() instanceof OpcuaAcknowledgeResponse)
+            .unwrap(p -> (OpcuaAcknowledgeResponse) p.getMessage())
+            .handle(opcuaAcknowledgeResponse -> onConnectOpenSecureChannel(context, opcuaAcknowledgeResponse));
         channelTransactionManager.submit(requestConsumer, channelTransactionManager.getTransactionIdentifier());
     }
 
@@ -259,7 +240,7 @@ public class SecureChannel {
             REQUEST_TIMEOUT_LONG,
             NULL_EXTENSION_OBJECT);
 
-        OpenSecureChannelRequest openSecureChannelRequest = null;
+        OpenSecureChannelRequest openSecureChannelRequest;
         if (this.isEncrypted) {
             openSecureChannelRequest = new OpenSecureChannelRequest(
                 requestHeader,
@@ -280,7 +261,7 @@ public class SecureChannel {
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(openSecureChannelRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(openSecureChannelRequest.getIdentifier())),
             null,
             null);
 
@@ -310,47 +291,38 @@ public class SecureChannel {
                 apu = new OpcuaAPU(openRequest);
             }
 
-            Consumer<Integer> requestConsumer = t -> {
-                context.sendRequest(apu)
-                    .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
-                    .unwrap(apuMessage -> encryptionHandler.decodeMessage(apuMessage))
-                    .check(p -> p.getMessage() instanceof OpcuaOpenResponse)
-                    .unwrap(p -> (OpcuaOpenResponse) p.getMessage())
-                    .check(p -> {
-                        if (p.getRequestId() == transactionId) {
-                            return true;
+            Consumer<Integer> requestConsumer = t -> context.sendRequest(apu)
+                .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+                .unwrap(apuMessage -> encryptionHandler.decodeMessage(apuMessage))
+                .check(p -> p.getMessage() instanceof OpcuaOpenResponse)
+                .unwrap(p -> (OpcuaOpenResponse) p.getMessage())
+                .check(p -> p.getRequestId() == transactionId)
+                .handle(opcuaOpenResponse -> {
+                    try {
+                        ReadBuffer readBuffer = new ReadBufferByteBased(opcuaOpenResponse.getMessage(), org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN);
+                        ExtensionObject message = ExtensionObjectIO.staticParse(readBuffer, false);
+                        //Store the initial sequence number from the server. there's no requirement for the server and client to use the same starting number.
+                        senderSequenceNumber.set(opcuaOpenResponse.getSequenceNumber());
+
+                        if (message.getBody() instanceof ServiceFault) {
+                            ServiceFault fault = (ServiceFault) message.getBody();
+                            LOGGER.error("Failed to connect to opc ua server for the following reason:- {}, {}", ((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode(), OpcuaStatusCode.enumForValue(((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode()));
                         } else {
-                            return false;
-                        }
-                    })
-                    .handle(opcuaOpenResponse -> {
-                        try {
-                            ReadBuffer readBuffer = new ReadBufferByteBased(opcuaOpenResponse.getMessage(), org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN);
-                            ExtensionObject message = ExtensionObjectIO.staticParse(readBuffer, false);
-                            //Store the initial sequence number from the server. there's no requirement for the server and client to use the same starting number.
-                            senderSequenceNumber.set(opcuaOpenResponse.getSequenceNumber());
-                            certificateThumbprint = opcuaOpenResponse.getReceiverCertificateThumbprint();
-
-                            if (message.getBody() instanceof ServiceFault) {
-                                ServiceFault fault = (ServiceFault) message.getBody();
-                                LOGGER.error("Failed to connect to opc ua server for the following reason:- {}, {}", ((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode(), OpcuaStatusCode.enumForValue(((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode()));
-                            } else {
-                                LOGGER.debug("Got Secure Response Connection Response");
-                                try {
-                                    OpenSecureChannelResponse openSecureChannelResponse = (OpenSecureChannelResponse) message.getBody();
-                                    tokenId.set((int) ((ChannelSecurityToken) openSecureChannelResponse.getSecurityToken()).getTokenId());
-                                    channelId.set((int) ((ChannelSecurityToken) openSecureChannelResponse.getSecurityToken()).getChannelId());
-                                    onConnectCreateSessionRequest(context);
-                                } catch (PlcConnectionException e) {
-                                    LOGGER.error("Error occurred while connecting to OPC UA server");
-                                    e.printStackTrace();
-                                }
+                            LOGGER.debug("Got Secure Response Connection Response");
+                            try {
+                                OpenSecureChannelResponse openSecureChannelResponse = (OpenSecureChannelResponse) message.getBody();
+                                tokenId.set((int) ((ChannelSecurityToken) openSecureChannelResponse.getSecurityToken()).getTokenId());
+                                channelId.set((int) ((ChannelSecurityToken) openSecureChannelResponse.getSecurityToken()).getChannelId());
+                                onConnectCreateSessionRequest(context);
+                            } catch (PlcConnectionException e) {
+                                LOGGER.error("Error occurred while connecting to OPC UA server");
+                                e.printStackTrace();
                             }
-                        } catch (ParseException e) {
-                            e.printStackTrace();
                         }
-                    });
-            };
+                    } catch (ParseException e) {
+                        e.printStackTrace();
+                    }
+                });
             LOGGER.debug("Submitting OpenSecureChannel with id of {}", transactionId);
             channelTransactionManager.submit(requestConsumer, transactionId);
         } catch (ParseException e) {
@@ -374,17 +346,15 @@ public class SecureChannel {
             new PascalString("en"),
             APPLICATION_TEXT);
 
-        PascalString gatewayServerUri = NULL_STRING;
-        PascalString discoveryProfileUri = NULL_STRING;
         int noOfDiscoveryUrls = -1;
-        PascalString[] discoveryUrls = new PascalString[0];
+        List<PascalString> discoveryUrls = new ArrayList<>(0);
 
         ApplicationDescription clientDescription = new ApplicationDescription(APPLICATION_URI,
             PRODUCT_URI,
             applicationName,
             ApplicationType.applicationTypeClient,
-            gatewayServerUri,
-            discoveryProfileUri,
+            NULL_STRING,
+            NULL_STRING,
             noOfDiscoveryUrls,
             discoveryUrls);
 
@@ -401,7 +371,7 @@ public class SecureChannel {
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(createSessionRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(createSessionRequest.getIdentifier())),
             null,
             null);
 
@@ -415,42 +385,42 @@ public class SecureChannel {
             ExtensionObjectIO.staticSerialize(buffer, extObject);
 
             Consumer<byte[]> consumer = opcuaResponse -> {
+                try {
+                    ExtensionObject message = ExtensionObjectIO.staticParse(new ReadBufferByteBased(opcuaResponse, org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN), false);
+                    if (message.getBody() instanceof ServiceFault) {
+                        ServiceFault fault = (ServiceFault) message.getBody();
+                        LOGGER.error("Failed to connect to opc ua server for the following reason:- {}, {}", ((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode(), OpcuaStatusCode.enumForValue(((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode()));
+                    } else {
+                        LOGGER.debug("Got Create Session Response Connection Response");
                         try {
-                            ExtensionObject message = ExtensionObjectIO.staticParse(new ReadBufferByteBased(opcuaResponse, org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN), false);
-                            if (message.getBody() instanceof ServiceFault) {
-                                ServiceFault fault = (ServiceFault) message.getBody();
-                                LOGGER.error("Failed to connect to opc ua server for the following reason:- {}, {}", ((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode(), OpcuaStatusCode.enumForValue(((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode()));
-                            } else {
-                                LOGGER.debug("Got Create Session Response Connection Response");
-                                try {
-                                    CreateSessionResponse responseMessage;
-
-                                    ExtensionObjectDefinition unknownExtensionObject = ExtensionObjectIO.staticParse(new ReadBufferByteBased(opcuaResponse, org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN), false).getBody();
-                                    if (unknownExtensionObject instanceof CreateSessionResponse) {
-                                        responseMessage = (CreateSessionResponse) unknownExtensionObject;
+                            CreateSessionResponse responseMessage;
 
-                                        authenticationToken = responseMessage.getAuthenticationToken().getNodeId();
+                            ExtensionObjectDefinition unknownExtensionObject = ExtensionObjectIO.staticParse(new ReadBufferByteBased(opcuaResponse, org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN), false).getBody();
+                            if (unknownExtensionObject instanceof CreateSessionResponse) {
+                                responseMessage = (CreateSessionResponse) unknownExtensionObject;
 
-                                        onConnectActivateSessionRequest(context, responseMessage, (CreateSessionResponse) message.getBody());
-                                    } else {
-                                        ServiceFault serviceFault = (ServiceFault) unknownExtensionObject;
-                                        ResponseHeader header = (ResponseHeader) serviceFault.getResponseHeader();
-                                        LOGGER.error("Subscription ServiceFault returned from server with error code,  '{}'", header.getServiceResult().toString());
+                                authenticationToken = responseMessage.getAuthenticationToken().getNodeId();
 
-                                    }
+                                onConnectActivateSessionRequest(context, responseMessage, (CreateSessionResponse) message.getBody());
+                            } else {
+                                ServiceFault serviceFault = (ServiceFault) unknownExtensionObject;
+                                ResponseHeader header = (ResponseHeader) serviceFault.getResponseHeader();
+                                LOGGER.error("Subscription ServiceFault returned from server with error code,  '{}'", header.getServiceResult().toString());
 
-                                } catch (PlcConnectionException e) {
-                                    LOGGER.error("Error occurred while connecting to OPC UA server");
-                                } catch (ParseException e) {
-                                    LOGGER.error("Unable to parse the returned Subscription response");
-                                    e.printStackTrace();
-                                }
                             }
+
+                        } catch (PlcConnectionException e) {
+                            LOGGER.error("Error occurred while connecting to OPC UA server");
                         } catch (ParseException e) {
+                            LOGGER.error("Unable to parse the returned Subscription response");
                             e.printStackTrace();
                         }
+                    }
+                } catch (ParseException e) {
+                    e.printStackTrace();
+                }
 
-                    };
+            };
 
             Consumer<TimeoutException> timeout = e -> {
                 LOGGER.error("Timeout while waiting for subscription response");
@@ -477,9 +447,9 @@ public class SecureChannel {
         String[] endpoints = new String[3];
         try {
             InetAddress address = InetAddress.getByName(this.configuration.getHost());
-            endpoints[0] = "opc.tcp://" + address.getHostAddress() + ":" + configuration.getPort() +  configuration.getTransportEndpoint();
-            endpoints[1] = "opc.tcp://" + address.getHostName() + ":" + configuration.getPort() +  configuration.getTransportEndpoint();
-            endpoints[2] = "opc.tcp://" + address.getCanonicalHostName() + ":" + configuration.getPort() +  configuration.getTransportEndpoint();
+            endpoints[0] = "opc.tcp://" + address.getHostAddress() + ":" + configuration.getPort() + configuration.getTransportEndpoint();
+            endpoints[1] = "opc.tcp://" + address.getHostName() + ":" + configuration.getPort() + configuration.getTransportEndpoint();
+            endpoints[2] = "opc.tcp://" + address.getCanonicalHostName() + ":" + configuration.getPort() + configuration.getTransportEndpoint();
         } catch (UnknownHostException e) {
             e.printStackTrace();
         }
@@ -522,10 +492,6 @@ public class SecureChannel {
 
         SignatureData clientSignature = new SignatureData(NULL_STRING, NULL_BYTE_STRING);
 
-        SignedSoftwareCertificate[] signedSoftwareCertificate = new SignedSoftwareCertificate[1];
-
-        signedSoftwareCertificate[0] = new SignedSoftwareCertificate(NULL_BYTE_STRING, NULL_BYTE_STRING);
-
         ActivateSessionRequest activateSessionRequest = new ActivateSessionRequest(
             requestHeader,
             clientSignature,
@@ -538,7 +504,7 @@ public class SecureChannel {
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(activateSessionRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(activateSessionRequest.getIdentifier())),
             null,
             null);
 
@@ -657,7 +623,7 @@ public class SecureChannel {
                             if (unknownExtensionObject instanceof CloseSessionResponse) {
                                 responseMessage = (CloseSessionResponse) unknownExtensionObject;
 
-                                LOGGER.trace("Got Close Session Response Connection Response" + responseMessage.toString());
+                                LOGGER.trace("Got Close Session Response Connection Response" + responseMessage);
                                 onDisconnectCloseSecureChannel(context);
                             } else {
                                 ServiceFault serviceFault = (ServiceFault) unknownExtensionObject;
@@ -707,7 +673,7 @@ public class SecureChannel {
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(closeSecureChannelRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(closeSecureChannelRequest.getIdentifier())),
             null,
             null);
 
@@ -726,16 +692,8 @@ public class SecureChannel {
                 .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
                 .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
                 .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
-                .check(p -> {
-                    if (p.getRequestId() == transactionId) {
-                        return true;
-                    } else {
-                        return false;
-                    }
-                })
-                .handle(opcuaMessageResponse -> {
-                    LOGGER.trace("Got Close Secure Channel Response" + opcuaMessageResponse.toString());
-                });
+                .check(p -> p.getRequestId() == transactionId)
+                .handle(opcuaMessageResponse -> LOGGER.trace("Got Close Secure Channel Response" + opcuaMessageResponse.toString()));
 
             context.fireDisconnected();
         };
@@ -756,16 +714,14 @@ public class SecureChannel {
             DEFAULT_MAX_CHUNK_COUNT,
             this.endpoint);
 
-        Consumer<Integer> requestConsumer = t -> {
-            context.sendRequest(new OpcuaAPU(hello))
-                .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
-                .check(p -> p.getMessage() instanceof OpcuaAcknowledgeResponse)
-                .unwrap(p -> (OpcuaAcknowledgeResponse) p.getMessage())
-                .handle(opcuaAcknowledgeResponse -> {
-                    LOGGER.debug("Got Hello Response Connection Response");
-                    onDiscoverOpenSecureChannel(context, opcuaAcknowledgeResponse);
-                });
-        };
+        Consumer<Integer> requestConsumer = t -> context.sendRequest(new OpcuaAPU(hello))
+            .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+            .check(p -> p.getMessage() instanceof OpcuaAcknowledgeResponse)
+            .unwrap(p -> (OpcuaAcknowledgeResponse) p.getMessage())
+            .handle(opcuaAcknowledgeResponse -> {
+                LOGGER.debug("Got Hello Response Connection Response");
+                onDiscoverOpenSecureChannel(context, opcuaAcknowledgeResponse);
+            });
 
         channelTransactionManager.submit(requestConsumer, 1);
     }
@@ -791,7 +747,7 @@ public class SecureChannel {
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(openSecureChannelRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(openSecureChannelRequest.getIdentifier())),
             null,
             null);
 
@@ -812,37 +768,29 @@ public class SecureChannel {
                 transactionId,
                 buffer.getData());
 
-            Consumer<Integer> requestConsumer = t -> {
-                context.sendRequest(new OpcuaAPU(openRequest))
-                    .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
-                    .check(p -> p.getMessage() instanceof OpcuaOpenResponse)
-                    .unwrap(p -> (OpcuaOpenResponse) p.getMessage())
-                    .check(p -> {
-                        if (p.getRequestId() == transactionId) {
-                            return true;
+            Consumer<Integer> requestConsumer = t -> context.sendRequest(new OpcuaAPU(openRequest))
+                .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+                .check(p -> p.getMessage() instanceof OpcuaOpenResponse)
+                .unwrap(p -> (OpcuaOpenResponse) p.getMessage())
+                .check(p -> p.getRequestId() == transactionId)
+                .handle(opcuaOpenResponse -> {
+                    try {
+                        ExtensionObject message = ExtensionObjectIO.staticParse(new ReadBufferByteBased(opcuaOpenResponse.getMessage(), org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN), false);
+                        if (message.getBody() instanceof ServiceFault) {
+                            ServiceFault fault = (ServiceFault) message.getBody();
+                            LOGGER.error("Failed to connect to opc ua server for the following reason:- {}, {}", ((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode(), OpcuaStatusCode.enumForValue(((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode()));
                         } else {
-                            return false;
-                        }
-                    })
-                    .handle(opcuaOpenResponse -> {
-                        try {
-                            ExtensionObject message = ExtensionObjectIO.staticParse(new ReadBufferByteBased(opcuaOpenResponse.getMessage(), org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN), false);
-                            if (message.getBody() instanceof ServiceFault) {
-                                ServiceFault fault = (ServiceFault) message.getBody();
-                                LOGGER.error("Failed to connect to opc ua server for the following reason:- {}, {}", ((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode(), OpcuaStatusCode.enumForValue(((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode()));
-                            } else {
-                                LOGGER.debug("Got Secure Response Connection Response");
-                                try {
-                                    onDiscoverGetEndpointsRequest(context, opcuaOpenResponse, (OpenSecureChannelResponse) message.getBody());
-                                } catch (PlcConnectionException e) {
-                                    LOGGER.error("Error occurred while connecting to OPC UA server");
-                                }
+                            LOGGER.debug("Got Secure Response Connection Response");
+                            try {
+                                onDiscoverGetEndpointsRequest(context, opcuaOpenResponse, (OpenSecureChannelResponse) message.getBody());
+                            } catch (PlcConnectionException e) {
+                                LOGGER.error("Error occurred while connecting to OPC UA server");
                             }
-                        } catch (ParseException e) {
-                            e.printStackTrace();
                         }
-                    });
-            };
+                    } catch (ParseException e) {
+                        e.printStackTrace();
+                    }
+                });
 
             channelTransactionManager.submit(requestConsumer, transactionId);
         } catch (ParseException e) {
@@ -851,18 +799,17 @@ public class SecureChannel {
     }
 
     public void onDiscoverGetEndpointsRequest(ConversationContext<OpcuaAPU> context, OpcuaOpenResponse opcuaOpenResponse, OpenSecureChannelResponse openSecureChannelResponse) throws PlcConnectionException {
-        certificateThumbprint = opcuaOpenResponse.getReceiverCertificateThumbprint();
         tokenId.set((int) ((ChannelSecurityToken) openSecureChannelResponse.getSecurityToken()).getTokenId());
         channelId.set((int) ((ChannelSecurityToken) openSecureChannelResponse.getSecurityToken()).getChannelId());
 
         int transactionId = channelTransactionManager.getTransactionIdentifier();
 
-        Integer nextSequenceNumber = opcuaOpenResponse.getSequenceNumber() + 1;
-        Integer nextRequestId = opcuaOpenResponse.getRequestId() + 1;
+        int nextSequenceNumber = opcuaOpenResponse.getSequenceNumber() + 1;
+        int nextRequestId = opcuaOpenResponse.getRequestId() + 1;
 
         if (!(transactionId == nextSequenceNumber)) {
-            LOGGER.error("Sequence number isn't as expected, we might have missed a packet. - " +  transactionId + " != " + nextSequenceNumber);
-            throw new PlcConnectionException("Sequence number isn't as expected, we might have missed a packet. - " +  transactionId + " != " + nextSequenceNumber);
+            LOGGER.error("Sequence number isn't as expected, we might have missed a packet. - " + transactionId + " != " + nextSequenceNumber);
+            throw new PlcConnectionException("Sequence number isn't as expected, we might have missed a packet. - " + transactionId + " != " + nextSequenceNumber);
         }
 
         RequestHeader requestHeader = new RequestHeader(new NodeId(authenticationToken),
@@ -883,7 +830,7 @@ public class SecureChannel {
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(endpointsRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(endpointsRequest.getIdentifier())),
             null,
             null);
 
@@ -901,50 +848,43 @@ public class SecureChannel {
                 nextRequestId,
                 buffer.getData());
 
-            Consumer<Integer> requestConsumer = t -> {
-                context.sendRequest(new OpcuaAPU(messageRequest))
-                    .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
-                    .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
-                    .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
-                    .check(p -> {
-                        if (p.getRequestId() == transactionId) {
-                            return true;
+            Consumer<Integer> requestConsumer = t -> context.sendRequest(new OpcuaAPU(messageRequest))
+                .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+                .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
+                .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
+                .check(p -> p.getRequestId() == transactionId)
+                .handle(opcuaMessageResponse -> {
+                    try {
+                        ExtensionObject message = ExtensionObjectIO.staticParse(new ReadBufferByteBased(opcuaMessageResponse.getMessage(), org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN), false);
+                        if (message.getBody() instanceof ServiceFault) {
+                            ServiceFault fault = (ServiceFault) message.getBody();
+                            LOGGER.error("Failed to connect to opc ua server for the following reason:- {}, {}", ((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode(), OpcuaStatusCode.enumForValue(((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode()));
                         } else {
-                            return false;
-                        }
-                    })
-                    .handle(opcuaMessageResponse -> {
-                        try {
-                            ExtensionObject message = ExtensionObjectIO.staticParse(new ReadBufferByteBased(opcuaMessageResponse.getMessage(), org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN), false);
-                            if (message.getBody() instanceof ServiceFault) {
-                                ServiceFault fault = (ServiceFault) message.getBody();
-                                LOGGER.error("Failed to connect to opc ua server for the following reason:- {}, {}", ((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode(), OpcuaStatusCode.enumForValue(((ResponseHeader) fault.getResponseHeader()).getServiceResult().getStatusCode()));
-                            } else {
-                                LOGGER.debug("Got Create Session Response Connection Response");
-                                GetEndpointsResponse response = (GetEndpointsResponse) message.getBody();
-
-                                EndpointDescription[] endpoints = (EndpointDescription[]) response.getEndpoints();
-                                for (EndpointDescription endpoint : endpoints) {
-                                    if (endpoint.getEndpointUrl().getStringValue().equals(this.endpoint.getStringValue()) && endpoint.getSecurityPolicyUri().getStringValue().equals(this.securityPolicy)) {
-                                        LOGGER.info("Found OPC UA endpoint {}", this.endpoint.getStringValue());
-                                        this.configuration.setSenderCertificate(endpoint.getServerCertificate().getStringValue());
-                                    }
+                            LOGGER.debug("Got Create Session Response Connection Response");
+                            GetEndpointsResponse response = (GetEndpointsResponse) message.getBody();
+
+                            List<ExtensionObjectDefinition> endpoints = response.getEndpoints();
+                            for (ExtensionObjectDefinition endpoint : endpoints) {
+                                EndpointDescription endpointDescription = (EndpointDescription) endpoint;
+                                if (endpointDescription.getEndpointUrl().getStringValue().equals(this.endpoint.getStringValue()) && endpointDescription.getSecurityPolicyUri().getStringValue().equals(this.securityPolicy)) {
+                                    LOGGER.info("Found OPC UA endpoint {}", this.endpoint.getStringValue());
+                                    this.configuration.setSenderCertificate(endpointDescription.getServerCertificate().getStringValue());
                                 }
+                            }
 
-                                try {
-                                    MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
-                                    byte[] digest = messageDigest.digest(this.configuration.getSenderCertificate());
-                                    this.configuration.setThumbprint(new PascalByteString(digest.length, digest));
-                                } catch (NoSuchAlgorithmException e) {
-                                    LOGGER.error("Failed to find hashing algorithm");
-                                }
-                                onDiscoverCloseSecureChannel(context, response);
+                            try {
+                                MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
+                                byte[] digest = messageDigest.digest(this.configuration.getSenderCertificate());
+                                this.configuration.setThumbprint(new PascalByteString(digest.length, digest));
+                            } catch (NoSuchAlgorithmException e) {
+                                LOGGER.error("Failed to find hashing algorithm");
                             }
-                        } catch (ParseException e) {
-                            e.printStackTrace();
+                            onDiscoverCloseSecureChannel(context, response);
                         }
-                    });
-            };
+                    } catch (ParseException e) {
+                        e.printStackTrace();
+                    }
+                });
 
             channelTransactionManager.submit(requestConsumer, transactionId);
         } catch (ParseException e) {
@@ -968,7 +908,7 @@ public class SecureChannel {
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(closeSecureChannelRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(closeSecureChannelRequest.getIdentifier())),
             null,
             null);
 
@@ -982,112 +922,97 @@ public class SecureChannel {
                 null,
                 closeSecureChannelRequest));
 
-        Consumer<Integer> requestConsumer = t -> {
-            context.sendRequest(new OpcuaAPU(closeRequest))
-                .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
-                .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
-                .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
-                .check(p -> {
-                    if (p.getRequestId() == transactionId) {
-                        return true;
-                    } else {
-                        return false;
-                    }
-                })
-                .handle(opcuaMessageResponse -> {
-                    LOGGER.trace("Got Close Secure Channel Response" + opcuaMessageResponse.toString());
-                    // Send an event that connection setup is complete.
-                    context.fireDiscovered(this.configuration);
-                });
-        };
+        Consumer<Integer> requestConsumer = t -> context.sendRequest(new OpcuaAPU(closeRequest))
+            .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+            .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
+            .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
+            .check(p -> p.getRequestId() == transactionId)
+            .handle(opcuaMessageResponse -> {
+                LOGGER.trace("Got Close Secure Channel Response" + opcuaMessageResponse.toString());
+                // Send an event that connection setup is complete.
+                context.fireDiscovered(this.configuration);
+            });
 
         channelTransactionManager.submit(requestConsumer, transactionId);
     }
 
     private void keepAlive() {
         keepAlive = CompletableFuture.supplyAsync(() -> {
-            while(true) {
-
-                try {
-                    Thread.sleep((long) Math.ceil(this.lifetime * 0.75f));
-                } catch (InterruptedException e) {
-                    LOGGER.trace("Interrupted Exception");
-                }
-
-                int transactionId = channelTransactionManager.getTransactionIdentifier();
-
-                RequestHeader requestHeader = new RequestHeader(new NodeId(authenticationToken),
-                    getCurrentDateTime(),
-                    0L,                                         //RequestHandle
-                    0L,
-                    NULL_STRING,
-                    REQUEST_TIMEOUT_LONG,
-                    NULL_EXTENSION_OBJECT);
-
-                OpenSecureChannelRequest openSecureChannelRequest = null;
-                if (this.isEncrypted) {
-                    openSecureChannelRequest = new OpenSecureChannelRequest(
-                        requestHeader,
-                        VERSION,
-                        SecurityTokenRequestType.securityTokenRequestTypeIssue,
-                        MessageSecurityMode.messageSecurityModeSignAndEncrypt,
-                        new PascalByteString(clientNonce.length, clientNonce),
-                        lifetime);
-                } else {
-                    openSecureChannelRequest = new OpenSecureChannelRequest(
-                        requestHeader,
-                        VERSION,
-                        SecurityTokenRequestType.securityTokenRequestTypeIssue,
-                        MessageSecurityMode.messageSecurityModeNone,
-                        NULL_BYTE_STRING,
-                        lifetime);
-                }
-
-                ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
-                    false,            //Server Index Specified
-                    new NodeIdFourByte((short) 0, Integer.valueOf(openSecureChannelRequest.getIdentifier())),
-                    null,
-                    null);
-
-                ExtensionObject extObject = new ExtensionObject(
-                    expandedNodeId,
-                    null,
-                    openSecureChannelRequest);
+                while (true) {
 
-                try {
-                    WriteBufferByteBased buffer = new WriteBufferByteBased(extObject.getLengthInBytes(), org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN);
-                    ExtensionObjectIO.staticSerialize(buffer, extObject);
+                    try {
+                        Thread.sleep((long) Math.ceil(this.lifetime * 0.75f));
+                    } catch (InterruptedException e) {
+                        LOGGER.trace("Interrupted Exception");
+                    }
 
-                    OpcuaOpenRequest openRequest = new OpcuaOpenRequest(FINAL_CHUNK,
-                        0,
-                        new PascalString(this.securityPolicy),
-                        this.publicCertificate,
-                        this.thumbprint,
-                        transactionId,
-                        transactionId,
-                        buffer.getData());
+                    int transactionId = channelTransactionManager.getTransactionIdentifier();
 
-                    final OpcuaAPU apu;
+                    RequestHeader requestHeader = new RequestHeader(new NodeId(authenticationToken),
+                        getCurrentDateTime(),
+                        0L,                                         //RequestHandle
+                        0L,
+                        NULL_STRING,
+                        REQUEST_TIMEOUT_LONG,
+                        NULL_EXTENSION_OBJECT);
 
+                    OpenSecureChannelRequest openSecureChannelRequest;
                     if (this.isEncrypted) {
-                        apu = OpcuaAPUIO.staticParse(encryptionHandler.encodeMessage(openRequest, buffer.getData()), false);
+                        openSecureChannelRequest = new OpenSecureChannelRequest(
+                            requestHeader,
+                            VERSION,
+                            SecurityTokenRequestType.securityTokenRequestTypeIssue,
+                            MessageSecurityMode.messageSecurityModeSignAndEncrypt,
+                            new PascalByteString(clientNonce.length, clientNonce),
+                            lifetime);
                     } else {
-                        apu = new OpcuaAPU(openRequest);
+                        openSecureChannelRequest = new OpenSecureChannelRequest(
+                            requestHeader,
+                            VERSION,
+                            SecurityTokenRequestType.securityTokenRequestTypeIssue,
+                            MessageSecurityMode.messageSecurityModeNone,
+                            NULL_BYTE_STRING,
+                            lifetime);
                     }
 
-                    Consumer<Integer> requestConsumer = t -> {
-                        context.sendRequest(apu)
+                    ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
+                        false,            //Server Index Specified
+                        new NodeIdFourByte((short) 0, Integer.parseInt(openSecureChannelRequest.getIdentifier())),
+                        null,
+                        null);
+
+                    ExtensionObject extObject = new ExtensionObject(
+                        expandedNodeId,
+                        null,
+                        openSecureChannelRequest);
+
+                    try {
+                        WriteBufferByteBased buffer = new WriteBufferByteBased(extObject.getLengthInBytes(), org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN);
+                        ExtensionObjectIO.staticSerialize(buffer, extObject);
+
+                        OpcuaOpenRequest openRequest = new OpcuaOpenRequest(FINAL_CHUNK,
+                            0,
+                            new PascalString(this.securityPolicy),
+                            this.publicCertificate,
+                            this.thumbprint,
+                            transactionId,
+                            transactionId,
+                            buffer.getData());
+
+                        final OpcuaAPU apu;
+
+                        if (this.isEncrypted) {
+                            apu = OpcuaAPUIO.staticParse(encryptionHandler.encodeMessage(openRequest, buffer.getData()), false);
+                        } else {
+                            apu = new OpcuaAPU(openRequest);
+                        }
+
+                        Consumer<Integer> requestConsumer = t -> context.sendRequest(apu)
                             .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
                             .unwrap(apuMessage -> encryptionHandler.decodeMessage(apuMessage))
                             .check(p -> p.getMessage() instanceof OpcuaOpenResponse)
                             .unwrap(p -> (OpcuaOpenResponse) p.getMessage())
-                            .check(p -> {
-                                if (p.getRequestId() == transactionId) {
-                                    return true;
-                                } else {
-                                    return false;
-                                }
-                            })
+                            .check(p -> p.getRequestId() == transactionId)
                             .handle(opcuaOpenResponse -> {
                                 try {
                                     ReadBufferByteBased readBuffer = new ReadBufferByteBased(opcuaOpenResponse.getMessage(), org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN);
@@ -1100,7 +1025,6 @@ public class SecureChannel {
                                         LOGGER.debug("Got Secure Response Connection Response");
                                         OpenSecureChannelResponse openSecureChannelResponse = (OpenSecureChannelResponse) message.getBody();
                                         ChannelSecurityToken token = (ChannelSecurityToken) openSecureChannelResponse.getSecurityToken();
-                                        certificateThumbprint = opcuaOpenResponse.getReceiverCertificateThumbprint();
                                         tokenId.set((int) token.getTokenId());
                                         channelId.set((int) token.getChannelId());
                                         lifetime = token.getRevisedLifetime();
@@ -1109,13 +1033,12 @@ public class SecureChannel {
                                     e.printStackTrace();
                                 }
                             });
-                    };
-                    channelTransactionManager.submit(requestConsumer, transactionId);
-                } catch (ParseException e) {
-                    LOGGER.error("Unable to to Parse Open Secure Request");
+                        channelTransactionManager.submit(requestConsumer, transactionId);
+                    } catch (ParseException e) {
+                        LOGGER.error("Unable to to Parse Open Secure Request");
+                    }
                 }
             }
-            }
         );
     }
 
@@ -1126,7 +1049,7 @@ public class SecureChannel {
      */
     public int getRequestHandle() {
         int transactionId = requestHandleGenerator.getAndIncrement();
-        if(requestHandleGenerator.get() == SecureChannelTransactionManager.DEFAULT_MAX_REQUEST_ID) {
+        if (requestHandleGenerator.get() == SecureChannelTransactionManager.DEFAULT_MAX_REQUEST_ID) {
             requestHandleGenerator.set(1);
         }
         return transactionId;
@@ -1151,25 +1074,17 @@ public class SecureChannel {
     }
 
     /**
-     * Gets the Token Identifier
-     *
-     * @return int representing the token identifier
-     */
-    public int getTokenId() {
-        return this.tokenId.get();
-    }
-
-    /**
      * Creates an IdentityToken to authenticate with a server.
-     * @param securityPolicy
+     *
+     * @param tokenType      the token type
+     * @param securityPolicy the security policy
      * @return returns an ExtensionObject with an IdentityToken.
      */
     private ExtensionObject getIdentityToken(UserTokenType tokenType, String securityPolicy) {
-        ExpandedNodeId extExpandedNodeId = null;
-        ExtensionObject userIdentityToken = null;
+        ExpandedNodeId extExpandedNodeId;
         switch (tokenType) {
             case userTokenTypeAnonymous:
-                //If we aren't using authentication tell the server we would like to login anonymously
+                //If we aren't using authentication tell the server we would like to log in anonymously
                 AnonymousIdentityToken anonymousIdentityToken = new AnonymousIdentityToken();
 
                 extExpandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
@@ -1195,7 +1110,7 @@ public class SecureChannel {
                 encodeableBuffer.get(encodeablePassword);
 
                 byte[] encryptedPassword = encryptionHandler.encryptPassword(encodeablePassword);
-                UserNameIdentityToken userNameIdentityToken =  new UserNameIdentityToken(
+                UserNameIdentityToken userNameIdentityToken = new UserNameIdentityToken(
                     new PascalString(this.username),
                     new PascalByteString(encryptedPassword.length, encryptedPassword),
                     new PascalString(PASSWORD_ENCRYPTION_ALGORITHM)
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannelTransactionManager.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannelTransactionManager.java
index e9d5d2b..e22574a 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannelTransactionManager.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/context/SecureChannelTransactionManager.java
@@ -19,22 +19,12 @@
 package org.apache.plc4x.java.opcua.context;
 
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.apache.plc4x.java.opcua.readwrite.OpcuaAPU;
-import org.apache.plc4x.java.opcua.readwrite.OpcuaMessageRequest;
-import org.apache.plc4x.java.opcua.readwrite.OpcuaMessageResponse;
-import org.apache.plc4x.java.spi.ConversationContext;
-import org.apache.plc4x.java.spi.context.DriverContext;
-import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.Map;
-import java.util.Queue;
-import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 public class SecureChannelTransactionManager {
@@ -93,10 +83,10 @@ public class SecureChannelTransactionManager {
         return transactionId;
     }
 
-    public class Transaction {
+    public static class Transaction {
 
-        private Integer transactionId;
-        private Consumer<Integer> consumer;
+        private final Integer transactionId;
+        private final Consumer<Integer> consumer;
 
         public Transaction(Consumer<Integer> consumer, Integer transactionId) {
             this.consumer = consumer;
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/field/OpcuaField.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/field/OpcuaField.java
index 8dd6df9..204013a 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/field/OpcuaField.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/field/OpcuaField.java
@@ -21,7 +21,6 @@ package org.apache.plc4x.java.opcua.field;
 import org.apache.commons.lang3.EnumUtils;
 import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.exceptions.PlcUnsupportedDataTypeException;
-import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.model.PlcSubscriptionField;
 import org.apache.plc4x.java.api.types.PlcSubscriptionType;
 import org.apache.plc4x.java.opcua.readwrite.types.OpcuaIdentifierType;
@@ -68,7 +67,7 @@ public class OpcuaField implements PlcSubscriptionField {
         OpcuaIdentifierType identifierType = OpcuaIdentifierType.enumForValue(identifierTypeString);
 
         String namespaceString = matcher.group("namespace");
-        Integer namespace = namespaceString != null ? Integer.valueOf(namespaceString) : 0;
+        Integer namespace = namespaceString != null ? Integer.parseInt(namespaceString) : 0;
 
         String dataTypeString = matcher.group("datatype") != null ? matcher.group("datatype").toUpperCase() : "NULL";
         if (!EnumUtils.isValidEnum(OpcuaDataType.class, dataTypeString)) {
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
index df59d3c..03b38df 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
@@ -134,7 +134,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             SecureChannel.REQUEST_TIMEOUT_LONG,
             NULL_EXTENSION_OBJECT);
 
-        ReadValueId[] readValueArray = new ReadValueId[request.getFieldNames().size()];
+        List<ExtensionObjectDefinition> readValueArray = new ArrayList<>(request.getFieldNames().size());
         Iterator<String> iterator = request.getFieldNames().iterator();
         for (int i = 0; i < request.getFieldNames().size(); i++ ) {
             String fieldName = iterator.next();
@@ -142,22 +142,22 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
 
             NodeId nodeId = generateNodeId(field);
 
-            readValueArray[i] = new ReadValueId(nodeId,
+            readValueArray.add(new ReadValueId(nodeId,
                 0xD,
                 NULL_STRING,
-                new QualifiedName(0, NULL_STRING));
+                new QualifiedName(0, NULL_STRING)));
         }
 
         ReadRequest opcuaReadRequest = new ReadRequest(
             requestHeader,
             0.0d,
             TimestampsToReturn.timestampsToReturnNeither,
-            readValueArray.length,
+            readValueArray.size(),
             readValueArray);
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(opcuaReadRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(opcuaReadRequest.getIdentifier())),
             null,
             null);
 
@@ -177,18 +177,15 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                     response = new DefaultPlcReadResponse(request, readResponse(request.getFieldNames(), ((ReadResponse) ExtensionObjectIO.staticParse(new ReadBufferByteBased(opcuaResponse, ByteOrder.LITTLE_ENDIAN), false).getBody()).getResults()));
                 } catch (ParseException e) {
                     e.printStackTrace();
-                };
+                }
 
                 // Pass the response back to the application.
                 future.complete(response);
             };
 
             /* Functional Consumer example using inner class */
-            Consumer<TimeoutException> timeout = t -> {
-
-                // Pass the response back to the application.
-                future.completeExceptionally(t);
-            };
+            // Pass the response back to the application.
+            Consumer<TimeoutException> timeout = future::completeExceptionally;
 
             /* Functional Consumer example using inner class */
             BiConsumer<OpcuaAPU, Throwable> error = (message, t) -> {
@@ -209,9 +206,9 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
     private NodeId generateNodeId(OpcuaField field) {
         NodeId nodeId = null;
         if (field.getIdentifierType() == OpcuaIdentifierType.BINARY_IDENTIFIER) {
-            nodeId = new NodeId(new NodeIdTwoByte(Short.valueOf(field.getIdentifier())));
+            nodeId = new NodeId(new NodeIdTwoByte(Short.parseShort(field.getIdentifier())));
         } else if (field.getIdentifierType() == OpcuaIdentifierType.NUMBER_IDENTIFIER) {
-            nodeId = new NodeId(new NodeIdNumeric((short) field.getNamespace(), Long.valueOf(field.getIdentifier())));
+            nodeId = new NodeId(new NodeIdNumeric((short) field.getNamespace(), Long.parseLong(field.getIdentifier())));
         } else if (field.getIdentifierType() == OpcuaIdentifierType.GUID_IDENTIFIER) {
             UUID guid = UUID.fromString(field.getIdentifier());
             byte[] guidBytes = new byte[16];
@@ -224,196 +221,153 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
         return nodeId;
     }
 
-    public Map<String, ResponseItem<PlcValue>> readResponse(LinkedHashSet<String> fieldNames, DataValue[] results) {
+    public Map<String, ResponseItem<PlcValue>> readResponse(LinkedHashSet<String> fieldNames, List<DataValue> results) {
         PlcResponseCode responseCode = PlcResponseCode.OK;
         Map<String, ResponseItem<PlcValue>> response = new HashMap<>();
         int count = 0;
         for ( String field : fieldNames ) {
             PlcValue value = null;
-            if (results[count].getValueSpecified()) {
-                Variant variant = results[count].getValue();
+            if (results.get(count).getValueSpecified()) {
+                Variant variant = results.get(count).getValue();
                 LOGGER.trace("Response of type {}", variant.getClass().toString());
                 if (variant instanceof VariantBoolean) {
                     byte[] array = ((VariantBoolean) variant).getValue();
                     int length = array.length;
                     Boolean[] tmpValue = new Boolean[length];
                     for (int i = 0; i < length; i++) {
-                        if (array[i] == 0) {
-                            tmpValue[i] = false;
-                        } else {
-                            tmpValue[i] = true;
-                        }
+                        tmpValue[i] = array[i] != 0;
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantSByte) {
                     byte[] array = ((VariantSByte) variant).getValue();
-                    int length = array.length;
-                    Byte[] tmpValue = new Byte[length];
-                    for (int i = 0; i < length; i++) {
-                        tmpValue[i] = array[i];
-                    }
-                    value = IEC61131ValueHandler.of(tmpValue);
+                    value = IEC61131ValueHandler.of(array);
                 } else if (variant instanceof VariantByte) {
-                    short[] array = ((VariantByte) variant).getValue();
-                    int length = array.length;
-                    Short[] tmpValue = new Short[length];
-                    for (int i = 0; i < length; i++) {
-                        tmpValue[i] = array[i];
-                    }
+                    List<Short> array = ((VariantByte) variant).getValue();
+                    Short[] tmpValue = array.toArray(new Short[0]);
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantInt16) {
-                    short[] array = ((VariantInt16) variant).getValue();
-                    int length = array.length;
-                    Short[] tmpValue = new Short[length];
-                    for (int i = 0; i < length; i++) {
-                        tmpValue[i] = array[i];
-                    }
+                    List<Short> array = ((VariantInt16) variant).getValue();
+                    Short[] tmpValue = array.toArray(new Short[0]);
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantUInt16) {
-                    int[] array = ((VariantUInt16) variant).getValue();
-                    int length = array.length;
-                    Integer[] tmpValue = new Integer[length];
-                    for (int i = 0; i < length; i++) {
-                        tmpValue[i] = array[i];
-                    }
+                    List<Integer> array = ((VariantUInt16) variant).getValue();
+                    Integer[] tmpValue = array.toArray(new Integer[0]);
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantInt32) {
-                    int[] array = ((VariantInt32) variant).getValue();
-                    int length = array.length;
-                    Integer[] tmpValue = new Integer[length];
-                    for (int i = 0; i < length; i++) {
-                        tmpValue[i] = array[i];
-                    }
+                    List<Integer> array = ((VariantInt32) variant).getValue();
+                    Integer[] tmpValue = array.toArray(new Integer[0]);
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantUInt32) {
-                    long[] array = ((VariantUInt32) variant).getValue();
-                    int length = array.length;
-                    Long[] tmpValue = new Long[length];
-                    for (int i = 0; i < length; i++) {
-                        tmpValue[i] = array[i];
-                    }
+                    List<Long> array = ((VariantUInt32) variant).getValue();
+                    Long[] tmpValue = array.toArray(new Long[0]);
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantInt64) {
-                    long[] array = ((VariantInt64) variant).getValue();
-                    int length = array.length;
-                    Long[] tmpValue = new Long[length];
-                    for (int i = 0; i < length; i++) {
-                        tmpValue[i] = array[i];
-                    }
+                    List<Long> array = ((VariantInt64) variant).getValue();
+                    Long[] tmpValue = array.toArray(new Long[0]);
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantUInt64) {
                     value = IEC61131ValueHandler.of(((VariantUInt64) variant).getValue());
                 } else if (variant instanceof VariantFloat) {
-                    float[] array = ((VariantFloat) variant).getValue();
-                    int length = array.length;
-                    Float[] tmpValue = new Float[length];
-                    for (int i = 0; i < length; i++) {
-                        tmpValue[i] = array[i];
-                    }
+                    List<Float> array = ((VariantFloat) variant).getValue();
+                    Float[] tmpValue = array.toArray(new Float[0]);
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantDouble) {
-                    double[] array = ((VariantDouble) variant).getValue();
-                    int length = array.length;
-                    Double[] tmpValue = new Double[length];
-                    for (int i = 0; i < length; i++) {
-                        tmpValue[i] = array[i];
-                    }
+                    List<Double> array = ((VariantDouble) variant).getValue();
+                    Double[] tmpValue = array.toArray(new Double[0]);
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantString) {
-                    int length = ((VariantString) variant).getValue().length;
-                    PascalString[] stringArray = ((VariantString) variant).getValue();
+                    int length = ((VariantString) variant).getValue().size();
+                    List<PascalString> stringArray = ((VariantString) variant).getValue();
                     String[] tmpValue = new String[length];
                     for (int i = 0; i < length; i++) {
-                        tmpValue[i] = stringArray[i].getStringValue();
+                        tmpValue[i] = stringArray.get(i).getStringValue();
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantDateTime) {
-                    long[] array = ((VariantDateTime) variant).getValue();
-                    int length = array.length;
+                    List<Long> array = ((VariantDateTime) variant).getValue();
+                    int length = array.size();
                     LocalDateTime[] tmpValue = new LocalDateTime[length];
                     for (int i = 0; i < length; i++) {
-                        tmpValue[i] = LocalDateTime.ofInstant(Instant.ofEpochMilli(getDateTime(array[i])), ZoneOffset.UTC);
+                        tmpValue[i] = LocalDateTime.ofInstant(Instant.ofEpochMilli(getDateTime(array.get(i))), ZoneOffset.UTC);
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantGuid) {
-                    GuidValue[] array = ((VariantGuid) variant).getValue();
-                    int length = array.length;
+                    List<GuidValue> array = ((VariantGuid) variant).getValue();
+                    int length = array.size();
                     String[] tmpValue = new String[length];
                     for (int i = 0; i < length; i++) {
                         //These two data section aren't little endian like the rest.
-                        byte[] data4Bytes = array[i].getData4();
+                        byte[] data4Bytes = array.get(i).getData4();
                         int data4 = 0;
-                        for (int k = 0; k < data4Bytes.length; k++)
-                        {
-                            data4 = (data4 << 8) + (data4Bytes[k] & 0xff);
+                        for (byte data4Byte : data4Bytes) {
+                            data4 = (data4 << 8) + (data4Byte & 0xff);
                         }
-                        byte[] data5Bytes = array[i].getData5();
+                        byte[] data5Bytes = array.get(i).getData5();
                         long data5 = 0;
-                        for (int k = 0; k < data5Bytes.length; k++)
-                        {
-                            data5 = (data5 << 8) + (data5Bytes[k] & 0xff);
+                        for (byte data5Byte : data5Bytes) {
+                            data5 = (data5 << 8) + (data5Byte & 0xff);
                         }
-                        tmpValue[i] = Long.toHexString(array[i].getData1()) + "-" + Integer.toHexString(array[i].getData2()) + "-" + Integer.toHexString(array[i].getData3()) + "-" + Integer.toHexString(data4) + "-" + Long.toHexString(data5);
+                        tmpValue[i] = Long.toHexString(array.get(i).getData1()) + "-" + Integer.toHexString(array.get(i).getData2()) + "-" + Integer.toHexString(array.get(i).getData3()) + "-" + Integer.toHexString(data4) + "-" + Long.toHexString(data5);
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantXmlElement) {
-                    int length = ((VariantXmlElement) variant).getValue().length;
-                    PascalString[] stringArray = ((VariantXmlElement) variant).getValue();
+                    int length = ((VariantXmlElement) variant).getValue().size();
+                    List<PascalString> strings = ((VariantXmlElement) variant).getValue();
                     String[] tmpValue = new String[length];
                     for (int i = 0; i < length; i++) {
-                        tmpValue[i] = stringArray[i].getStringValue();
+                        tmpValue[i] = strings.get(i).getStringValue();
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantLocalizedText) {
-                    int length = ((VariantLocalizedText) variant).getValue().length;
-                    LocalizedText[] stringArray = ((VariantLocalizedText) variant).getValue();
+                    int length = ((VariantLocalizedText) variant).getValue().size();
+                    List<LocalizedText> strings = ((VariantLocalizedText) variant).getValue();
                     String[] tmpValue = new String[length];
                     for (int i = 0; i < length; i++) {
                         tmpValue[i] = "";
-                        tmpValue[i] += stringArray[i].getLocaleSpecified() ? stringArray[i].getLocale().getStringValue() + "|" : "";
-                        tmpValue[i] += stringArray[i].getTextSpecified() ? stringArray[i].getText().getStringValue() : "";
+                        tmpValue[i] += strings.get(i).getLocaleSpecified() ? strings.get(i).getLocale().getStringValue() + "|" : "";
+                        tmpValue[i] += strings.get(i).getTextSpecified() ? strings.get(i).getText().getStringValue() : "";
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantQualifiedName) {
-                    int length = ((VariantQualifiedName) variant).getValue().length;
-                    QualifiedName[] stringArray = ((VariantQualifiedName) variant).getValue();
+                    int length = ((VariantQualifiedName) variant).getValue().size();
+                    List<QualifiedName> strings = ((VariantQualifiedName) variant).getValue();
                     String[] tmpValue = new String[length];
                     for (int i = 0; i < length; i++) {
-                        tmpValue[i] = "ns=" + stringArray[i].getNamespaceIndex() + ";s=" + stringArray[i].getName().getStringValue();
+                        tmpValue[i] = "ns=" + strings.get(i).getNamespaceIndex() + ";s=" + strings.get(i).getName().getStringValue();
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantExtensionObject) {
-                    int length = ((VariantExtensionObject) variant).getValue().length;
-                    ExtensionObject[] stringArray = ((VariantExtensionObject) variant).getValue();
+                    int length = ((VariantExtensionObject) variant).getValue().size();
+                    List<ExtensionObject> strings = ((VariantExtensionObject) variant).getValue();
                     String[] tmpValue = new String[length];
                     for (int i = 0; i < length; i++) {
-                        tmpValue[i] = stringArray[i].toString();
+                        tmpValue[i] = strings.get(i).toString();
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantNodeId) {
-                    int length = ((VariantNodeId) variant).getValue().length;
-                    NodeId[] stringArray = ((VariantNodeId) variant).getValue();
+                    int length = ((VariantNodeId) variant).getValue().size();
+                    List<NodeId> strings = ((VariantNodeId) variant).getValue();
                     String[] tmpValue = new String[length];
                     for (int i = 0; i < length; i++) {
-                        tmpValue[i] = stringArray[i].toString();
+                        tmpValue[i] = strings.get(i).toString();
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 }else if (variant instanceof VariantStatusCode) {
-                    int length = ((VariantStatusCode) variant).getValue().length;
-                    StatusCode[] stringArray = ((VariantStatusCode) variant).getValue();
+                    int length = ((VariantStatusCode) variant).getValue().size();
+                    List<StatusCode> strings = ((VariantStatusCode) variant).getValue();
                     String[] tmpValue = new String[length];
                     for (int i = 0; i < length; i++) {
-                        tmpValue[i] = stringArray[i].toString();
+                        tmpValue[i] = strings.get(i).toString();
                     }
                     value = IEC61131ValueHandler.of(tmpValue);
                 } else if (variant instanceof VariantByteString) {
                     PlcList plcList = new PlcList();
-                    ByteStringArray[] array = ((VariantByteString) variant).getValue();
-                    for (int k = 0; k < array.length; k++) {
-                        int length = array[k].getValue().length;
+                    List<ByteStringArray> array = ((VariantByteString) variant).getValue();
+                    for (ByteStringArray byteStringArray : array) {
+                        int length = byteStringArray.getValue().size();
                         Short[] tmpValue = new Short[length];
                         for (int i = 0; i < length; i++) {
-                            tmpValue[i] = array[k].getValue()[i];
+                            tmpValue[i] = byteStringArray.getValue().get(i);
                         }
                         plcList.add(IEC61131ValueHandler.of(tmpValue));
                     }
@@ -423,12 +377,12 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                     LOGGER.error("Data type - " +  variant.getClass() + " is not supported ");
                 }
             } else {
-                if (results[count].getStatusCode().getStatusCode() == OpcuaStatusCode.BadNodeIdUnknown.getValue()) {
+                if (results.get(count).getStatusCode().getStatusCode() == OpcuaStatusCode.BadNodeIdUnknown.getValue()) {
                     responseCode = PlcResponseCode.NOT_FOUND;
                 } else {
                     responseCode = PlcResponseCode.UNSUPPORTED;
                 }
-                LOGGER.error("Error while reading value from OPC UA server error code:- " + results[count].getStatusCode().toString());
+                LOGGER.error("Error while reading value from OPC UA server error code:- " + results.get(count).getStatusCode().toString());
             }
             count++;
             response.put(field, new ResponseItem<>(responseCode, value));
@@ -475,7 +429,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                 for (int i = 0; i < length; i++) {
                     tmpBOOL[i] = valueObject.getIndex(i).getByte();
                 }
-                return new VariantBoolean(length == 1 ? false : true,
+                return new VariantBoolean(length != 1,
                     false,
                     null,
                     null,
@@ -486,11 +440,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             case "USINT":
             case "UINT8":
             case "BIT8":
-                short[] tmpBYTE = new short[length];
+                List<Short> tmpBYTE = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpBYTE[i] = valueObject.getIndex(i).getByte();
+                    tmpBYTE.add((short) valueObject.getIndex(i).getByte());
                 }
-                return new VariantByte(length == 1 ? false : true,
+                return new VariantByte(length != 1,
                     false,
                     null,
                     null,
@@ -502,7 +456,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                 for (int i = 0; i < length; i++) {
                     tmpSINT[i] = valueObject.getIndex(i).getByte();
                 }
-                return new VariantSByte(length == 1 ? false : true,
+                return new VariantSByte(length != 1,
                     false,
                     null,
                     null,
@@ -510,11 +464,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                     tmpSINT);
             case "INT":
             case "INT16":
-                short[] tmpINT16 = new short[length];
+                List<Short> tmpINT16 = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpINT16[i] = valueObject.getIndex(i).getShort();
+                    tmpINT16.add(valueObject.getIndex(i).getShort());
                 }
-                return new VariantInt16(length == 1 ? false : true,
+                return new VariantInt16(length != 1,
                     false,
                     null,
                     null,
@@ -524,11 +478,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             case "UINT16":
             case "WORD":
             case "BITARR16":
-                int[] tmpUINT = new int[length];
+                List<Integer> tmpUINT = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpUINT[i] = valueObject.getIndex(i).getInt();
+                    tmpUINT.add(valueObject.getIndex(i).getInt());
                 }
-                return new VariantUInt16(length == 1 ? false : true,
+                return new VariantUInt16(length != 1,
                     false,
                     null,
                     null,
@@ -536,11 +490,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                     tmpUINT);
             case "DINT":
             case "INT32":
-                int[] tmpDINT = new int[length];
+                List<Integer> tmpDINT = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpDINT[i] = valueObject.getIndex(i).getInt();
+                    tmpDINT.add(valueObject.getIndex(i).getInt());
                 }
-                return new VariantInt32(length == 1 ? false : true,
+                return new VariantInt32(length != 1,
                     false,
                     null,
                     null,
@@ -550,11 +504,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             case "UINT32":
             case "DWORD":
             case "BITARR32":
-                long[] tmpUDINT = new long[length];
+                List<Long> tmpUDINT = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpUDINT[i] = valueObject.getIndex(i).getLong();
+                    tmpUDINT.add(valueObject.getIndex(i).getLong());
                 }
-                return new VariantUInt32(length == 1 ? false : true,
+                return new VariantUInt32(length != 1,
                     false,
                     null,
                     null,
@@ -562,11 +516,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                     tmpUDINT);
             case "LINT":
             case "INT64":
-                long[] tmpLINT = new long[length];
+                List<Long> tmpLINT = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpLINT[i] = valueObject.getIndex(i).getLong();
+                    tmpLINT.add(valueObject.getIndex(i).getLong());
                 }
-                return new VariantInt64(length == 1 ? false : true,
+                return new VariantInt64(length != 1,
                     false,
                     null,
                     null,
@@ -576,11 +530,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             case "UINT64":
             case "LWORD":
             case "BITARR64":
-                BigInteger[] tmpULINT = new BigInteger[length];
+                List<BigInteger> tmpULINT = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpULINT[i] = valueObject.getIndex(i).getBigInteger();
+                    tmpULINT.add(valueObject.getIndex(i).getBigInteger());
                 }
-                return new VariantUInt64(length == 1 ? false : true,
+                return new VariantUInt64(length != 1,
                     false,
                     null,
                     null,
@@ -588,11 +542,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                     tmpULINT);
             case "REAL":
             case "FLOAT":
-                float[] tmpREAL = new float[length];
+                List<Float> tmpREAL = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpREAL[i] = valueObject.getIndex(i).getFloat();
+                    tmpREAL.add(valueObject.getIndex(i).getFloat());
                 }
-                return new VariantFloat(length == 1 ? false : true,
+                return new VariantFloat(length != 1,
                     false,
                     null,
                     null,
@@ -600,11 +554,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                     tmpREAL);
             case "LREAL":
             case "DOUBLE":
-                double[] tmpLREAL = new double[length];
+                List<Double> tmpLREAL = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpLREAL[i] = valueObject.getIndex(i).getDouble();
+                    tmpLREAL.add(valueObject.getIndex(i).getDouble());
                 }
-                return new VariantDouble(length == 1 ? false : true,
+                return new VariantDouble(length != 1,
                     false,
                     null,
                     null,
@@ -615,23 +569,23 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             case "STRING":
             case "WSTRING":
             case "STRING16":
-                PascalString[] tmpString = new PascalString[length];
+                List<PascalString> tmpString = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
                     String s = valueObject.getIndex(i).getString();
-                    tmpString[i] = new PascalString(s);
+                    tmpString.add(new PascalString(s));
                 }
-                return new VariantString(length == 1 ? false : true,
+                return new VariantString(length != 1,
                     false,
                     null,
                     null,
                     length == 1 ? null : length,
                     tmpString);
             case "DATE_AND_TIME":
-                long[] tmpDateTime = new long[length];
+                List<Long> tmpDateTime = new ArrayList<>(length);
                 for (int i = 0; i < length; i++) {
-                    tmpDateTime[i] = valueObject.getIndex(i).getDateTime().toEpochSecond(ZoneOffset.UTC);
+                    tmpDateTime.add(valueObject.getIndex(i).getDateTime().toEpochSecond(ZoneOffset.UTC));
                 }
-                return new VariantDateTime(length == 1 ? false : true,
+                return new VariantDateTime(length != 1,
                     false,
                     null,
                     null,
@@ -656,7 +610,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             SecureChannel.REQUEST_TIMEOUT_LONG,
             NULL_EXTENSION_OBJECT);
 
-        WriteValue[] writeValueArray = new WriteValue[request.getFieldNames().size()];
+        List<ExtensionObjectDefinition> writeValueList = new ArrayList<>(request.getFieldNames().size());
         Iterator<String> iterator = request.getFieldNames().iterator();
         for (int i = 0; i < request.getFieldNames().size(); i++ ) {
             String fieldName = iterator.next();
@@ -664,7 +618,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
 
             NodeId nodeId = generateNodeId(field);
 
-            writeValueArray[i] = new WriteValue(nodeId,
+            writeValueList.set(i, new WriteValue(nodeId,
                 0xD,
                 NULL_STRING,
                 new DataValue(
@@ -679,17 +633,17 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                     null,
                     null,
                     null,
-                    null));
+                    null)));
         }
 
         WriteRequest opcuaWriteRequest = new WriteRequest(
             requestHeader,
-            writeValueArray.length,
-            writeValueArray);
+            writeValueList.size(),
+            writeValueList);
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(opcuaWriteRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(opcuaWriteRequest.getIdentifier())),
             null,
             null);
 
@@ -717,10 +671,8 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             };
 
             /* Functional Consumer example using inner class */
-            Consumer<TimeoutException> timeout = t -> {
-                // Pass the response back to the application.
-                future.completeExceptionally(t);
-            };
+            // Pass the response back to the application.
+            Consumer<TimeoutException> timeout = future::completeExceptionally;
 
             /* Functional Consumer example using inner class */
             BiConsumer<OpcuaAPU, Throwable> error = (message, t) -> {
@@ -739,11 +691,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
 
     private PlcWriteResponse writeResponse(DefaultPlcWriteRequest request, WriteResponse writeResponse) {
         Map<String, PlcResponseCode> responseMap = new HashMap<>();
-        StatusCode[] results = writeResponse.getResults();
+        List<StatusCode> results = writeResponse.getResults();
         Iterator<String> responseIterator = request.getFieldNames().iterator();
         for (int i = 0; i < request.getFieldNames().size(); i++ ) {
             String fieldName = responseIterator.next();
-            OpcuaStatusCode statusCode = OpcuaStatusCode.enumForValue(results[i].getStatusCode());
+            OpcuaStatusCode statusCode = OpcuaStatusCode.enumForValue(results.get(i).getStatusCode());
             switch (statusCode) {
                 case Good:
                     responseMap.put(fieldName, PlcResponseCode.OK);
@@ -761,11 +713,11 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
 
     @Override
     public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest subscriptionRequest) {
-        CompletableFuture<PlcSubscriptionResponse> future = CompletableFuture.supplyAsync(() -> {
+        return CompletableFuture.supplyAsync(() -> {
             Map<String, ResponseItem<PlcSubscriptionHandle>> values = new HashMap<>();
-            long subscriptionId = -1L;
+            long subscriptionId;
             ArrayList<String> fields = new ArrayList<>( subscriptionRequest.getFieldNames() );
-            long cycleTime = ((DefaultPlcSubscriptionField) subscriptionRequest.getField(fields.get(0))).getDuration().orElse(Duration.ofMillis(1000)).toMillis();
+            long cycleTime = (subscriptionRequest.getField(fields.get(0))).getDuration().orElse(Duration.ofMillis(1000)).toMillis();
 
             try {
                 CompletableFuture<CreateSubscriptionResponse> subscription = onSubscribeCreateSubscription(cycleTime);
@@ -786,8 +738,6 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             }
             return new DefaultPlcSubscriptionResponse(subscriptionRequest, values);
         });
-
-        return future;
     }
 
     private CompletableFuture<CreateSubscriptionResponse> onSubscribeCreateSubscription(long cycleTime) {
@@ -814,7 +764,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(createSubscriptionRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(createSubscriptionRequest.getIdentifier())),
             null,
             null);
 
@@ -888,7 +838,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             final PlcConsumerRegistration consumerRegistration = subscriptionHandle.register(consumer);
             registrations.add(consumerRegistration);
         }
-        return new DefaultPlcConsumerRegistration((PlcSubscriber) this, consumer, handles.toArray(new PlcSubscriptionHandle[0]));
+        return new DefaultPlcConsumerRegistration(this, consumer, handles.toArray(new PlcSubscriptionHandle[0]));
     }
 
     @Override
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubscriptionHandle.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubscriptionHandle.java
index df02165..6c27ff7 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubscriptionHandle.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaSubscriptionHandle.java
@@ -18,7 +18,6 @@
  */
 package org.apache.plc4x.java.opcua.protocol;
 
-import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent;
 import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest;
 import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
@@ -63,7 +62,7 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
 
     private final AtomicLong clientHandles = new AtomicLong(1L);
 
-    private ConversationContext context;
+    private ConversationContext<OpcuaAPU> context;
 
     public OpcuaSubscriptionHandle(ConversationContext<OpcuaAPU> context, OpcuaProtocolLogic plcSubscriber, SecureChannel channel, PlcSubscriptionRequest subscriptionRequest, Long subscriptionId, long cycleTime) {
         super(plcSubscriber);
@@ -87,7 +86,7 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
     }
 
     private CompletableFuture<CreateMonitoredItemsResponse> onSubscribeCreateMonitoredItemsRequest()  {
-        MonitoredItemCreateRequest[] requestList = new MonitoredItemCreateRequest[this.fieldNames.size()];
+        List<ExtensionObjectDefinition> requestList = new ArrayList<>(this.fieldNames.size());
         for (int i = 0; i <  this.fieldNames.size(); i++) {
             final DefaultPlcSubscriptionField fieldDefaultPlcSubscription = (DefaultPlcSubscriptionField) subscriptionRequest.getField(fieldNames.get(i));
 
@@ -127,7 +126,7 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
             MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(
                 readValueId, monitoringMode, parameters);
 
-            requestList[i] = request;
+            requestList.set(i, request);
         }
 
         CompletableFuture<CreateMonitoredItemsResponse> future = new CompletableFuture<>();
@@ -144,13 +143,13 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
             requestHeader,
             subscriptionId,
             TimestampsToReturn.timestampsToReturnNeither,
-            requestList.length,
+            requestList.size(),
             requestList
         );
 
         ExpandedNodeId expandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(createMonitoredItemsRequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(createMonitoredItemsRequest.getIdentifier())),
             null,
             null);
 
@@ -180,7 +179,7 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
                     e.printStackTrace();
                     plcSubscriber.onDisconnect(context);
                 }
-                for (MonitoredItemCreateResult result : Arrays.stream(responseMessage.getResults()).toArray(MonitoredItemCreateResult[]::new)) {
+                for (MonitoredItemCreateResult result : responseMessage.getResults().toArray(new MonitoredItemCreateResult[0])) {
                     if (OpcuaStatusCode.enumForValue(result.getStatusCode().getStatusCode()) != OpcuaStatusCode.Good) {
                         LOGGER.error("Invalid Field {}, subscription created without this field", fieldNames.get((int) result.getMonitoredItemId()));
                     } else {
@@ -230,8 +229,8 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
         LOGGER.trace("Starting Subscription");
         CompletableFuture.supplyAsync(() -> {
             try {
-                LinkedList<SubscriptionAcknowledgement> outstandingAcknowledgements = new LinkedList<>();
-                LinkedList<Long> outstandingRequests = new LinkedList<>();
+                List<ExtensionObjectDefinition> outstandingAcknowledgements = new LinkedList<>();
+                List<Long> outstandingRequests = new LinkedList<>();
                 while (!this.destroy.get()) {
                     long requestHandle = channel.getRequestHandle();
 
@@ -245,13 +244,10 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
                             this.revisedCycleTime * 10,
                             OpcuaProtocolLogic.NULL_EXTENSION_OBJECT);
 
-                        //Make a copy of the outstanding requests so it isn't modified while we are putting the ack list together.
-                        LinkedList<Long> outstandingAcknowledgementsSnapshot = (LinkedList<Long>) outstandingAcknowledgements.clone();
-                        SubscriptionAcknowledgement[] acks = new SubscriptionAcknowledgement[outstandingAcknowledgementsSnapshot.size()];
-                        ;
-                        outstandingAcknowledgementsSnapshot.toArray(acks);
-                        int ackLength = outstandingAcknowledgementsSnapshot.size() == 0 ? -1 : outstandingAcknowledgementsSnapshot.size();
-                        outstandingAcknowledgements.removeAll(outstandingAcknowledgementsSnapshot);
+                        //Make a copy of the outstanding requests, so it isn't modified while we are putting the ack list together.
+                        List<ExtensionObjectDefinition> acks = Collections.unmodifiableList(outstandingAcknowledgements);
+                        int ackLength = acks.size() == 0 ? -1 : acks.size();
+                        outstandingAcknowledgements.removeAll(acks);
 
                         PublishRequest publishRequest = new PublishRequest(
                             requestHeader,
@@ -261,7 +257,7 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
 
                         ExpandedNodeId extExpandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
                             false,            //Server Index Specified
-                            new NodeIdFourByte((short) 0, Integer.valueOf(publishRequest.getIdentifier())),
+                            new NodeIdFourByte((short) 0, Integer.parseInt(publishRequest.getIdentifier())),
                             null,
                             null);
 
@@ -304,8 +300,8 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
                                         ExtensionObjectDefinition notification = notificationMessage.getBody();
                                         if (notification instanceof DataChangeNotification) {
                                             LOGGER.trace("Found a Data Change notification");
-                                            ExtensionObjectDefinition[] items = ((DataChangeNotification) notification).getMonitoredItems();
-                                            onSubscriptionValue(Arrays.stream(items).toArray(MonitoredItemNotification[]::new));
+                                            List<ExtensionObjectDefinition> items = ((DataChangeNotification) notification).getMonitoredItems();
+                                            onSubscriptionValue(items.toArray(new MonitoredItemNotification[0]));
                                         } else {
                                             LOGGER.warn("Unsupported Notification type");
                                         }
@@ -345,7 +341,6 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
             }
             return null;
         });
-        return;
     }
 
 
@@ -366,8 +361,8 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
             this.revisedCycleTime * 10,
             OpcuaProtocolLogic.NULL_EXTENSION_OBJECT);
 
-        long[] subscriptions = new long[1];
-        subscriptions[0] = subscriptionId;
+        List<Long> subscriptions = new ArrayList<>(1);
+        subscriptions.add(subscriptionId);
         DeleteSubscriptionsRequest deleteSubscriptionrequest = new DeleteSubscriptionsRequest(requestHeader,
             1,
             subscriptions
@@ -375,7 +370,7 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
 
         ExpandedNodeId extExpandedNodeId = new ExpandedNodeId(false,           //Namespace Uri Specified
             false,            //Server Index Specified
-            new NodeIdFourByte((short) 0, Integer.valueOf(deleteSubscriptionrequest.getIdentifier())),
+            new NodeIdFourByte((short) 0, Integer.parseInt(deleteSubscriptionrequest.getIdentifier())),
             null,
             null);
 
@@ -434,19 +429,15 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
      */
     private void onSubscriptionValue(MonitoredItemNotification[] values) {
         LinkedHashSet<String> fieldList = new LinkedHashSet<>();
-        DataValue[] dataValues = new DataValue[values.length];
-        int i = 0;
+        List<DataValue> dataValues = new ArrayList<>(values.length);
         for (MonitoredItemNotification value : values) {
             fieldList.add(fieldNames.get((int) value.getClientHandle() - 1));
-            dataValues[i] = value.getValue();
-            i++;
+            dataValues.add(value.getValue());
         }
         Map<String, ResponseItem<PlcValue>> fields = plcSubscriber.readResponse(fieldList, dataValues);
         final PlcSubscriptionEvent event = new DefaultPlcSubscriptionEvent(Instant.now(), fields);
 
-        consumers.forEach(plcSubscriptionEventConsumer -> {
-            plcSubscriptionEventConsumer.accept(event);
-        });
+        consumers.forEach(plcSubscriptionEventConsumer -> plcSubscriptionEventConsumer.accept(event));
     }
 
     /**
@@ -469,9 +460,9 @@ public class OpcuaSubscriptionHandle extends DefaultPlcSubscriptionHandle {
     private NodeId generateNodeId(OpcuaField field) {
         NodeId nodeId = null;
         if (field.getIdentifierType() == OpcuaIdentifierType.BINARY_IDENTIFIER) {
-            nodeId = new NodeId(new NodeIdTwoByte(Short.valueOf(field.getIdentifier())));
+            nodeId = new NodeId(new NodeIdTwoByte(Short.parseShort(field.getIdentifier())));
         } else if (field.getIdentifierType() == OpcuaIdentifierType.NUMBER_IDENTIFIER) {
-            nodeId = new NodeId(new NodeIdNumeric((short) field.getNamespace(), Long.valueOf(field.getIdentifier())));
+            nodeId = new NodeId(new NodeIdNumeric((short) field.getNamespace(), Long.parseLong(field.getIdentifier())));
         } else if (field.getIdentifierType() == OpcuaIdentifierType.GUID_IDENTIFIER) {
             UUID guid = UUID.fromString(field.getIdentifier());
             byte[] guidBytes = new byte[16];
diff --git a/protocols/ab-eth/src/main/resources/protocols/abeth/ab-eth.mspec b/protocols/ab-eth/src/main/resources/protocols/abeth/ab-eth.mspec
index 7322ec5..525e54c 100644
--- a/protocols/ab-eth/src/main/resources/protocols/abeth/ab-eth.mspec
+++ b/protocols/ab-eth/src/main/resources/protocols/abeth/ab-eth.mspec
@@ -62,7 +62,7 @@
     [simple        uint 8  'status']
     [simple        uint 16 'transactionCounter']
     [typeSwitch 'commandCode'
-        ['0x4F' DF1CommandResponseMessageProtectedTypedLogicalRead (uint 16 'payloadLength', uint 8 'status')
+        ['0x4F' DF1CommandResponseMessageProtectedTypedLogicalRead (uint 8 'status')
             [array    uint 8 'data' length 'payloadLength - 8']
         ]
     ]
diff --git a/protocols/canopen/src/main/resources/protocols/can/canopen.mspec b/protocols/canopen/src/main/resources/protocols/can/canopen.mspec
index d4c55e6..8e90037 100644
--- a/protocols/canopen/src/main/resources/protocols/can/canopen.mspec
+++ b/protocols/canopen/src/main/resources/protocols/can/canopen.mspec
@@ -177,7 +177,7 @@
 
 [type 'SDOInitiateUploadResponsePayload' (bit 'expedited', bit 'indicated', uint 2 'size')
     [typeSwitch 'expedited', 'indicated'
-        ['true', 'true' SDOInitiateExpeditedUploadResponse (uint 2 'size')
+        ['true', 'true' SDOInitiateExpeditedUploadResponse
             [array byte 'data' count '4 - size']
             [padding uint 8 'alignment' '0x00' '4 - COUNT(data)']
         ]
diff --git a/protocols/opcua/src/main/xslt/opc-common.xsl b/protocols/opcua/src/main/xslt/opc-common.xsl
index beaaf69..30d74bc 100644
--- a/protocols/opcua/src/main/xslt/opc-common.xsl
+++ b/protocols/opcua/src/main/xslt/opc-common.xsl
@@ -224,9 +224,9 @@
                     <xsl:when test="$dataType = 'ExtensionObjectDefinition'">
                         <xsl:variable name="browseName" select="substring-after(@TypeName,':')"/>
                         <xsl:variable name="id" select="number(substring-after($file/node:UANodeSet/node:UADataType[@BrowseName=$browseName]/@NodeId, '=')) + 2"/><xsl:text>
-            </xsl:text>[array <xsl:value-of select="$dataType"/>  '<xsl:value-of select="$lowerCaseName"/>' count '<xsl:value-of select="$lowerCaseLengthField"/>' ['<xsl:value-of select='$id'/>']]
+            </xsl:text>[array <xsl:value-of select="$dataType"/>('"<xsl:value-of select='$id'/>"') '<xsl:value-of select="$lowerCaseName"/>' count '<xsl:value-of select="$lowerCaseLengthField"/>']
             </xsl:when>
-                    <xsl:when test="$dataType = 'ExtensionObject'">[array <xsl:value-of select="$dataType"/>  '<xsl:value-of select="$lowerCaseName"/>' count '<xsl:value-of select="$lowerCaseLengthField"/>' ['true']]
+                    <xsl:when test="$dataType = 'ExtensionObject'">[array <xsl:value-of select="$dataType"/>('true') '<xsl:value-of select="$lowerCaseName"/>' count '<xsl:value-of select="$lowerCaseLengthField"/>']
                     </xsl:when>
                     <xsl:otherwise>[array <xsl:value-of select="$dataType"/>  '<xsl:value-of select="$lowerCaseName"/>' count '<xsl:value-of select="$lowerCaseLengthField"/>']
             </xsl:otherwise>
@@ -247,9 +247,9 @@
             <xsl:when test="$dataType = 'ExtensionObjectDefinition'">
                 <xsl:variable name="browseName" select="substring-after(@TypeName,':')"/>
                 <xsl:variable name="id" select="number(substring-after($file/node:UANodeSet/node:UADataType[@BrowseName=$browseName]/@NodeId, '=')) + 2"/><xsl:text>
-            </xsl:text>[<xsl:value-of select="$mspecType"/><xsl:text> </xsl:text><xsl:value-of select="$dataType"/> '<xsl:value-of select="$lowerCaseName"/>' ['<xsl:value-of select='$id'/>']]
+            </xsl:text>[<xsl:value-of select="$mspecType"/><xsl:text> </xsl:text><xsl:value-of select="$dataType"/>('"<xsl:value-of select='$id'/>"') '<xsl:value-of select="$lowerCaseName"/>']
             </xsl:when>
-            <xsl:when test="$dataType = 'ExtensionObject'">[<xsl:value-of select="$mspecType"/><xsl:text> </xsl:text><xsl:value-of select="$dataType"/> '<xsl:value-of select="$lowerCaseName"/>' ['true']]
+            <xsl:when test="$dataType = 'ExtensionObject'">[<xsl:value-of select="$mspecType"/><xsl:text> </xsl:text><xsl:value-of select="$dataType"/>('true') '<xsl:value-of select="$lowerCaseName"/>']
             </xsl:when>
             <xsl:otherwise>[<xsl:value-of select="$mspecType"/><xsl:text> </xsl:text><xsl:value-of select="$dataType"/> '<xsl:value-of select="$lowerCaseName"/>']
             </xsl:otherwise>
diff --git a/protocols/opcua/src/main/xslt/opc-manual.xsl b/protocols/opcua/src/main/xslt/opc-manual.xsl
index a01781c..696580e 100644
--- a/protocols/opcua/src/main/xslt/opc-manual.xsl
+++ b/protocols/opcua/src/main/xslt/opc-manual.xsl
@@ -55,8 +55,8 @@
     <xsl:template match="/">
 // Remark: The different fields are encoded in Little-endian.
 
-[type 'OpcuaAPU' (bit 'response') byteOrder='"LITTLE_ENDIAN"'
-    [simple         MessagePDU   'message' ['response']]
+[type 'OpcuaAPU' byteOrder='"LITTLE_ENDIAN"' (bit 'response')
+    [simple MessagePDU('response') 'message']
 ]
 
 [discriminatedType 'MessagePDU' (bit 'response')
@@ -90,7 +90,7 @@
             [simple          PascalByteString   'receiverCertificateThumbprint']
             [simple          int 32             'sequenceNumber']
             [simple          int 32             'requestId']
-            [array           int 8              'message' count 'messageSize - (endpoint.stringLength == -1 ? 0 : endpoint.stringLength ) - (senderCertificate.stringLength == -1 ? 0 : senderCertificate.stringLength) - (receiverCertificateThumbprint.stringLength == -1 ? 0 : receiverCertificateThumbprint.stringLength) - 32']
+            [array           byte               'message' count 'messageSize - (endpoint.stringLength == -1 ? 0 : endpoint.stringLength ) - (senderCertificate.stringLength == -1 ? 0 : senderCertificate.stringLength) - (receiverCertificateThumbprint.stringLength == -1 ? 0 : receiverCertificateThumbprint.stringLength) - 32']
        ]
        ['OPN','true'     OpcuaOpenResponse
            [simple          string 8           'chunk']
@@ -101,7 +101,7 @@
            [simple          PascalByteString   'receiverCertificateThumbprint']
            [simple          int 32             'sequenceNumber']
            [simple          int 32             'requestId']
-           [array           int 8              'message' count 'messageSize - (securityPolicyUri.stringLength == -1 ? 0 : securityPolicyUri.stringLength) - (senderCertificate.stringLength == -1 ? 0 : senderCertificate.stringLength) - (receiverCertificateThumbprint.stringLength == -1 ? 0 : receiverCertificateThumbprint.stringLength) - 32']
+           [array           byte               'message' count 'messageSize - (securityPolicyUri.stringLength == -1 ? 0 : securityPolicyUri.stringLength) - (senderCertificate.stringLength == -1 ? 0 : senderCertificate.stringLength) - (receiverCertificateThumbprint.stringLength == -1 ? 0 : receiverCertificateThumbprint.stringLength) - 32']
        ]
        ['CLO','false'     OpcuaCloseRequest
            [simple          string 8           'chunk']
@@ -110,7 +110,7 @@
            [simple          int 32             'secureTokenId']
            [simple          int 32             'sequenceNumber']
            [simple          int 32             'requestId']
-           [simple          ExtensionObject       'message' ['false']]
+           [simple          ExtensionObject('false')       'message']
        ]
        ['MSG','false'     OpcuaMessageRequest
            [simple          string 8           'chunk']
@@ -119,7 +119,7 @@
            [simple          int 32             'secureTokenId']
            [simple          int 32             'sequenceNumber']
            [simple          int 32             'requestId']
-           [array           int 8              'message' count 'messageSize - 24']
+           [array           byte               'message' count 'messageSize - 24']
        ]
        ['MSG','true'     OpcuaMessageResponse
            [simple          string 8           'chunk']
@@ -128,7 +128,7 @@
            [simple          int 32             'secureTokenId']
            [simple          int 32             'sequenceNumber']
            [simple          int 32             'requestId']
-           [array           int 8              'message' count 'messageSize - 24']
+           [array           byte               'message' count 'messageSize - 24']
        ]
     ]
 ]
@@ -142,8 +142,8 @@
     [simple uint 32 'data1']
     [simple uint 16 'data2']
     [simple uint 16 'data3']
-    [array int 8 'data4' count '2']
-    [array int 8 'data5' count '6']
+    [array  byte    'data4' count '2']
+    [array  byte    'data5' count '6']
 ]
 
 [type 'ExpandedNodeId'
@@ -190,14 +190,14 @@
         ['811' DataChangeNotification
             [implicit int 32 'notificationLength' 'lengthInBytes']
             [simple int 32 'noOfMonitoredItems']
-            [array ExtensionObjectDefinition('808')  'monitoredItems' count 'noOfMonitoredItems']
+            [array ExtensionObjectDefinition('"808"')  'monitoredItems' count 'noOfMonitoredItems']
             [simple int 32 'noOfDiagnosticInfos']
             [array DiagnosticInfo  'diagnosticInfos' count 'noOfDiagnosticInfos']
         ]
         ['916' EventNotificationList
             [implicit int 32 'notificationLength' 'lengthInBytes']
             [simple int 32 'noOfEvents']
-            [array ExtensionObjectDefinition('919')  'events' count 'noOfEvents']
+            [array ExtensionObjectDefinition('"919"')  'events' count 'noOfEvents']
         ]
         ['820' StatusChangeNotification
             [implicit int 32 'notificationLength' 'lengthInBytes']
@@ -240,11 +240,11 @@
     [typeSwitch 'VariantType','arrayLengthSpecified'
         ['1' VariantBoolean (bit 'arrayLengthSpecified')
             [optional int 32 'arrayLength' 'arrayLengthSpecified']
-            [array int 8 'value' count 'arrayLength == null ? 1 : arrayLength']
+            [array byte 'value' count 'arrayLength == null ? 1 : arrayLength']
         ]
         ['2' VariantSByte (bit 'arrayLengthSpecified')
             [optional int 32 'arrayLength' 'arrayLengthSpecified']
-            [array int 8 'value' count 'arrayLength == null ? 1 : arrayLength']
+            [array byte 'value' count 'arrayLength == null ? 1 : arrayLength']
         ]
         ['3' VariantByte (bit 'arrayLengthSpecified')
             [optional int 32 'arrayLength' 'arrayLengthSpecified']
@@ -324,7 +324,7 @@
         ]
         ['22' VariantExtensionObject (bit 'arrayLengthSpecified')
             [optional int 32 'arrayLength' 'arrayLengthSpecified']
-            [array ExtensionObject 'value' count 'arrayLength == null ? 1 : arrayLength' ['true']]
+            [array ExtensionObject('true') 'value' count 'arrayLength == null ? 1 : arrayLength']
         ]
         ['23' VariantDataValue (bit 'arrayLengthSpecified')
             [optional int 32 'arrayLength' 'arrayLengthSpecified']
@@ -368,7 +368,7 @@
         ]
         ['nodeIdTypeGuid' NodeIdGuid
             [simple uint 16 'namespaceIndex']
-            [array int 8 'id' count '16']
+            [array byte 'id' count '16']
             [virtual vstring '-1' 'identifier' 'id']
         ]
         ['nodeIdTypeByteString' NodeIdByteString
@@ -393,7 +393,7 @@
 
 [type 'PascalByteString'
     [simple int 32 'stringLength']
-    [array int 8 'stringValue' count 'stringLength == -1 ? 0 : stringLength' ]
+    [array byte 'stringValue' count 'stringLength == -1 ? 0 : stringLength' ]
 ]
 
 [type 'Structure'
diff --git a/protocols/s7/src/main/resources/protocols/s7/s7.mspec b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
index b947146..54fa9f6 100644
--- a/protocols/s7/src/main/resources/protocols/s7/s7.mspec
+++ b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
@@ -84,7 +84,7 @@
         ['0xC3' COTPParameterChecksum
             [simple uint 8 'crc']
         ]
-        ['0xE0' COTPParameterDisconnectAdditionalInformation(uint 8 'rest')
+        ['0xE0' COTPParameterDisconnectAdditionalInformation
             [array byte 'data' count 'rest']
         ]
     ]