You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2023/09/25 05:58:41 UTC

[plc4x] branch develop updated: fix(plc4j/opcua): Fix incorrectly handled GUID tags (#1099)

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

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new bd064a5944 fix(plc4j/opcua): Fix incorrectly handled GUID tags (#1099)
bd064a5944 is described below

commit bd064a594440160d98da61e6eae741fa2777a263
Author: takraj <ta...@gmail.com>
AuthorDate: Mon Sep 25 07:58:36 2023 +0200

    fix(plc4j/opcua): Fix incorrectly handled GUID tags (#1099)
    
    1. The driver tried to `arraycopy()` a `Long`, which caused `ArrayStoreException`.
     2. GUIDs are structured objects, that matters when it comes to byte ordering.
        The OPC-UA protocol uses little (mixed) endian GUID encoding format, while Java
        uses the standard big endian one (RFC4122), so conversion is needed.
    
    References:
     * https://reference.opcfoundation.org/Core/Part6/v104/docs/5.2.2.6
     * https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding
     * https://devblogs.microsoft.com/oldnewthing/20220928-00/?p=107221
     * https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html
     * https://www.ietf.org/rfc/rfc4122.txt
---
 .../java/opcua/protocol/OpcuaProtocolLogic.java    | 13 +++--
 .../plc4x/java/opcua/ManualOpcuaGuidTag.java       | 43 +++++++++++++++
 .../opcua/protocol/OpcuaProtocolLogicTest.java     | 63 ++++++++++++++++++++++
 3 files changed, 115 insertions(+), 4 deletions(-)

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 fb320c26d9..543db9acbc 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
@@ -18,6 +18,7 @@
  */
 package org.apache.plc4x.java.opcua.protocol;
 
+import java.nio.ByteBuffer;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
 import org.apache.plc4x.java.api.messages.*;
 import org.apache.plc4x.java.api.model.PlcConsumerRegistration;
@@ -228,10 +229,14 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             nodeId = new NodeId(new NodeIdNumeric((short) tag.getNamespace(), Long.parseLong(tag.getIdentifier())));
         } else if (tag.getIdentifierType() == OpcuaIdentifierType.GUID_IDENTIFIER) {
             UUID guid = UUID.fromString(tag.getIdentifier());
-            byte[] guidBytes = new byte[16];
-            System.arraycopy(guid.getMostSignificantBits(), 0, guidBytes, 0, 8);
-            System.arraycopy(guid.getLeastSignificantBits(), 0, guidBytes, 8, 8);
-            nodeId = new NodeId(new NodeIdGuid((short) tag.getNamespace(), guidBytes));
+            ByteBuffer bb = ByteBuffer.allocate(16)
+                    .order(java.nio.ByteOrder.LITTLE_ENDIAN)
+                    .putInt((int)(guid.getMostSignificantBits() >> (4*8)))
+                    .putShort((short)(guid.getMostSignificantBits() >> (2*8)))
+                    .putShort((short)guid.getMostSignificantBits())
+                    .order(java.nio.ByteOrder.BIG_ENDIAN)
+                    .putLong(guid.getLeastSignificantBits());
+            nodeId = new NodeId(new NodeIdGuid((short) tag.getNamespace(), bb.array()));
         } else if (tag.getIdentifierType() == OpcuaIdentifierType.STRING_IDENTIFIER) {
             nodeId = new NodeId(new NodeIdString((short) tag.getNamespace(), new PascalString(tag.getIdentifier())));
         }
diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualOpcuaGuidTag.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualOpcuaGuidTag.java
new file mode 100644
index 0000000000..1ab29c5519
--- /dev/null
+++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/ManualOpcuaGuidTag.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.plc4x.java.opcua;
+
+import org.apache.plc4x.java.DefaultPlcDriverManager;
+import org.apache.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+
+public class ManualOpcuaGuidTag {
+
+    public static void main(String... args) throws Exception {
+        DefaultPlcDriverManager driverManager = new DefaultPlcDriverManager();
+        try (PlcConnection opcuaConnection = driverManager.getConnection("opcua:tcp://opcuaserver.com:48010")) {
+            PlcReadRequest request = opcuaConnection.readRequestBuilder()
+                    .addTagAddress(
+                            "VariableWithGuidNodeId",
+                            "ns=2;g=5CE9DBCE-5D79-434C-9AC3-1CFBA9A6E92C"
+                    )
+                    .build();
+
+            PlcReadResponse response = request.execute().get();
+            System.out.println(response.getObject("VariableWithGuidNodeId"));
+        }
+    }
+}
diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogicTest.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogicTest.java
new file mode 100644
index 0000000000..5a7694c402
--- /dev/null
+++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogicTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.plc4x.java.opcua.protocol;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.plc4x.java.opcua.readwrite.NodeId;
+import org.apache.plc4x.java.opcua.readwrite.NodeIdGuid;
+import org.apache.plc4x.java.opcua.readwrite.NodeIdType;
+import org.apache.plc4x.java.opcua.tag.OpcuaTag;
+import org.junit.jupiter.api.Test;
+
+public class OpcuaProtocolLogicTest {
+
+    @Test
+    public void testGenerateNodeId() {
+        OpcuaTag tag = OpcuaTag.of("ns=2;g=00112233-4455-6677-8899-aabbccddeeff");
+        NodeId nodeId = OpcuaProtocolLogic.generateNodeId(tag);
+        assertEquals(NodeIdType.nodeIdTypeGuid, nodeId.getNodeId().getNodeType());
+
+        NodeIdGuid nodeIdGuid = (NodeIdGuid) nodeId.getNodeId();
+        assertEquals(2, nodeIdGuid.getNamespaceIndex());
+        assertArrayEquals(
+                new byte[] {
+                        (byte) 0x33,
+                        (byte) 0x22,
+                        (byte) 0x11,
+                        (byte) 0x00,
+                        (byte) 0x55,
+                        (byte) 0x44,
+                        (byte) 0x77,
+                        (byte) 0x66,
+                        (byte) 0x88,
+                        (byte) 0x99,
+                        (byte) 0xaa,
+                        (byte) 0xbb,
+                        (byte) 0xcc,
+                        (byte) 0xdd,
+                        (byte) 0xee,
+                        (byte) 0xff
+                },
+                nodeIdGuid.getId()
+        );
+    }
+}