java.lang.Object
org.eclipse.milo.opcua.sdk.core.typetree.TypeTree<org.eclipse.milo.opcua.sdk.core.typetree.DataType>
org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
org.eclipse.milo.opcua.sdk.client.typetree.LazyClientDataTypeTree

public class LazyClientDataTypeTree extends org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
A lazy-loading DataTypeTree that resolves types on demand by browsing inverse HasSubtype references.

Unlike DataTypeTreeBuilder which eagerly builds the entire tree by forward browsing from NodeIds0.BaseDataType, this implementation starts with only the root type and resolves additional types lazily when they are queried.

This approach is useful when servers don't support recursive forward browsing of the DataType hierarchy or when only a subset of types is needed.

Thread Safety

This implementation is thread-safe. All read operations acquire a read lock and all modifications acquire a write lock. However, note that type resolution (which includes network I/O to browse and read from the server) is performed while holding the write lock. This means that concurrent threads attempting to resolve different types will be serialized. Once a type is resolved, later lookups only require the read lock and can proceed concurrently.

Resolution Behavior

Resolution errors (e.g., network failures, non-existent types) do not cause exceptions to be thrown from query methods like getDataType(NodeId). Instead, null is returned. Once a resolution attempt has failed, it will not be retried unless clearFailedResolutions() is called.

Namespace Table

