You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by hu...@apache.org on 2021/01/04 11:40:26 UTC

[plc4x] branch feature/native_opua_client updated: Cleaned up the Connection logic a bit, next step to add read logic values :)

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

hutcheb pushed a commit to branch feature/native_opua_client
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/feature/native_opua_client by this push:
     new 9971783  Cleaned up the Connection logic a bit, next step to add read logic values :)
9971783 is described below

commit 9971783aa158f5f5724792de3a6313adc047757c
Author: hutcheb <be...@gmail.com>
AuthorDate: Mon Jan 4 06:39:27 2021 -0500

    Cleaned up the Connection logic a bit, next step to add read logic values :)
---
 .../apache/plc4x/java/opcua/OpcuaPlcDriver.java    | 112 ++++-
 .../java/opcua/config/OpcuaConfiguration.java      |  34 ++
 .../java/opcua/protocol/OpcuaProtocolLogic.java    | 517 +++++++++++----------
 .../src/main/resources/protocols/opcua/opcua.mspec |  11 +-
 protocols/opcua/src/main/xslt/opc-types.xsl        |   6 +-
 5 files changed, 429 insertions(+), 251 deletions(-)

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 b2c7d1f..efb16b3 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
@@ -29,24 +29,27 @@ import org.apache.plc4x.java.opcua.config.*;
 import org.apache.plc4x.java.opcua.readwrite.*;
 import org.apache.plc4x.java.opcua.readwrite.io.*;
 import org.apache.plc4x.java.opcua.readwrite.types.*;
-import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
+import org.apache.plc4x.java.spi.configuration.ConfigurationFactory;
+import org.apache.plc4x.java.spi.connection.*;
+import org.apache.plc4x.java.spi.transport.Transport;
 import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
 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 org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer;
-import org.apache.plc4x.java.spi.connection.SingleProtocolStackConfigurer;
 import org.apache.plc4x.java.spi.optimizer.BaseOptimizer;
 import org.apache.plc4x.java.spi.optimizer.SingleFieldOptimizer;
 import io.netty.buffer.ByteBuf;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.ServiceLoader;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import java.util.function.ToIntFunction;
 
