diff --git a/Libraries/Opc.Ua.Server/NodeManager/INodeManager.cs b/Libraries/Opc.Ua.Server/NodeManager/INodeManager.cs
index 4c8ed1b746..7eba8a9d4f 100644
--- a/Libraries/Opc.Ua.Server/NodeManager/INodeManager.cs
+++ b/Libraries/Opc.Ua.Server/NodeManager/INodeManager.cs
@@ -33,11 +33,24 @@ using System.Text;
namespace Opc.Ua.Server
{
+ ///
+ /// An interface to an object that creates a INodeManager object.
+ ///
+ public interface INodeManagerFactory
+ {
+ ///
+ /// The INodeManager factory.
+ ///
+ /// The server instance.
+ /// The application configuration.
+ INodeManager Create(IServerInternal server, ApplicationConfiguration configuration);
+ }
+
///
/// An interface to an object that manages a set of nodes in the address space.
///
public interface INodeManager
- {
+ {
///
/// Returns the NamespaceUris for the Nodes belonging to the NodeManager.
///
@@ -61,8 +74,8 @@ namespace Opc.Ua.Server
/// by other node managers. In these cases, the node managers only manage one half of those references. The
/// other half of the reference should be returned to the MasterNodeManager.
///
- void CreateAddressSpace(IDictionary> externalReferences);
-
+ void CreateAddressSpace(IDictionary> externalReferences);
+
///
/// Deletes the address by releasing all resources and disconnecting from any underlying system.
///
@@ -85,17 +98,17 @@ namespace Opc.Ua.Server
///
/// The node manager checks the dictionary for nodes that it owns and ensures the associated references exist.
///
- void AddReferences(IDictionary> references);
-
+ void AddReferences(IDictionary> references);
+
///
/// Deletes a reference.
///
ServiceResult DeleteReference(
- object sourceHandle,
- NodeId referenceTypeId,
- bool isInverse,
- ExpandedNodeId targetId,
- bool deleteBidirectional);
+ object sourceHandle,
+ NodeId referenceTypeId,
+ bool isInverse,
+ ExpandedNodeId targetId,
+ bool deleteBidirectional);
///
/// Returns the metadata associated with the node.
@@ -125,8 +138,8 @@ namespace Opc.Ua.Server
/// Thrown if the context, continuationPoint or references parameters are null.
/// Thrown if an error occurs during processing.
void Browse(
- OperationContext context,
- ref ContinuationPoint continuationPoint,
+ OperationContext context,
+ ref ContinuationPoint continuationPoint,
IList references);
///
@@ -146,11 +159,11 @@ namespace Opc.Ua.Server
///
/// Thrown if the sourceHandle, relativePath or targetIds parameters are null.
void TranslateBrowsePath(
- OperationContext context,
- object sourceHandle,
- RelativePathElement relativePath,
+ OperationContext context,
+ object sourceHandle,
+ RelativePathElement relativePath,
IList targetIds,
- IList unresolvedTargetIds);
+ IList unresolvedTargetIds);
///
/// Reads the attribute values for a set of nodes.
@@ -170,23 +183,23 @@ namespace Opc.Ua.Server
/// The node manager must set the Processed flag for any ReadValueId that it processes.
///
void Read(
- OperationContext context,
- double maxAge,
- IList nodesToRead,
- IList values,
+ OperationContext context,
+ double maxAge,
+ IList nodesToRead,
+ IList values,
IList errors);
-
+
///
/// Reads the history of a set of items.
///
void HistoryRead(
- OperationContext context,
- HistoryReadDetails details,
- TimestampsToReturn timestampsToReturn,
- bool releaseContinuationPoints,
- IList nodesToRead,
- IList results,
- IList errors);
+ OperationContext context,
+ HistoryReadDetails details,
+ TimestampsToReturn timestampsToReturn,
+ bool releaseContinuationPoints,
+ IList nodesToRead,
+ IList results,
+ IList errors);
///
/// Writes a set of values.
@@ -196,28 +209,28 @@ namespace Opc.Ua.Server
/// must set the Processed flag in the WriteValue structure.
///
void Write(
- OperationContext context,
- IList nodesToWrite,
+ OperationContext context,
+ IList nodesToWrite,
IList errors);
-
+
///
/// Updates the history for a set of nodes.
///
void HistoryUpdate(
- OperationContext context,
- Type detailsType,
- IList nodesToUpdate,
- IList results,
- IList errors);
+ OperationContext context,
+ Type detailsType,
+ IList nodesToUpdate,
+ IList results,
+ IList errors);
///
/// Calls a method defined on a object.
///
void Call(
- OperationContext context,
+ OperationContext context,
IList methodsToCall,
- IList results,
- IList errors);
+ IList results,
+ IList errors);
///
/// Tells the NodeManager to report events from the specified notifier.
@@ -226,13 +239,13 @@ namespace Opc.Ua.Server
/// This method may be called multiple times for the name monitoredItemId if the
/// context for that MonitoredItem changes (i.e. UserIdentity and/or Locales).
///
- ServiceResult SubscribeToEvents(
- OperationContext context,
- object sourceId,
- uint subscriptionId,
+ ServiceResult SubscribeToEvents(
+ OperationContext context,
+ object sourceId,
+ uint subscriptionId,
IEventMonitoredItem monitoredItem,
- bool unsubscribe);
-
+ bool unsubscribe);
+
///
/// Tells the NodeManager to report events all events from all sources.
///
@@ -240,64 +253,64 @@ namespace Opc.Ua.Server
/// This method may be called multiple times for the name monitoredItemId if the
/// context for that MonitoredItem changes (i.e. UserIdentity and/or Locales).
///
- ServiceResult SubscribeToAllEvents(
- OperationContext context,
- uint subscriptionId,
+ ServiceResult SubscribeToAllEvents(
+ OperationContext context,
+ uint subscriptionId,
IEventMonitoredItem monitoredItem,
- bool unsubscribe);
-
+ bool unsubscribe);
+
///
/// Tells the NodeManager to refresh any conditions.
///
- ServiceResult ConditionRefresh(
- OperationContext context,
+ ServiceResult ConditionRefresh(
+ OperationContext context,
IList monitoredItems);
///
/// Creates a set of monitored items.
///
void CreateMonitoredItems(
- OperationContext context,
- uint subscriptionId,
- double publishingInterval,
- TimestampsToReturn timestampsToReturn,
+ OperationContext context,
+ uint subscriptionId,
+ double publishingInterval,
+ TimestampsToReturn timestampsToReturn,
IList itemsToCreate,
- IList errors,
- IList filterErrors,
- IList monitoredItems,
- ref long globalIdCounter);
-
+ IList errors,
+ IList filterErrors,
+ IList monitoredItems,
+ ref long globalIdCounter);
+
///
/// Modifies a set of monitored items.
///
void ModifyMonitoredItems(
- OperationContext context,
- TimestampsToReturn timestampsToReturn,
- IList monitoredItems,
+ OperationContext context,
+ TimestampsToReturn timestampsToReturn,
+ IList monitoredItems,
IList itemsToModify,
- IList errors,
- IList filterErrors);
+ IList errors,
+ IList filterErrors);
///
/// Deletes a set of monitored items.
///
void DeleteMonitoredItems(
- OperationContext context,
- IList monitoredItems,
- IList processedItems,
- IList errors);
-
+ OperationContext context,
+ IList monitoredItems,
+ IList processedItems,
+ IList errors);
+
///
/// Changes the monitoring mode for a set of monitored items.
///
void SetMonitoringMode(
- OperationContext context,
- MonitoringMode monitoringMode,
- IList monitoredItems,
- IList processedItems,
- IList errors);
+ OperationContext context,
+ MonitoringMode monitoringMode,
+ IList monitoredItems,
+ IList processedItems,
+ IList errors);
}
-
+
///
/// An interface to an object that manages a set of nodes in the address space.
///
@@ -328,7 +341,7 @@ namespace Opc.Ua.Server
Dictionary> uniqueNodesServiceAttributesCache,
bool permissionsOnly);
}
-
+
///
/// Stores metadata required to process requests related to a node.
///
@@ -344,7 +357,7 @@ namespace Opc.Ua.Server
m_nodeId = nodeId;
}
#endregion
-
+
#region Public Properties
///
/// The handle assigned by the NodeManager that owns the Node.
@@ -360,14 +373,14 @@ namespace Opc.Ua.Server
public NodeId NodeId
{
get { return m_nodeId; }
- }
+ }
///
/// The NodeClass for the Node.
///
public NodeClass NodeClass
{
- get { return m_nodeClass; }
+ get { return m_nodeClass; }
set { m_nodeClass = value; }
}
@@ -376,7 +389,7 @@ namespace Opc.Ua.Server
///
public QualifiedName BrowseName
{
- get { return m_browseName; }
+ get { return m_browseName; }
set { m_browseName = value; }
}
@@ -385,7 +398,7 @@ namespace Opc.Ua.Server
///
public LocalizedText DisplayName
{
- get { return m_displayName; }
+ get { return m_displayName; }
set { m_displayName = value; }
}
@@ -394,7 +407,7 @@ namespace Opc.Ua.Server
///
public ExpandedNodeId TypeDefinition
{
- get { return m_typeDefinition; }
+ get { return m_typeDefinition; }
set { m_typeDefinition = value; }
}
@@ -403,7 +416,7 @@ namespace Opc.Ua.Server
///
public NodeId ModellingRule
{
- get { return m_modellingRule; }
+ get { return m_modellingRule; }
set { m_modellingRule = value; }
}
@@ -412,7 +425,7 @@ namespace Opc.Ua.Server
///
public AttributeWriteMask WriteMask
{
- get { return m_writeMask; }
+ get { return m_writeMask; }
set { m_writeMask = value; }
}
@@ -421,16 +434,16 @@ namespace Opc.Ua.Server
///
public byte EventNotifier
{
- get { return m_eventNotifier; }
+ get { return m_eventNotifier; }
set { m_eventNotifier = value; }
}
-
+
///
/// Whether the Node can be use to read or write current or historical values.
///
public byte AccessLevel
{
- get { return m_accessLevel; }
+ get { return m_accessLevel; }
set { m_accessLevel = value; }
}
@@ -439,7 +452,7 @@ namespace Opc.Ua.Server
///
public bool Executable
{
- get { return m_executable; }
+ get { return m_executable; }
set { m_executable = value; }
}
@@ -448,7 +461,7 @@ namespace Opc.Ua.Server
///
public NodeId DataType
{
- get { return m_dataType; }
+ get { return m_dataType; }
set { m_dataType = value; }
}
@@ -457,7 +470,7 @@ namespace Opc.Ua.Server
///
public int ValueRank
{
- get { return m_valueRank; }
+ get { return m_valueRank; }
set { m_valueRank = value; }
}
@@ -466,7 +479,7 @@ namespace Opc.Ua.Server
///
public IList ArrayDimensions
{
- get { return m_arrayDimensions; }
+ get { return m_arrayDimensions; }
set { m_arrayDimensions = value; }
}
diff --git a/Stack/Opc.Ua.Core/Stack/Nodes/TypeTable.cs b/Stack/Opc.Ua.Core/Stack/Nodes/TypeTable.cs
index 6e19363289..e3def2fbb6 100644
--- a/Stack/Opc.Ua.Core/Stack/Nodes/TypeTable.cs
+++ b/Stack/Opc.Ua.Core/Stack/Nodes/TypeTable.cs
@@ -15,7 +15,7 @@ using System.Collections.Generic;
namespace Opc.Ua
{
///
- /// Stores the type tree for a server.
+ /// Stores the type tree for a server.
///
public class TypeTable : ITypeTable
{
@@ -26,24 +26,24 @@ namespace Opc.Ua
/// The namespace URIs.
public TypeTable(NamespaceTable namespaceUris)
{
- m_namespaceUris = namespaceUris;
- m_referenceTypes = new SortedDictionary();
+ m_namespaceUris = namespaceUris;
+ m_referenceTypes = new SortedDictionary();
m_nodes = new NodeIdDictionary();
m_encodings = new NodeIdDictionary();
}
#endregion
#region ITypeTable Methods
- ///
+ ///
public bool IsKnown(ExpandedNodeId typeId)
- {
+ {
if (NodeId.IsNull(typeId) || typeId.ServerIndex != 0)
{
return false;
}
NodeId localId = ExpandedNodeId.ToNodeId(typeId, m_namespaceUris);
-
+
if (localId == null)
{
return false;
@@ -55,9 +55,9 @@ namespace Opc.Ua
}
}
- ///
+ ///
public bool IsKnown(NodeId typeId)
- {
+ {
if (NodeId.IsNull(typeId))
{
return false;
@@ -67,18 +67,18 @@ namespace Opc.Ua
{
return m_nodes.ContainsKey(typeId);
}
- }
-
- ///
+ }
+
+ ///
public NodeId FindSuperType(ExpandedNodeId typeId)
{
if (NodeId.IsNull(typeId) || typeId.ServerIndex != 0)
{
return NodeId.Null;
}
-
+
NodeId localId = ExpandedNodeId.ToNodeId(typeId, m_namespaceUris);
-
+
if (localId == null)
{
return NodeId.Null;
@@ -101,10 +101,10 @@ namespace Opc.Ua
return NodeId.Null;
}
}
-
- ///
+
+ ///
public NodeId FindSuperType(NodeId typeId)
- {
+ {
if (typeId == null)
{
return NodeId.Null;
@@ -128,7 +128,7 @@ namespace Opc.Ua
}
}
- ///
+ ///
public IList FindSubTypes(ExpandedNodeId typeId)
{
List subtypes = new List();
@@ -158,14 +158,14 @@ namespace Opc.Ua
}
}
- ///
+ ///
public bool IsTypeOf(ExpandedNodeId subTypeId, ExpandedNodeId superTypeId)
{
if (NodeId.IsNull(subTypeId) || subTypeId.ServerIndex != 0)
{
return false;
}
-
+
if (NodeId.IsNull(superTypeId) || superTypeId.ServerIndex != 0)
{
return false;
@@ -178,14 +178,14 @@ namespace Opc.Ua
}
NodeId startId = ExpandedNodeId.ToNodeId(subTypeId, m_namespaceUris);
-
+
if (startId == null)
{
return false;
}
NodeId targetId = ExpandedNodeId.ToNodeId(superTypeId, m_namespaceUris);
-
+
if (targetId == null)
{
return false;
@@ -204,7 +204,7 @@ namespace Opc.Ua
}
}
- ///
+ ///
public bool IsTypeOf(NodeId subTypeId, NodeId superTypeId)
{
// check for null.
@@ -218,7 +218,7 @@ namespace Opc.Ua
{
return true;
}
-
+
lock (m_lock)
{
TypeInfo typeInfo = null;
@@ -231,9 +231,8 @@ namespace Opc.Ua
return typeInfo.IsTypeOf(superTypeId);
}
}
-
-
- ///
+
+ ///
public QualifiedName FindReferenceTypeName(NodeId referenceTypeId)
{
lock (m_lock)
@@ -249,7 +248,7 @@ namespace Opc.Ua
}
}
- ///
+ ///
public NodeId FindReferenceType(QualifiedName browseName)
{
// check for empty name.
@@ -270,8 +269,8 @@ namespace Opc.Ua
return typeInfo.NodeId;
}
}
-
- ///
+
+ ///
public bool IsEncodingOf(ExpandedNodeId encodingId, ExpandedNodeId datatypeId)
{
// check for invalid ids.
@@ -279,7 +278,7 @@ namespace Opc.Ua
{
return false;
}
-
+
NodeId localId = ExpandedNodeId.ToNodeId(encodingId, m_namespaceUris);
if (localId == null)
@@ -288,7 +287,7 @@ namespace Opc.Ua
}
NodeId localTypeId = ExpandedNodeId.ToNodeId(datatypeId, m_namespaceUris);
-
+
if (localTypeId == null)
{
return false;
@@ -327,8 +326,8 @@ namespace Opc.Ua
return false;
}
}
-
- ///
+
+ ///
public bool IsEncodingFor(NodeId expectedTypeId, ExtensionObject value)
{
// no match on null values.
@@ -347,7 +346,7 @@ namespace Opc.Ua
return false;
}
- ///
+ ///
public bool IsEncodingFor(NodeId expectedTypeId, object value)
{
// null actual datatype matches nothing.
@@ -381,12 +380,12 @@ namespace Opc.Ua
// for structure types must try to determine the subtype.
ExtensionObject extension = value as ExtensionObject;
-
+
if (extension != null)
{
return IsEncodingFor(expectedTypeId, extension);
}
-
+
// every element in an array must match.
ExtensionObject[] extensions = value as ExtensionObject[];
@@ -406,10 +405,10 @@ namespace Opc.Ua
// can only get here if the value is an unrecognized data type.
return false;
}
-
- ///
- public NodeId FindDataTypeId(ExpandedNodeId encodingId)
- {
+
+ ///
+ public NodeId FindDataTypeId(ExpandedNodeId encodingId)
+ {
NodeId localId = ExpandedNodeId.ToNodeId(encodingId, m_namespaceUris);
if (localId == null)
@@ -430,8 +429,8 @@ namespace Opc.Ua
}
}
- ///
- public NodeId FindDataTypeId(NodeId encodingId)
+ ///
+ public NodeId FindDataTypeId(NodeId encodingId)
{
lock (m_lock)
{
@@ -472,7 +471,7 @@ namespace Opc.Ua
{
return;
}
-
+
// ignore non-types.
if ((node.NodeClass & (NodeClass.ObjectType | NodeClass.VariableType | NodeClass.ReferenceType | NodeClass.DataType)) == 0)
{
@@ -487,11 +486,11 @@ namespace Opc.Ua
if (superTypeId != null)
{
localsuperTypeId = ExpandedNodeId.ToNodeId(superTypeId, m_namespaceUris);
-
+
if (localsuperTypeId == null)
{
throw ServiceResultException.Create(StatusCodes.BadNodeIdInvalid, "A valid supertype identifier is required.");
- }
+ }
}
lock (m_lock)
@@ -515,7 +514,7 @@ namespace Opc.Ua
typeInfo = new TypeInfo();
m_nodes.Add(node.NodeId, typeInfo);
}
-
+
// update the info.
typeInfo.NodeId = node.NodeId;
typeInfo.SuperType = superTypeInfo;
@@ -526,7 +525,7 @@ namespace Opc.Ua
{
superTypeInfo.AddSubType(typeInfo);
}
-
+
// remove the encodings.
if (typeInfo.Encodings != null)
{
@@ -549,7 +548,7 @@ namespace Opc.Ua
m_encodings[typeInfo.Encodings[ii]] = typeInfo;
}
}
-
+
// add reference type.
if ((node.NodeClass & NodeClass.ReferenceType) != 0)
{
@@ -557,14 +556,14 @@ namespace Opc.Ua
{
m_referenceTypes.Remove(typeInfo.BrowseName);
}
-
+
typeInfo.BrowseName = node.BrowseName;
m_referenceTypes[node.BrowseName] = typeInfo;
}
}
}
-
+
///
/// Adds type to the table. A browse name is only required if it is a ReferenceType.
///
@@ -607,7 +606,7 @@ namespace Opc.Ua
lock (m_lock)
{
TypeInfo typeInfo = null;
-
+
if (!m_nodes.TryGetValue(dataTypeId, out typeInfo))
{
return false;
@@ -662,7 +661,7 @@ namespace Opc.Ua
typeInfo = new TypeInfo();
m_nodes.Add(subTypeId, typeInfo);
}
-
+
// update the info.
typeInfo.NodeId = subTypeId;
typeInfo.SuperType = superTypeInfo;
@@ -682,7 +681,7 @@ namespace Opc.Ua
m_encodings.Remove(encoding);
}
}
-
+
// add reference type.
if (!QualifiedName.IsNull(browseName))
{
@@ -701,7 +700,7 @@ namespace Opc.Ua
{
return;
}
-
+
NodeId localId = ExpandedNodeId.ToNodeId(typeId, m_namespaceUris);
if (localId == null)
@@ -716,7 +715,7 @@ namespace Opc.Ua
if (!m_nodes.TryGetValue(localId, out typeInfo))
{
- return;
+ return;
}
m_nodes.Remove(localId);
@@ -738,7 +737,7 @@ namespace Opc.Ua
m_encodings.Remove(typeInfo.Encodings[ii]);
}
}
-
+
// remove reference type.
if (!QualifiedName.IsNull(typeInfo.BrowseName))
{
@@ -771,7 +770,7 @@ namespace Opc.Ua
public bool IsTypeOf(NodeId nodeId)
{
TypeInfo typeInfo = SuperType;
-
+
while (typeInfo != null)
{
if (!typeInfo.Deleted && typeInfo.NodeId == nodeId)
@@ -834,11 +833,11 @@ namespace Opc.Ua
}
}
#endregion
-
+
#region Private Fields
private object m_lock = new object();
private NamespaceTable m_namespaceUris;
- private SortedDictionary m_referenceTypes;
+ private SortedDictionary m_referenceTypes;
private NodeIdDictionary m_nodes;
private NodeIdDictionary m_encodings;
#endregion
diff --git a/Stack/Opc.Ua.Core/Stack/State/DataTypeState.cs b/Stack/Opc.Ua.Core/Stack/State/DataTypeState.cs
index e8a654902e..25e9999df7 100644
--- a/Stack/Opc.Ua.Core/Stack/State/DataTypeState.cs
+++ b/Stack/Opc.Ua.Core/Stack/State/DataTypeState.cs
@@ -64,6 +64,7 @@ namespace Opc.Ua
/// The purpose of the data type.
///
public Opc.Ua.Export.DataTypePurpose Purpose { get; set; }
+
#region Serialization Functions
///
/// Saves the attributes from the stream.
@@ -179,21 +180,27 @@ namespace Opc.Ua
switch (attributeId)
{
case Attributes.DataTypeDefinition:
+ {
+ ExtensionObject dataTypeDefinition = m_dataTypeDefinition;
+
+ if (OnReadDataTypeDefinition != null)
{
- ExtensionObject dataTypeDefinition = m_dataTypeDefinition;
-
- if (OnReadDataTypeDefinition != null)
- {
- result = OnReadDataTypeDefinition(context, this, ref dataTypeDefinition);
- }
-
- if (ServiceResult.IsGood(result))
- {
- value = dataTypeDefinition;
- }
-
- return result;
+ result = OnReadDataTypeDefinition(context, this, ref dataTypeDefinition);
}
+
+ if (ServiceResult.IsGood(result))
+ {
+ if (dataTypeDefinition?.Body is StructureDefinition structureType &&
+ structureType.DefaultEncodingId.IsNullNodeId)
+ {
+ // one time set the id for binary encoding, currently the only supported encoding
+ structureType.SetDefaultEncodingId(context, NodeId, null);
+ }
+ value = dataTypeDefinition;
+ }
+
+ return result;
+ }
}
return base.ReadNonValueAttribute(context, attributeId, ref value);
@@ -214,26 +221,26 @@ namespace Opc.Ua
switch (attributeId)
{
case Attributes.DataTypeDefinition:
+ {
+ ExtensionObject dataTypeDefinition = value as ExtensionObject;
+
+ if ((WriteMask & AttributeWriteMask.DataTypeDefinition) == 0)
{
- ExtensionObject dataTypeDefinition = value as ExtensionObject;
-
- if ((WriteMask & AttributeWriteMask.DataTypeDefinition) == 0)
- {
- return StatusCodes.BadNotWritable;
- }
-
- if (OnWriteDataTypeDefinition != null)
- {
- result = OnWriteDataTypeDefinition(context, this, ref dataTypeDefinition);
- }
-
- if (ServiceResult.IsGood(result))
- {
- m_dataTypeDefinition = dataTypeDefinition;
- }
-
- return result;
+ return StatusCodes.BadNotWritable;
}
+
+ if (OnWriteDataTypeDefinition != null)
+ {
+ result = OnWriteDataTypeDefinition(context, this, ref dataTypeDefinition);
+ }
+
+ if (ServiceResult.IsGood(result))
+ {
+ m_dataTypeDefinition = dataTypeDefinition;
+ }
+
+ return result;
+ }
}
return base.WriteNonValueAttribute(context, attributeId, value);
diff --git a/Stack/Opc.Ua.Core/Stack/State/ModelCompilerExtension.cs b/Stack/Opc.Ua.Core/Stack/State/ModelCompilerExtension.cs
index 478c70bebf..33c53b3480 100644
--- a/Stack/Opc.Ua.Core/Stack/State/ModelCompilerExtension.cs
+++ b/Stack/Opc.Ua.Core/Stack/State/ModelCompilerExtension.cs
@@ -1,3 +1,15 @@
+/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
+ The source code in this file is covered under a dual-license scenario:
+ - RCL: for OPC Foundation members in good-standing
+ - GPL V2: everybody else
+ RCL license terms accompanied with this source code. See http://opcfoundation.org/License/RCL/1.00/
+ GNU General Public License as published by the Free Software Foundation;
+ version 2 of the License are accompanied with this source code. See http://opcfoundation.org/License/GPLv2
+ This source code is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/Stack/Opc.Ua.Core/Stack/Types/StructureDefinition.cs b/Stack/Opc.Ua.Core/Stack/Types/StructureDefinition.cs
new file mode 100644
index 0000000000..28aafe9c24
--- /dev/null
+++ b/Stack/Opc.Ua.Core/Stack/Types/StructureDefinition.cs
@@ -0,0 +1,59 @@
+/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
+ The source code in this file is covered under a dual-license scenario:
+ - RCL: for OPC Foundation members in good-standing
+ - GPL V2: everybody else
+ RCL license terms accompanied with this source code. See http://opcfoundation.org/License/RCL/1.00/
+ GNU General Public License as published by the Free Software Foundation;
+ version 2 of the License are accompanied with this source code. See http://opcfoundation.org/License/GPLv2
+ This source code is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Xml;
+using System.Runtime.Serialization;
+
+namespace Opc.Ua
+{
+ #region StructureDefinition Class
+ ///
+ ///
+ ///
+ ///
+ public partial class StructureDefinition : DataTypeDefinition
+ {
+ ///
+ /// Set the default encoding id for the requested data encoding.
+ ///
+ /// The system context with the encodeable factory.
+ /// The type id of the Data Type.
+ /// The data encoding to apply to the default encoding id.
+ public void SetDefaultEncodingId(ISystemContext context, NodeId typeId, QualifiedName dataEncoding)
+ {
+ if (context == null) throw new ArgumentNullException(nameof(context));
+ if (dataEncoding?.Name == BrowseNames.DefaultJson)
+ {
+ DefaultEncodingId = ExpandedNodeId.ToNodeId(typeId, context.NamespaceUris);
+ return;
+ }
+
+ // note: custom types must be added to the encodeable factory by the node manager to be found
+ var systemType = context.EncodeableFactory?.GetSystemType(NodeId.ToExpandedNodeId(typeId, context.NamespaceUris));
+ if (systemType != null && Activator.CreateInstance(systemType) is IEncodeable encodeable)
+ {
+ if (dataEncoding == null || dataEncoding.Name == BrowseNames.DefaultBinary)
+ {
+ DefaultEncodingId = ExpandedNodeId.ToNodeId(encodeable.BinaryEncodingId, context.NamespaceUris);
+ }
+ else if (dataEncoding.Name == BrowseNames.DefaultXml)
+ {
+ DefaultEncodingId = ExpandedNodeId.ToNodeId(encodeable.XmlEncodingId, context.NamespaceUris);
+ }
+ }
+ }
+ }
+ #endregion
+}
diff --git a/Stack/Opc.Ua.Core/Types/Encoders/EncodeableFactory.cs b/Stack/Opc.Ua.Core/Types/Encoders/EncodeableFactory.cs
index 93d23e987d..3f4ded6e2b 100644
--- a/Stack/Opc.Ua.Core/Types/Encoders/EncodeableFactory.cs
+++ b/Stack/Opc.Ua.Core/Types/Encoders/EncodeableFactory.cs
@@ -341,6 +341,26 @@ namespace Opc.Ua
}
}
+ ///
+ /// Adds an enumerable of extension types to the factory.
+ ///
+ /// The underlying system types to add to the factory
+ public void AddEncodeableTypes(IEnumerable systemTypes)
+ {
+ lock (m_lock)
+ {
+ foreach (var type in systemTypes)
+ {
+ if (type.GetTypeInfo().IsAbstract)
+ {
+ continue;
+ }
+
+ AddEncodeableType(type);
+ }
+ }
+ }
+
///
/// Returns the system type for the specified type id.
///
diff --git a/Stack/Opc.Ua.Core/Types/Encoders/IEncodeableFactory.cs b/Stack/Opc.Ua.Core/Types/Encoders/IEncodeableFactory.cs
index 26196f88c9..e1c6096d1e 100644
--- a/Stack/Opc.Ua.Core/Types/Encoders/IEncodeableFactory.cs
+++ b/Stack/Opc.Ua.Core/Types/Encoders/IEncodeableFactory.cs
@@ -46,9 +46,6 @@ namespace Opc.Ua
///
/// Adds an extension type to the factory.
///
- ///
- /// Adds an extension type to the factory.
- ///
/// The underlying system type to add to the factory
void AddEncodeableType(Type systemType);
@@ -75,6 +72,12 @@ namespace Opc.Ua
/// The assembly containing the types to add to the factory
void AddEncodeableTypes(Assembly assembly);
+ ///
+ /// Adds an enumerable of extension types to the factory.
+ ///
+ /// The underlying system types to add to the factory
+ void AddEncodeableTypes(IEnumerable systemTypes);
+
///
/// Returns the system type for the specified type id.
///
diff --git a/Tests/Opc.Ua.Client.Tests/ClientTest.cs b/Tests/Opc.Ua.Client.Tests/ClientTest.cs
index 262724b179..6e1358317f 100644
--- a/Tests/Opc.Ua.Client.Tests/ClientTest.cs
+++ b/Tests/Opc.Ua.Client.Tests/ClientTest.cs
@@ -303,6 +303,23 @@ namespace Opc.Ua.Client.Tests
m_session.ChangePreferredLocales(locale);
}
+ [Test]
+ public void ReadDataTypeDefinition()
+ {
+ // Test Read a DataType Node
+ var node = m_session.ReadNode(DataTypeIds.ProgramDiagnosticDataType);
+ Assert.NotNull(node);
+ var dataTypeNode = (DataTypeNode)node;
+ Assert.NotNull(dataTypeNode);
+ var dataTypeDefinition = dataTypeNode.DataTypeDefinition;
+ Assert.NotNull(dataTypeDefinition);
+ Assert.True(dataTypeDefinition is ExtensionObject);
+ Assert.NotNull(dataTypeDefinition.Body);
+ Assert.True(dataTypeDefinition.Body is StructureDefinition);
+ StructureDefinition structureDefinition = dataTypeDefinition.Body as StructureDefinition;
+ Assert.AreEqual(ObjectIds.ProgramDiagnosticDataType_Encoding_DefaultBinary, structureDefinition.DefaultEncodingId);
+ }
+
[Theory, Order(400)]
public async Task BrowseFullAddressSpace(string securityPolicy)
{