This tree caches a copy of the server's NamespaceTable for converting ExpandedNodeIds during browse operations. If the server's namespace array changes (e.g., after a reconnection or dynamic namespace registration), call invalidateNamespaceTable() or refreshNamespaceTable() to update the cached copy.

  • Nested Class Summary

    Nested classes/interfaces inherited from class org.eclipse.milo.opcua.sdk.core.typetree.TypeTree

    org.eclipse.milo.opcua.sdk.core.typetree.TypeTree.Type
  • Field Summary

    Fields inherited from class org.eclipse.milo.opcua.sdk.core.typetree.TypeTree

    tree, types
  • Constructor Summary

    Constructors
    Constructor
    Description
    Create a new LazyClientDataTypeTree with only NodeIds0.BaseDataType initially loaded.
    LazyClientDataTypeTree(OpcUaClient client, org.eclipse.milo.opcua.stack.core.util.Tree<org.eclipse.milo.opcua.sdk.core.typetree.DataType> preSeededTree)
    Create a new LazyClientDataTypeTree with a pre-seeded tree.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Clear failed resolution attempts, allowing retry.
    boolean
    containsType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId typeId)
     
    getBackingClass(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    @Nullable org.eclipse.milo.opcua.stack.core.types.builtin.NodeId
    getBinaryEncodingId(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    org.eclipse.milo.opcua.stack.core.OpcUaDataType
    getBuiltinType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    @Nullable org.eclipse.milo.opcua.sdk.core.typetree.DataType
    getDataType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    @Nullable org.eclipse.milo.opcua.stack.core.types.structured.DataTypeDefinition
    getDataTypeDefinition(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    @Nullable org.eclipse.milo.opcua.stack.core.types.builtin.NodeId
    getJsonEncodingId(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    org.eclipse.milo.opcua.stack.core.util.Tree<org.eclipse.milo.opcua.sdk.core.typetree.DataType>
    Get a snapshot of the root of the underlying Tree structure.
    @Nullable org.eclipse.milo.opcua.stack.core.util.Tree<org.eclipse.milo.opcua.sdk.core.typetree.DataType>
    getTreeNode(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    @Nullable org.eclipse.milo.opcua.sdk.core.typetree.DataType
    getType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId nodeId)
     
    @Nullable org.eclipse.milo.opcua.stack.core.types.builtin.NodeId
    getXmlEncodingId(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    void
    Invalidate the cached NamespaceTable, causing it to be re-read on next use.
    boolean
    isAssignable(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId, Class<?> clazz)
     
    boolean
    isEnumType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    boolean
    isResolved(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId typeId)
    Check if a type has been resolved/loaded without triggering resolution.
    boolean
    isStructType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
     
    boolean
    isSubtypeOf(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId typeId, org.eclipse.milo.opcua.stack.core.types.builtin.NodeId superTypeId)
     
    void
    Refresh the cached NamespaceTable immediately by reading it from the server.

    Methods inherited from class org.eclipse.milo.opcua.sdk.core.typetree.TypeTree

    isSubtypeOf, isSubtypeOf, isSubtypeOf

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • LazyClientDataTypeTree

      public LazyClientDataTypeTree(OpcUaClient client)
      Create a new LazyClientDataTypeTree with only NodeIds0.BaseDataType initially loaded.
      Parameters:
      client - a connected OpcUaClient.
    • LazyClientDataTypeTree

      public LazyClientDataTypeTree(OpcUaClient client, org.eclipse.milo.opcua.stack.core.util.Tree<org.eclipse.milo.opcua.sdk.core.typetree.DataType> preSeededTree)
      Create a new LazyClientDataTypeTree with a pre-seeded tree.

      This constructor supports preloading known types (e.g., namespace 0 types from a code generator) to reduce the number of lazy resolutions needed.

      Parameters:
      client - a connected OpcUaClient.
      preSeededTree - a pre-built tree containing known types.
  • Method Details

    • invalidateNamespaceTable

      public void invalidateNamespaceTable()
      Invalidate the cached NamespaceTable, causing it to be re-read on next use.

      Call this method when the server's namespace array may have changed (e.g., after a reconnection or when namespaces are dynamically registered on the server).

      See Also:
    • refreshNamespaceTable

      public void refreshNamespaceTable() throws org.eclipse.milo.opcua.stack.core.UaException
      Refresh the cached NamespaceTable immediately by reading it from the server.

      Unlike invalidateNamespaceTable(), this method reads the namespace table immediately rather than deferring until the next type resolution.

      Throws:
      org.eclipse.milo.opcua.stack.core.UaException - if reading the namespace table fails.
      See Also:
    • isResolved

      public boolean isResolved(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId typeId)
      Check if a type has been resolved/loaded without triggering resolution.
      Parameters:
      typeId - the NodeId to check.
      Returns:
      true if the type is already loaded in the tree.
    • clearFailedResolutions

      public void clearFailedResolutions()
      Clear failed resolution attempts, allowing retry.

      When a type resolution fails (e.g., due to network errors or non-existent types), the failure is recorded to avoid repeated failed attempts. This method clears those records, allowing later queries for those types to attempt resolution again.

      This is useful after transient network issues have been resolved or when the server's type system may have changed.

    • getRoot

      public org.eclipse.milo.opcua.stack.core.util.Tree<org.eclipse.milo.opcua.sdk.core.typetree.DataType> getRoot()
      Get a snapshot of the root of the underlying Tree structure.

      Because this tree is lazily populated, returning the live tree would expose callers to potential concurrent modification during traversal. Instead, this method returns a deep copy (snapshot) of the current tree state, taken under a read lock.

      The snapshot reflects the types that have been resolved at the time of the call. Types resolved after the snapshot is taken will not appear in the returned tree.

      Note: The Tree structure is copied, but the contained DataType instances are shared references. This is safe because DataType instances are effectively immutable.

      Overrides:
      getRoot in class org.eclipse.milo.opcua.sdk.core.typetree.TypeTree<org.eclipse.milo.opcua.sdk.core.typetree.DataType>
      Returns:
      a snapshot copy of the root node of the underlying Tree structure.
    • containsType

      public boolean containsType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId typeId)
      Overrides:
      containsType in class org.eclipse.milo.opcua.sdk.core.typetree.TypeTree<org.eclipse.milo.opcua.sdk.core.typetree.DataType>
    • getType

      public @Nullable org.eclipse.milo.opcua.sdk.core.typetree.DataType getType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId nodeId)
      Overrides:
      getType in class org.eclipse.milo.opcua.sdk.core.typetree.TypeTree<org.eclipse.milo.opcua.sdk.core.typetree.DataType>
    • getBackingClass

      public Class<?> getBackingClass(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      getBackingClass in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • getBuiltinType

      public org.eclipse.milo.opcua.stack.core.OpcUaDataType getBuiltinType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      getBuiltinType in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • getDataType

      public @Nullable org.eclipse.milo.opcua.sdk.core.typetree.DataType getDataType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      getDataType in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • getBinaryEncodingId

      public @Nullable org.eclipse.milo.opcua.stack.core.types.builtin.NodeId getBinaryEncodingId(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      getBinaryEncodingId in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • getXmlEncodingId

      public @Nullable org.eclipse.milo.opcua.stack.core.types.builtin.NodeId getXmlEncodingId(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      getXmlEncodingId in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • getJsonEncodingId

      public @Nullable org.eclipse.milo.opcua.stack.core.types.builtin.NodeId getJsonEncodingId(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      getJsonEncodingId in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • getDataTypeDefinition

      public @Nullable org.eclipse.milo.opcua.stack.core.types.structured.DataTypeDefinition getDataTypeDefinition(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      getDataTypeDefinition in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • isAssignable

      public boolean isAssignable(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId, Class<?> clazz)
      Overrides:
      isAssignable in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • isEnumType

      public boolean isEnumType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      isEnumType in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • isStructType

      public boolean isStructType(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      isStructType in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • getTreeNode

      public @Nullable org.eclipse.milo.opcua.stack.core.util.Tree<org.eclipse.milo.opcua.sdk.core.typetree.DataType> getTreeNode(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId dataTypeId)
      Overrides:
      getTreeNode in class org.eclipse.milo.opcua.sdk.core.typetree.DataTypeTree
    • isSubtypeOf

      public boolean isSubtypeOf(org.eclipse.milo.opcua.stack.core.types.builtin.NodeId typeId, org.eclipse.milo.opcua.stack.core.types.builtin.NodeId superTypeId)
      Overrides:
      isSubtypeOf in class org.eclipse.milo.opcua.sdk.core.typetree.TypeTree<org.eclipse.milo.opcua.sdk.core.typetree.DataType>