+import static org.apache.plc4x.java.spi.configuration.ConfigurationFactory.configure;
+
 /**
  * Implementation of the OPC UA protocol, based on:
  * - Eclipse Milo (https://github.com/eclipse/milo)
@@ -56,9 +59,21 @@ import java.util.function.ToIntFunction;
 public class OpcuaPlcDriver extends GeneratedDriverBase<OpcuaAPU> {
 
 
-    public static final Pattern INET_ADDRESS_PATTERN = Pattern.compile("(:(?<transport>tcp))?://(?<host>[\\w.-]+)(:(?<port>\\d*))?");
     public static final Pattern OPCUA_URI_PARAM_PATTERN = Pattern.compile("(?<param>[(\\?|\\&)([^=]+)\\=([^&]+)]+)?"); //later used for regex filtering of the params
-    public static final Pattern OPCUA_URI_PATTERN = Pattern.compile("^opcua" + INET_ADDRESS_PATTERN + "(?<params>[\\w/=?&]+)?");
+
+
+    public static final Pattern INET_ADDRESS_PATTERN = Pattern.compile("(:(?<transportCode>tcp))?://" +
+                                                                        "(?<transportHost>[\\w.-]+)(:" +
+                                                                        "(?<transportPort>\\d*))?");
+
+
+    public static final Pattern URI_PATTERN = Pattern.compile("^(?<protocolCode>opcua)" +
+                                                                    INET_ADDRESS_PATTERN +
+                                                                    "(?<transportEndpoint>[\\w/=]+)" +
+                                                                    "(?<paramString>[(\\?|\\&)\\w=]+\\=[\\w&]+)*"
+                                                                );
+
+
     private static final int requestTimeout = 10000;
     private OpcuaConnectionFactory opcuaConnectionFactory = new OpcuaConnectionFactory();
 
@@ -128,6 +143,93 @@ public class OpcuaPlcDriver extends GeneratedDriverBase<OpcuaAPU> {
             .build();
     }
 
+
+
+    @Override
+    public PlcConnection getConnection(String connectionString) throws PlcConnectionException {
+        // Split up the connection string into it's individual segments.
+        Matcher matcher = URI_PATTERN.matcher(connectionString);
+        if (!matcher.matches()) {
+            throw new PlcConnectionException(
+                "Connection string doesn't match the format '{protocol-code}:({transport-code})?//{transport-host}(:{transport-port})(/{transport-endpoint})(?{parameter-string)?'");
+        }
+        final String protocolCode = matcher.group("protocolCode");
+        final String transportCode = (matcher.group("transportCode") != null) ?
+            matcher.group("transportCode") : getDefaultTransport();
+        final String transportHost = matcher.group("transportHost");
+        final String transportPort = matcher.group("transportPort");
+        final String transportEndpoint = matcher.group("transportEndpoint");
+        final String paramString = matcher.group("paramString");
+
+        System.out.println(protocolCode + " - " + transportCode + " - " + transportHost + " - " +  transportPort + " - " +  transportEndpoint + " - " +  paramString);
+
+        // Check if the protocol code matches this driver.
+        if(!protocolCode.equals(getProtocolCode())) {
+            // Actually this shouldn't happen as the DriverManager should have not used this driver in the first place.
+            throw new PlcConnectionException(
+                "This driver is not suited to handle this connection string");
+        }
+
+        // Create the configuration object.
+        OpcuaConfiguration configuration = new OpcuaConfiguration(  transportCode,
+                                                                    transportHost,
+                                                                    transportPort,
+                                                                    transportEndpoint,
+                                                                    paramString);
+
+        if(configuration == null) {
+            throw new PlcConnectionException("Unsupported configuration");
+        }
+
+        // Try to find a transport in order to create a communication channel.
+        Transport transport = null;
+        ServiceLoader<Transport> transportLoader = ServiceLoader.load(
+            Transport.class, Thread.currentThread().getContextClassLoader());
+        for (Transport curTransport : transportLoader) {
+            if(curTransport.getTransportCode().equals(transportCode)) {
+                transport = curTransport;
+                break;
+            }
+        }
+        if(transport == null) {
+            throw new PlcConnectionException("Unsupported transport " + transportCode);
+        }
+
+        // Inject the configuration into the transport.
+        configure(configuration, transport);
+
+        // Create an instance of the communication channel which the driver should use.
+        ChannelFactory channelFactory = transport.createChannelFactory(transportHost + ":" + transportPort);
+        if(channelFactory == null) {
+            throw new PlcConnectionException("Unable to get channel factory from url " + transportHost + ":" + transportPort);
+        }
+        configure(configuration, channelFactory);
+
+        // Give drivers the option to customize the channel.
+        initializePipeline(channelFactory);
+
+        // Make the "await setup complete" overridable via system property.
+        boolean awaitSetupComplete = awaitSetupComplete();
+        if(System.getProperty(PROPERTY_PLC4X_FORCE_AWAIT_SETUP_COMPLETE) != null) {
+            awaitSetupComplete = Boolean.parseBoolean(System.getProperty(PROPERTY_PLC4X_FORCE_AWAIT_SETUP_COMPLETE));
+        }
+
+        return new DefaultNettyPlcConnection(
+            canRead(), canWrite(), canSubscribe(),
+            getFieldHandler(),
+            getValueHandler(),
+            configuration,
+            channelFactory,
+            awaitSetupComplete,
+            getStackConfigurer(),
+            getOptimizer());
+    }
+
+    @Override
+    public PlcConnection getConnection(String url, PlcAuthentication authentication) throws PlcConnectionException {
+        throw new PlcConnectionException("Authentication not supported.");
+    }
+
     /** Estimate the Length of a Packet */
     public static class ByteLengthEstimator implements ToIntFunction<ByteBuf> {
         @Override
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/config/OpcuaConfiguration.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/config/OpcuaConfiguration.java
index 07f1b47..99f43a3 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/config/OpcuaConfiguration.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/config/OpcuaConfiguration.java
@@ -25,6 +25,40 @@ import org.apache.plc4x.java.spi.configuration.annotations.defaults.IntDefaultVa
 import org.apache.plc4x.java.transport.tcp.TcpTransportConfiguration;
 
 public class OpcuaConfiguration implements Configuration, TcpTransportConfiguration {
+
+    private final String code;
+    private final String host;
+    private final String port;
+    private final String endpoint;
+    private final String params;
+
+    public OpcuaConfiguration(String transportCode, String transportHost, String transportPort, String transportEndpoint, String paramString) {
+        this.code = transportCode;
+        this.host = transportHost;
+        this.port = transportPort;
+        this.endpoint = "opc." + transportCode + "://" + transportHost + ":" + transportPort + "" + transportEndpoint;
+        this.params = paramString;
+    }
+
+    public String getTransportCode() {
+        return code;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public String getPort() {
+        return port;
+    }
+
+    public String getEndpoint() {
+        return endpoint;
+    }
+
+    public String getParams() {
+        return params;
+    }
         
     @Override
     public int getDefaultPort() {
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 af83533..1e5e233 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
@@ -21,6 +21,10 @@ package org.apache.plc4x.java.opcua.protocol;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.authentication.PlcAuthentication;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
@@ -30,6 +34,11 @@ import org.apache.plc4x.java.api.messages.PlcWriteRequest;
 import org.apache.plc4x.java.api.messages.PlcWriteResponse;
 import org.apache.plc4x.java.api.model.PlcField;
 import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.spi.configuration.Configuration;
+import org.apache.plc4x.java.spi.configuration.ConfigurationFactory;
+import org.apache.plc4x.java.spi.connection.ChannelFactory;
+import org.apache.plc4x.java.spi.connection.DefaultNettyPlcConnection;
+import org.apache.plc4x.java.spi.transport.Transport;
 import org.apache.plc4x.java.spi.values.PlcNull;
 import org.apache.plc4x.java.api.value.PlcValue;
 import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
@@ -55,15 +64,15 @@ import org.slf4j.LoggerFactory;
 
 import java.io.UnsupportedEncodingException;
 import java.time.Duration;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Matcher;
 import java.util.stream.IntStream;
 import java.nio.charset.StandardCharsets;
 
+import static org.apache.plc4x.java.spi.configuration.ConfigurationFactory.configure;
+
 /**
  * The S7 Protocol states that there can not be more then {min(maxAmqCaller, maxAmqCallee} "ongoing" requests.
  * So we need to limit those.
@@ -73,12 +82,41 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
 
     private static final Logger LOGGER = LoggerFactory.getLogger(OpcuaProtocolLogic.class);
     public static final Duration REQUEST_TIMEOUT = Duration.ofMillis(10000);
-
-    private final AtomicInteger tpduGenerator = new AtomicInteger(10);
+    private static final String CHUNK = "F";
+    private static final int VERSION = 0;
+    private static final int DEFAULT_RECEIVE_BUFFER_SIZE = 65535;
+    private static final int DEFAULT_SEND_BUFFER_SIZE = 65535;
+    private static final int DEFAULT_MAX_MESSAGE_SIZE = 2097152;
+    private static final int DEFAULT_MAX_CHUNK_COUNT = 64;
+    private NodeId authenticationToken = new NodeIdTwoByte(NodeIdType.nodeIdTypeTwoByte, new TwoByteNodeId((short) 0));
+    private static final PascalString NULL_STRING = new PascalString(-1,null);
+    private static ExpandedNodeId NULL_EXPANDED_NODEID = new ExpandedNodeIdTwoByte(false,
+                                                                                    false,
+                                                                                    null,
+                                                                                    null,
+                                                                                    new TwoByteNodeId((short) 0));
+    private static final ExtensionObject NULL_EXTENSION_OBJECT = new ExtensionObject(NULL_EXPANDED_NODEID,
+                                                                                        (short) 0,
+                                                                                null,               //Body Length
+                                                                                    null);               // Body
+    private static final long epochOffset = 116444736000000000L;         //Offset between OPC UA epoch time and linux epoch time.
+    private static final int DEFAULT_CONNECTION_LIFETIME = 36000000;
+    private static final String nameSpaceSecurityPolicyNone = "http://opcfoundation.org/UA/SecurityPolicy#None";
+    private static final String applicationUri = "urn:apache:plc4x:client";
+    private static final String productUri = "urn:apache:plc4x:client";
+    private static final String applicationText = "OPCUA client for the Apache PLC4X:PLC4J project";
+
+    private String sessionName = "UaSession:" + applicationText + ":" + RandomStringUtils.random(20, true, true);
+    private String clientNonce = RandomStringUtils.random(40, true, true);
     private RequestTransactionManager tm;
 
+    private String endpoint;
+    private AtomicInteger transactionIdentifierGenerator = new AtomicInteger(1);
+
     @Override
     public void setConfiguration(OpcuaConfiguration configuration) {
+        this.endpoint = configuration.getEndpoint();
+        this.tm = new RequestTransactionManager(1);
     }
 
     @Override
@@ -87,19 +125,30 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
     }
 
     @Override
+    public void setDriverContext(DriverContext driverContext) {
+        super.setDriverContext(driverContext);
+
+        // Initialize Transaction Manager.
+        // Until the number of concurrent requests is successfully negotiated we set it to a
+        // maximum of only one request being able to be sent at a time. During the login process
+        // No concurrent requests can be sent anyway. It will be updated when receiving the
+        // S7ParameterSetupCommunication response.
+        this.tm = new RequestTransactionManager(1);
+    }
+
+    @Override
     public void onConnect(ConversationContext<OpcuaAPU> context) {
         // Only the TCP transport supports login.
         LOGGER.info("Opcua Driver running in ACTIVE mode.");
 
-        final String endpoint = "opc.tcp://127.0.0.1:12687/plc4x";
-        OpcuaHelloRequest hello = new OpcuaHelloRequest("F",
-                                                        0,
-                                                        65535,
-                                                        65535,
-                                                        2097152,
-                                                        64,
-                                                        endpoint.length(),
-                                                        endpoint);
+        OpcuaHelloRequest hello = new OpcuaHelloRequest(CHUNK,
+            VERSION,
+            DEFAULT_RECEIVE_BUFFER_SIZE,
+            DEFAULT_SEND_BUFFER_SIZE,
+            DEFAULT_MAX_MESSAGE_SIZE,
+            DEFAULT_MAX_CHUNK_COUNT,
+            this.endpoint.length(),
+            this.endpoint);
 
         context.sendRequest(new OpcuaAPU(hello))
             .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
@@ -107,234 +156,228 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             .unwrap(p -> (OpcuaAcknowledgeResponse) p.getMessage())
             .handle(opcuaAcknowledgeResponse -> {
                 LOGGER.debug("Got Hello Response Connection Response");
+                onConnectOpenSecureChannel(context, opcuaAcknowledgeResponse);
+            });
+    }
 
-                NodeIdTwoByte authenticationToken = new NodeIdTwoByte(NodeIdType.nodeIdTypeTwoByte,
-                                                                    new TwoByteNodeId((short) 0));
-
-                ExpandedNodeId expandedNodeId = new ExpandedNodeIdFourByte(false,
-                                                                    false,
-                                                                    new PascalString(-1,null),
-                                                                    1L,
-                                                                    new FourByteNodeId((short) 0, 466));
-
-                ExpandedNodeId extExpandedNodeId = new ExpandedNodeIdTwoByte(false,
-                                                                    false,
-                                                                    null,
-                                                                    null,
-                                                                    new TwoByteNodeId((short) 0));
-
-                ExtensionObject extObject = new ExtensionObject(extExpandedNodeId, (short) 0, null, null);
-
-                RequestHeader requestHeader = new RequestHeader(authenticationToken,
-                                                                (System.currentTimeMillis() * 10000) + 116444736000000000L,
-                                                                0L,
-                                                                0L,
-                                                                new PascalString(-1, null),
-                                                                10000L,
-                                                                extObject);
-
-
-
-                OpenSecureChannelRequest openrequest = new OpenSecureChannelRequest((byte) 1,
-                                                                (byte) 0,
-                                                                requestHeader,
-                                                                0L,
-                                                                SecurityTokenRequestType.securityTokenRequestTypeIssue,
-                                                                MessageSecurityMode.messageSecurityModeNone,
-                                                                new PascalString(-1, null),
-                                                                36000000);
-
-
-                String nameSpace = "http://opcfoundation.org/UA/SecurityPolicy#None";
-                OpcuaOpenRequest openRequest = new OpcuaOpenRequest("F",
-                                                                0,
-                                                                nameSpace.length(),
-                                                                nameSpace,
-                                                                -1,
-                                                                "",
-                                                                -1,
-                                                                "",
-                                                                1,
-                                                                1,
-                                                                openrequest);
-
-                context.sendRequest(new OpcuaAPU(openRequest))
-                    .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
-                    .check(p -> p.getMessage() instanceof OpcuaOpenResponse)
-                    .unwrap(p -> (OpcuaOpenResponse) p.getMessage())
-                    .handle(opcuaOpenResponse -> {
-                        LOGGER.debug("Got Secure Response Connection Response");
-                        OpenSecureChannelResponse openSecureChannelResponse = (OpenSecureChannelResponse) opcuaOpenResponse.getMessage();
-                        Integer tokenId = (int) openSecureChannelResponse.getSecurityToken().getTokenId();
-                        Integer channelId = (int) openSecureChannelResponse.getSecurityToken().getChannelId();
-                        Integer nextSequenceNumber = opcuaOpenResponse.getSequenceNumber() + 1;
-                        Integer nextRequestId = opcuaOpenResponse.getRequestId() + 1;
-
-                        NodeIdTwoByte authenticationToken2 = new NodeIdTwoByte(NodeIdType.nodeIdTypeTwoByte,
-                                                                            new TwoByteNodeId((short) 0));
-
-                        ExpandedNodeId extExpandedNodeId2 = new ExpandedNodeIdTwoByte(false,
-                                                                            false,
-                                                                            NodeIdType.nodeIdTypeTwoByte,
-                                                                            null,
-                                                                            null,
-                                                                            new TwoByteNodeId((short) 0));
-
-                        ExtensionObject extObject2 = new ExtensionObject(extExpandedNodeId2, (short) 0);
-
-                        RequestHeader requestHeader2 = new RequestHeader(authenticationToken2,
-                                                                        (System.currentTimeMillis() * 10000) + 116444736000000000L,
-                                                                        0L,
-                                                                        0L,
-                                                                        new PascalString(-1, null),
-                                                                        10000L,
-                                                                        extObject2);
-
-                        String applicationUri = "urn:eclipse:milo:plc4x:client";
-                        String productUri = "urn:eclipse:milo:plc4x:client";
-                        String text = "eclipse milo opc-ua client of the apache PLC4X:PLC4J project";
-                        LocalizedText applicationName = new LocalizedText((short) 0,
-                                                                          true,
-                                                                          true,
-                                                                          new PascalString(2, "en"),
-                                                                          new PascalString(text.length(), text));
-                        PascalString gatewayServerUri = new PascalString(-1, null);
-                        PascalString discoveryProfileUri = new PascalString(-1, null);
-                        int noOfDiscoveryUrls = -1;
-                        PascalString discoveryUrls = null;
-
-                        ApplicationDescription clientDescription = new ApplicationDescription(new PascalString(applicationUri.length(), applicationUri),
-                                                                                    new PascalString(productUri.length(), productUri),
-                                                                                    applicationName,
-                                                                                    ApplicationType.applicationTypeClient,
-                                                                                    gatewayServerUri,
-                                                                                    discoveryProfileUri,
-                                                                                    noOfDiscoveryUrls,
-                                                                                    discoveryUrls);
-
-                        String endpoint2 = "opc.tcp://127.0.0.1:12687/plc4x";
-                        String sessionName = "UaSession:eclipse milo opc-ua client of the apache PLC4X:PLC4J project:" + System.currentTimeMillis();
-                        String clientNonce = "764287368237654873259869867";
-
-                        CreateSessionRequest createSessionRequest = new CreateSessionRequest((byte) 1,
-                                                                        (byte) 0,
-                                                                        requestHeader2,
-                                                                        clientDescription,
-                                                                        new PascalString(-1, null),
-                                                                        new PascalString(endpoint2.length(), endpoint2),
-                                                                        new PascalString(sessionName.length(), sessionName),
-                                                                        new PascalString(clientNonce.length(), clientNonce),
-                                                                        new PascalString(-1, null),
-                                                                        120000L,
-                                                                        0L);
-
-                        OpcuaMessageRequest messageRequest = new OpcuaMessageRequest("F",
-                                                                        channelId,
-                                                                        tokenId,
-                                                                        nextSequenceNumber,
-                                                                        nextRequestId,
-                                                                        createSessionRequest);
-
-                        context.sendRequest(new OpcuaAPU(messageRequest))
-                            .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
-                            .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
-                            .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
-                            .handle(opcuaMessageResponse -> {
-                                LOGGER.debug("Got Create Session Response Connection Response");
-                                CreateSessionResponse createSessionResponse = (CreateSessionResponse) opcuaMessageResponse.getMessage();
-
-                                NodeIdByteString authenticationToken3 = (NodeIdByteString) createSessionResponse.getAuthenticationToken();
-                                Integer tokenId2 = (int) opcuaMessageResponse.getSecureTokenId();
-                                Integer channelId2 = (int) opcuaMessageResponse.getSecureChannelId();
-                                Integer nextSequenceNumber2 = opcuaMessageResponse.getSequenceNumber() + 1;
-                                Integer nextRequestId2 = opcuaMessageResponse.getRequestId() + 1;
-
-
-                                ExpandedNodeId extExpandedNodeId3 = new ExpandedNodeIdTwoByte(false,
-                                                                                    false,
-                                                                                    NodeIdType.nodeIdTypeTwoByte,
-                                                                                    null,
-                                                                                    null,
-                                                                                    new TwoByteNodeId((short) 0));
-                                System.out.println("(((((((((((((((" + extExpandedNodeId3.getLengthInBytes());
-
-                                ExtensionObject extObject3 = new ExtensionObject(extExpandedNodeId3, (short) 0);
-
-                                System.out.println("(((((((((((((((" + extObject3.getLengthInBytes());
-                                System.out.println("(((((((((((((((" + authenticationToken3.getLengthInBytes());
-                                System.out.println("@@@@@@@@@@@@@@@@@" + authenticationToken3.getId().getIdentifier().getStringLength());
-                                System.out.println("@@@@@@@@@@@@@@@@@" + authenticationToken3.getId().getIdentifier().getStringValue().length());
-
-                                RequestHeader requestHeader3 = new RequestHeader(authenticationToken3,
-                                                                                (System.currentTimeMillis() * 10000) + 116444736000000000L,
-                                                                                1L,
-                                                                                0L,
-                                                                                new PascalString(-1, null),
-                                                                                10000L,
-                                                                                extObject3);
-
-                                System.out.println("(((((((((((((((" + requestHeader3.getLengthInBytes());
-
-                                SignatureData clientSignature = new SignatureData(new PascalString(-1, null), new PascalString(-1, null));
-
-                                System.out.println("(((((((((((((((" + clientSignature.getLengthInBytes());
-
-                                SignedSoftwareCertificate[] signedSoftwareCertificate = new SignedSoftwareCertificate[1];
-
-                                signedSoftwareCertificate[0] = new SignedSoftwareCertificate(new PascalString(-1, null), new PascalString(-1, null));
-
-                                ExpandedNodeId extExpandedNodeId4 = new ExpandedNodeIdFourByte(false,
-                                                                                    false,
-                                                                                    NodeIdType.nodeIdTypeFourByte,
-                                                                                    null,
-                                                                                    null,
-                                                                                    new FourByteNodeId((short) 1,  321));
-
-                                System.out.println("(((((((((((((((" + extExpandedNodeId4.getLengthInBytes());
-
-
-                                ExtensionObject useridentityToken = new ExtensionObject(extExpandedNodeId4, (short) 1);
-
-                                System.out.println("(((((((((((((((" + useridentityToken.getLengthInBytes());
-
-                                String endpoint3 = "opc.tcp://127.0.0.1:12687/plc4x";
-
-                                ActivateSessionRequest activateSessionRequest = new ActivateSessionRequest((byte) 1,
-                                                                                (byte) 0,
-                                                                                requestHeader3,
-                                                                                clientSignature,
-                                                                                0,
-                                                                                null,
-                                                                                0,
-                                                                                null,
-                                                                                useridentityToken,
-                                                                                clientSignature);
-
-                                System.out.println("(((((((((((((((" + activateSessionRequest.getLengthInBytes());
-
-                                OpcuaMessageRequest activateMessageRequest = new OpcuaMessageRequest("F",
-                                                                                channelId2,
-                                                                                tokenId2,
-                                                                                nextSequenceNumber2,
-                                                                                nextRequestId2,
-                                                                                activateSessionRequest);
-
-                                System.out.println("(((((((((((((((" + activateMessageRequest.getLengthInBytes());
-
-                                context.sendRequest(new OpcuaAPU(activateMessageRequest))
-                                    .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
-                                    .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
-                                    .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
-                                    .handle(opcuaActivateResponse -> {
-                                        LOGGER.debug("Got Activate Session Response Connection Response");
+    public void onConnectOpenSecureChannel(ConversationContext<OpcuaAPU> context, OpcuaAcknowledgeResponse opcuaAcknowledgeResponse) {
+
+        int transactionId = transactionIdentifierGenerator.getAndIncrement();
+        if(transactionIdentifierGenerator.get() == 0xFFFF) {
+            transactionIdentifierGenerator.set(1);
+        }
+
+        ExpandedNodeId expandedNodeId = new ExpandedNodeIdFourByte(false,           //Namespace Uri Specified
+                                                                    false,            //Server Index Specified
+                                                                    NULL_STRING,                      //Namespace Uri
+                                                                    1L,                     //Server Index
+                                                                    new FourByteNodeId((short) 0, 466));    //Identifier for OpenSecureChannel
+
+        RequestHeader requestHeader = new RequestHeader(authenticationToken,
+            getCurrentDateTime(),
+            0L,                                         //RequestHandle
+            0L,
+            NULL_STRING,
+            10000L,
+            NULL_EXTENSION_OBJECT);
+
+        OpenSecureChannelRequest openSecureChannelRequest = new OpenSecureChannelRequest((byte) 1,
+            (byte) 0,
+            requestHeader,
+            VERSION,
+            SecurityTokenRequestType.securityTokenRequestTypeIssue,
+            MessageSecurityMode.messageSecurityModeNone,
+            NULL_STRING,
+            DEFAULT_CONNECTION_LIFETIME);
+
+        OpcuaOpenRequest openRequest = new OpcuaOpenRequest(CHUNK,
+            0,
+            new PascalString(nameSpaceSecurityPolicyNone.length(), nameSpaceSecurityPolicyNone),
+            NULL_STRING,
+            NULL_STRING,
+            transactionId,
+            transactionId,
+            openSecureChannelRequest);
+
+        context.sendRequest(new OpcuaAPU(openRequest))
+            .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+            .check(p -> p.getMessage() instanceof OpcuaOpenResponse)
+            .unwrap(p -> (OpcuaOpenResponse) p.getMessage())
+            .handle(opcuaOpenResponse -> {
+                LOGGER.debug("Got Secure Response Connection Response");
+                try {
+                    onConnectCreateSessionRequest(context, opcuaOpenResponse);
+                } catch (PlcConnectionException e) {
+                    LOGGER.error("Error occurred while connecting to OPC UA server");
+                }
+            });
 
-                                    });
+    }
 
+    public void onConnectCreateSessionRequest(ConversationContext<OpcuaAPU> context, OpcuaOpenResponse opcuaOpenResponse) throws PlcConnectionException {
+        OpenSecureChannelResponse openSecureChannelResponse = (OpenSecureChannelResponse) opcuaOpenResponse.getMessage();
+        Integer tokenId = (int) openSecureChannelResponse.getSecurityToken().getTokenId();
+        Integer channelId = (int) openSecureChannelResponse.getSecurityToken().getChannelId();
+
+        int transactionId = transactionIdentifierGenerator.getAndIncrement();
+        if(transactionIdentifierGenerator.get() == 0xFFFF) {
+            transactionIdentifierGenerator.set(1);
+        }
+
+        Integer nextSequenceNumber = opcuaOpenResponse.getSequenceNumber() + 1;
+        Integer 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);
+        }
+
+        RequestHeader requestHeader = new RequestHeader(authenticationToken,
+            getCurrentDateTime(),
+            0L,
+            0L,
+            NULL_STRING,
+            10000L,
+            NULL_EXTENSION_OBJECT);
+
+        LocalizedText applicationName = new LocalizedText((short) 0,
+            true,
+            true,
+            new PascalString("en".length(), "en"),
+            new PascalString(applicationText.length(), applicationText));
+
+        PascalString gatewayServerUri = NULL_STRING;
+        PascalString discoveryProfileUri = NULL_STRING;
+        int noOfDiscoveryUrls = -1;
+        PascalString discoveryUrls = null;
+
+        ApplicationDescription clientDescription = new ApplicationDescription(new PascalString(applicationUri.length(), applicationUri),
+            new PascalString(productUri.length(), productUri),
+            applicationName,
+            ApplicationType.applicationTypeClient,
+            gatewayServerUri,
+            discoveryProfileUri,
+            noOfDiscoveryUrls,
+            discoveryUrls);
+
+        clientNonce = RandomStringUtils.random(40, true, true);
+
+        CreateSessionRequest createSessionRequest = new CreateSessionRequest((byte) 1,
+            (byte) 0,
+            requestHeader,
+            clientDescription,
+            NULL_STRING,
+            new PascalString(endpoint.length(), endpoint),
+            new PascalString(sessionName.length(), sessionName),
+            new PascalString(clientNonce.length(), clientNonce),
+            NULL_STRING,
+            120000L,
+            0L);
+
+        OpcuaMessageRequest messageRequest = new OpcuaMessageRequest(CHUNK,
+            channelId,
+            tokenId,
+            nextSequenceNumber,
+            nextRequestId,
+            createSessionRequest);
+
+        context.sendRequest(new OpcuaAPU(messageRequest))
+            .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+            .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
+            .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
+            .handle(opcuaMessageResponse -> {
+                LOGGER.debug("Got Create Session Response Connection Response");
+                try {
+                    onConnectActivateSessionRequest(context, opcuaMessageResponse);
+                } catch (PlcConnectionException e) {
+                    LOGGER.error("Error occurred while connecting to OPC UA server");
+                }
+            });
+    }
 
-                            });
+    private void onConnectActivateSessionRequest(ConversationContext<OpcuaAPU> context, OpcuaMessageResponse opcuaMessageResponse) throws PlcConnectionException {
+
+        CreateSessionResponse createSessionResponse = (CreateSessionResponse) opcuaMessageResponse.getMessage();
+
+        authenticationToken = (NodeIdByteString) createSessionResponse.getAuthenticationToken();
+        Integer tokenId = (int) opcuaMessageResponse.getSecureTokenId();
+        Integer channelId = (int) opcuaMessageResponse.getSecureChannelId();
+
+        int transactionId = transactionIdentifierGenerator.getAndIncrement();
+        if(transactionIdentifierGenerator.get() == 0xFFFF) {
+            transactionIdentifierGenerator.set(1);
+        }
+
+        Integer nextSequenceNumber = opcuaMessageResponse.getSequenceNumber() + 1;
+        Integer nextRequestId = opcuaMessageResponse.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);
+        }
+
+        RequestHeader requestHeader = new RequestHeader(authenticationToken,
+            getCurrentDateTime(),
+            1L,
+            0L,
+            NULL_STRING,
+            10000L,
+            NULL_EXTENSION_OBJECT);
+
+        SignatureData clientSignature = new SignatureData(NULL_STRING, NULL_STRING);
+
+        SignedSoftwareCertificate[] signedSoftwareCertificate = new SignedSoftwareCertificate[1];
+
+        signedSoftwareCertificate[0] = new SignedSoftwareCertificate(NULL_STRING, NULL_STRING);
+
+        //Manually serialize this object
+        PascalString anonymousIdentityToken = new PascalString("anonymous".length(), "anonymous");
+        WriteBuffer buffer = new WriteBuffer(anonymousIdentityToken.getLengthInBytes(), true);
+        try{
+            PascalStringIO.staticSerialize(buffer, anonymousIdentityToken);
+        } catch (ParseException e) {
+            LOGGER.error("Failed to serialize the user identity token - " + anonymousIdentityToken.getStringValue());
+            throw new PlcConnectionException("Failed to serialize the user identity token - " + anonymousIdentityToken.getStringValue());
+        }
+
+        ExpandedNodeId extExpandedNodeId4 = new ExpandedNodeIdFourByte(false,
+            false,
+            null,
+            null,
+            new FourByteNodeId((short) 0,  321));
+
+        ExtensionObject userIdentityToken = new ExtensionObject(extExpandedNodeId4, (short) 1, buffer.getData().length, buffer.getData());
+
+        ActivateSessionRequest activateSessionRequest = new ActivateSessionRequest((byte) 1,
+            (byte) 0,
+            requestHeader,
+            clientSignature,
+            0,
+            null,
+            0,
+            null,
+            userIdentityToken,
+            clientSignature);
+
+        OpcuaMessageRequest activateMessageRequest = new OpcuaMessageRequest(CHUNK,
+            channelId,
+            tokenId,
+            nextSequenceNumber,
+            nextRequestId,
+            activateSessionRequest);
+
+        context.sendRequest(new OpcuaAPU(activateMessageRequest))
+            .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+            .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
+            .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
+            .handle(opcuaActivateResponse -> {
+                LOGGER.debug("Got Activate Session Response Connection Response");
 
-                    });
             });
     }
 
+
+    private long getCurrentDateTime() {
+        return (System.currentTimeMillis() * 10000) + epochOffset;
+    }
 }
diff --git a/protocols/opcua/src/main/resources/protocols/opcua/opcua.mspec b/protocols/opcua/src/main/resources/protocols/opcua/opcua.mspec
index d4406bf..c50a140 100644
--- a/protocols/opcua/src/main/resources/protocols/opcua/opcua.mspec
+++ b/protocols/opcua/src/main/resources/protocols/opcua/opcua.mspec
@@ -56,14 +56,11 @@
         ]
         ['OPN','false'     OpcuaOpenRequest
             [simple          string '8'         'chunk']
-            [implicit          int 32             'messageSize' 'lengthInBytes']
+            [implicit        int 32             'messageSize' 'lengthInBytes']
             [simple          int 32             'secureChannelId']
-            [simple          int 32             'securityPolicyUriSize']
-            [simple          string 'securityPolicyUriSize == -1 ? 0 : securityPolicyUriSize * 8'          'endpoint']
-            [simple          int 32             'senderCertificateSize']
-            [simple          string 'senderCertificateSize == -1 ? 0 : senderCertificateSize * 8'             'senderCertificate']
-            [simple          int 32             'receiverCertificateThumbprintSize']
-            [simple          string 'receiverCertificateThumbprintSize == -1 ? 0 : receiverCertificateThumbprintSize * 8'             'receiverCertificateThumbprint']
+            [simple          PascalString       'endpoint']
+            [simple          PascalString       'senderCertificate']
+            [simple          PascalString       'receiverCertificateThumbprint']
             [simple          int 32             'sequenceNumber']
             [simple          int 32             'requestId']
             [simple          OpcuaMessage       'message']
diff --git a/protocols/opcua/src/main/xslt/opc-types.xsl b/protocols/opcua/src/main/xslt/opc-types.xsl
index c675c8a..f3e54cf 100644
--- a/protocols/opcua/src/main/xslt/opc-types.xsl
+++ b/protocols/opcua/src/main/xslt/opc-types.xsl
@@ -133,7 +133,9 @@
 ]
 
 [type 'ByteStringNodeId'
-    <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='ByteStringNodeId']"/>
+    [simple uint 16 'namespaceIndex']
+    [simple int 32 'bodyLength']
+    [array int 8 'body' count 'bodyLength == -1 ? 0 : bodyLength']
 ]
 
 [type 'DataValue'
@@ -428,7 +430,7 @@
     [simple ExpandedNodeId 'nodeId']
     [simple uint 8 'encodingMask']
     [optional int 32 'bodyLength' 'encodingMask > 0']
-    [array uint 8 'body' count 'bodyLength']
+    [array int 8 'body' count 'bodyLength == null ? 0 : bodyLength']
 ]
 
 [type 'PascalString'