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 2022/09/15 20:19:29 UTC
[plc4x] branch plc4j/opcua-browse updated: chore(plc4x): Browse now browses each node. Still need to sort out how to create the BrowseItem Tree.
This is an automated email from the ASF dual-hosted git repository.
hutcheb pushed a commit to branch plc4j/opcua-browse
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/plc4j/opcua-browse by this push:
new 018c27ed8 chore(plc4x): Browse now browses each node. Still need to sort out how to create the BrowseItem Tree.
018c27ed8 is described below
commit 018c27ed8bef9971cf774c5e6b380e4ca0d2f912
Author: Ben Hutcheson <be...@gmail.com>
AuthorDate: Thu Sep 15 14:19:17 2022 -0600
chore(plc4x): Browse now browses each node. Still need to sort out how to create the BrowseItem Tree.
---
.../java/opcua/protocol/OpcuaProtocolLogic.java | 142 +++++++++++++--------
protocols/opcua/src/main/xslt/opc-common.xsl | 19 +--
2 files changed, 96 insertions(+), 65 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 5b3c75358..62924d546 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
@@ -39,6 +39,7 @@ import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration;
import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionField;
import org.apache.plc4x.java.spi.values.IEC61131ValueHandler;
+import org.apache.plc4x.java.spi.values.PlcINT;
import org.apache.plc4x.java.spi.values.PlcList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -83,6 +84,9 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
private Map<Long, OpcuaSubscriptionHandle> subscriptions = new HashMap<>();
private SecureChannel channel;
private AtomicBoolean securedConnection = new AtomicBoolean(false);
+ private LinkedHashMap<String, ReferenceDescription> discoveredNodes= new LinkedHashMap<>();
+ private LinkedHashMap<String, ReferenceDescription> browsedNodes= new LinkedHashMap<>();
+ private LinkedHashMap<String, String> nodeChildren= new LinkedHashMap<>();
@Override
public void setConfiguration(OpcuaConfiguration configuration) {
@@ -128,8 +132,8 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
channel.onDiscover(context);
}
- private CompletableFuture<List<PlcBrowseItem>> browseNode(NodeId nodeId) {
- CompletableFuture<List<PlcBrowseItem>> future = new CompletableFuture<>();
+ private CompletableFuture<PlcBrowseItem> browseNode(ExpandedNodeId nodeId) {
+ CompletableFuture<PlcBrowseItem> future = new CompletableFuture<>();
RequestHeader requestHeader = new RequestHeader(channel.getAuthenticationToken(),
SecureChannel.getCurrentDateTime(),
channel.getRequestHandle(),
@@ -140,7 +144,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
List<ExtensionObjectDefinition> requestedValues = new ArrayList<>(1);
requestedValues.add(new BrowseDescription(
- nodeId,
+ new NodeId(nodeId.getNodeId()),
BrowseDirection.browseDirectionForward,
new NodeId(new NodeIdTwoByte((short) 33)),
true,
@@ -176,13 +180,15 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
Consumer<byte[]> consumer = opcuaResponse -> {
try {
ExtensionObjectDefinition reply = ExtensionObject.staticParse(new ReadBufferByteBased(opcuaResponse, ByteOrder.LITTLE_ENDIAN), false).getBody();
+ PlcBrowseItem value = null;
if (reply instanceof BrowseResponse) {
BrowseResponse response = (BrowseResponse) reply;
BrowseResult castResult = (BrowseResult) response.getResults().get(0);
- List<PlcBrowseItem> values = new ArrayList<>(response.getResults().size());
+ ArrayList<PlcBrowseItem> children = new ArrayList<>(0);
for (ExtensionObjectDefinition result : castResult.getReferences()) {
ReferenceDescription referenceResult = (ReferenceDescription) result;
+ referenceResult.getNodeId().getIdentifier();
String typeDefinition = referenceResult.getTypeDefinition().getIdentifier();
PlcValueType plcValue = null;
if (OpcuaDataType.isDefined(typeDefinition)) {
@@ -191,33 +197,36 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
} else {
plcValue = PlcValueType.Struct;
}
- ExpandedNodeId tempNodeId = ((ReferenceDescription) result).getNodeId();
- NodeId tempNode = new NodeId(
- new NodeIdString(tempNodeId tempNodeId.getIdentifier());
- )
- CompletableFuture<List<PlcBrowseItem>> childFuture = browseNode();
- List<PlcBrowseItem> list = childFuture.get(5000L, TimeUnit.SECONDS);
- if (list != null) {
- values.add(new DefaultPlcBrowseItem(
- referenceResult.getBrowseName().getName().getStringValue(),
- referenceResult.getDisplayName().getText().getStringValue(),
- plcValue,
- true,
- true,
- true, list, null));
- } else {
- values.add(new DefaultPlcBrowseItem(
- referenceResult.getBrowseName().getName().getStringValue(),
- referenceResult.getDisplayName().getText().getStringValue(),
- plcValue,
- true,
- true,
- true, new ArrayList<PlcBrowseItem>(0), null));
+ String test = referenceResult.getNodeId().getIdentifier();
+ if (referenceResult.getNodeClass() == NodeClass.nodeClassObject || referenceResult.getNodeClass() == NodeClass.nodeClassVariable) {
+ nodeChildren.put(nodeId.getIdentifier(), referenceResult.getNodeId().getIdentifier());
+ discoveredNodes.put(referenceResult.getNodeId().getIdentifier(), referenceResult);
}
}
- future.complete(values);
+ value = new DefaultPlcBrowseItem(
+ nodeId.getIdentifier(),
+ nodeId.getIdentifier(),
+ PlcValueType.INT,
+ true,
+ true,
+ true,
+ new ArrayList<>(0),
+ new HashMap<>()
+ );
+
+ future.complete(value);
} else {
- List<PlcBrowseItem> values = new ArrayList<>(0);
+ value = new DefaultPlcBrowseItem(
+ nodeId.getIdentifier(),
+ nodeId.getNamespaceURI().getStringValue(),
+ PlcValueType.INT,
+ false,
+ false,
+ false,
+ new ArrayList<>(0),
+ new HashMap<>()
+ );
+
if (reply instanceof ServiceFault) {
ExtensionObjectDefinition header = ((ServiceFault) reply).getResponseHeader();
LOGGER.error("Browse request ended up with ServiceFault: {}", header);
@@ -225,17 +234,10 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
LOGGER.error("Remote party returned an error '{}'", reply);
}
- future.complete(values);
- return;
+ future.complete(value);
}
} catch (ParseException e) {
future.completeExceptionally(new PlcRuntimeException(e));
- } catch (ExecutionException e) {
- throw new RuntimeException(e);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } catch (TimeoutException e) {
- throw new RuntimeException(e);
}
};
@@ -262,25 +264,61 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
@Override
public CompletableFuture<PlcBrowseResponse> browse(PlcBrowseRequest browseRequest) {
CompletableFuture<PlcBrowseResponse> future = new CompletableFuture<>();
+ boolean browsable = true;
+ PlcBrowseResponse response = null;
- CompletableFuture<List<PlcBrowseItem>> childFuture = browseNode(new ExpandedNodeId(
- false,
- false,
- new NodeIdTwoByte((short) 85),
- null,
- 0L));
+ ReferenceDescription referenceDescription = new ReferenceDescription(
+ new NodeId(
+ new NodeIdTwoByte((short) 47)
+ ),
+ true,
+ new ExpandedNodeId(
+ false,
+ false,
+ new NodeIdTwoByte((short) 85),
+ null,
+ 0L),
+ new QualifiedName(
+ 0,
+ new PascalString("root")
+ ),
+ new LocalizedText(
+ true,
+ true,
+ new PascalString("en"),
+ new PascalString("root")),
+ NodeClass.nodeClassObject,
+ new ExpandedNodeId(
+ false,
+ false,
+ new NodeIdTwoByte((short) 2034),
+ null,
+ 0L)
+ );
- PlcBrowseResponse response = null;
- try {
- response = new DefaultPlcBrowseResponse(browseRequest, PlcResponseCode.OK, childFuture.get(1000L, TimeUnit.SECONDS));
- future.complete(response);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } catch (ExecutionException e) {
- throw new RuntimeException(e);
- } catch (TimeoutException e) {
- throw new RuntimeException(e);
+ discoveredNodes.put(referenceDescription.getNodeId().getIdentifier(), referenceDescription);
+
+ while (browsable) {
+ CompletableFuture<PlcBrowseItem> childFuture = browseNode(referenceDescription.getNodeId());
+
+ try {
+ PlcBrowseItem responseItem = childFuture.get(10L, TimeUnit.SECONDS);
+ browsedNodes.put(referenceDescription.getNodeId().getIdentifier(), referenceDescription);
+ discoveredNodes.remove(referenceDescription.getNodeId().getIdentifier());
+ Optional<String> first = discoveredNodes.keySet().stream().findFirst();
+ if (first.isPresent()) {
+ referenceDescription = discoveredNodes.get(first.get());
+ }
+ } catch (TimeoutException | InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ if (discoveredNodes.isEmpty()) {
+ browsable = false;
+ }
}
+
+ response = new DefaultPlcBrowseResponse(browseRequest, PlcResponseCode.OK, new ArrayList<PlcBrowseItem>());
+ future.complete(response);
//new DefaultPlcBrowseResponse(browseRequest, PlcResponseCode.INTERNAL_ERROR, values)
return future;
}
diff --git a/protocols/opcua/src/main/xslt/opc-common.xsl b/protocols/opcua/src/main/xslt/opc-common.xsl
index 630feca92..73ca19b34 100644
--- a/protocols/opcua/src/main/xslt/opc-common.xsl
+++ b/protocols/opcua/src/main/xslt/opc-common.xsl
@@ -354,16 +354,15 @@
<xsl:function name="plc4x:getDataTypeLength" as="xs:integer">
<xsl:param name="lengthMap" as="map(xs:string, xs:int)"/>
<xsl:param name="datatype"/>
- <xsl:message>[DEBUG] Getting length of <xsl:value-of select="xs:string($datatype[@TypeName])"/></xsl:message>
<xsl:choose>
- <xsl:when test="map:contains($lengthMap, xs:string($datatype[@TypeName]))">
- <xsl:message>[DEBUG] Bit Length <xsl:value-of select="$lengthMap(xs:string($datatype[@TypeName]))"/></xsl:message>
- <xsl:value-of select="map:get($lengthMap, xs:string($datatype[@TypeName]))"/>
+ <xsl:when test="map:contains($lengthMap, xs:string($datatype/[@TypeName]))">
+ <xsl:message>[DEBUG] Bit Length <xsl:value-of select="$lengthMap(xs:string($datatype/[@TypeName]))"/></xsl:message>
+ <xsl:value-of select="map:get($lengthMap, xs:string($datatype/[@TypeName]))"/>
</xsl:when>
- <xsl:when test="($datatype[@TypeName] = 'opc:Bit') or ($datatype[@TypeName] = 'opc:Boolean')">
+ <xsl:when test="($datatype/[@TypeName] = 'opc:Bit') or ($datatype/[@TypeName] = 'opc:Boolean')">
<xsl:choose>
- <xsl:when test="$datatype[@Length] != ''">
- <xsl:value-of select="xs:int($datatype[@Length])"/>
+ <xsl:when test="$datatype/[@Length] != ''">
+ <xsl:value-of select="xs:int($datatype/[@Length])"/>
</xsl:when>
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
@@ -379,7 +378,6 @@
<xsl:param name="currentNodePosition" as="xs:int"/>
<xsl:param name="currentBitPosition" as="xs:int"/>
<xsl:param name="currentBytePosition" as="xs:int"/>
- <xsl:message>[DEBUG] Recursively rearranging bit order in nodes, Position - <xsl:value-of select="$currentNodePosition"/>, Bit Position - <xsl:value-of select="$currentBitPosition"/>, Byte Position - <xsl:value-of select="$currentBytePosition"/></xsl:message>
<xsl:for-each select="$baseNode/opc:Field">
<xsl:message>[DEBUG] <xsl:value-of select="position()"/> - <xsl:value-of select="@TypeName"/></xsl:message>
</xsl:for-each>
@@ -390,7 +388,6 @@
<xsl:choose>
<xsl:when test="$currentBitPosition != 0">
<!-- Add a reserved field if we are halfway through a Byte. -->
- <xsl:message>[DEBUG] Adding a reserved field</xsl:message>
<xsl:call-template name="plc4x:parseFields">
<xsl:with-param name="baseNode">
<xsl:copy-of select="$baseNode/opc:Field[position() lt ($currentNodePosition - $currentBytePosition)]"/>
@@ -427,7 +424,6 @@
<xsl:choose>
<xsl:when test="$currentBitPosition=0">
<!-- Put node into current position -->
- <xsl:message>[DEBUG] First Bit in Byte</xsl:message>
<xsl:call-template name="plc4x:parseFields">
<xsl:with-param name="baseNode">
<xsl:copy-of select="$baseNode/opc:Field"/>
@@ -446,7 +442,6 @@
</xsl:when>
<xsl:otherwise>
<!-- Put node into correct position based on bit and byte position -->
- <xsl:message>[DEBUG] Additional Bit in Byte</xsl:message>
<xsl:call-template name="plc4x:parseFields">
<xsl:with-param name="baseNode">
<xsl:copy-of select="$baseNode/opc:Field[position() lt ($currentNodePosition - $currentBytePosition)]"/>
@@ -472,7 +467,6 @@
<xsl:choose>
<xsl:when test="$currentBitPosition != 0 and $currentBitPosition lt 8">
<!-- Add a reserved field if we are halfway through a Byte. -->
- <xsl:message>[DEBUG] Adding a reserved field</xsl:message>
<xsl:call-template name="plc4x:parseFields">
<xsl:with-param name="baseNode">
<xsl:copy-of select="$baseNode/opc:Field[position() lt ($currentNodePosition - $currentBytePosition)]"/>
@@ -497,7 +491,6 @@
</xsl:when>
<xsl:otherwise>
<!-- Put node into current position -->
- <xsl:message>[DEBUG] not a bit data type, just leave it in it's place</xsl:message>
<xsl:call-template name="plc4x:parseFields">
<xsl:with-param name="baseNode">
<xsl:copy-of select="$baseNode/opc:Field"/>