/// <summary> /// Validates a read value id parameter. /// </summary> public static ServiceResult Validate(ReadValueId valueId) { // check for null structure. if (valueId == null) { return(StatusCodes.BadStructureMissing); } // null node ids are always invalid. if (valueId.NodeId == null) { return(StatusCodes.BadNodeIdInvalid); } // must be a legimate attribute value. if (!Attributes.IsValid(valueId.AttributeId)) { return(StatusCodes.BadAttributeIdInvalid); } // data encoding and index range is only valid for value attributes. if (valueId.AttributeId != Attributes.Value) { if (!String.IsNullOrEmpty(valueId.IndexRange)) { return(StatusCodes.BadIndexRangeNoData); } if (!QualifiedName.IsNull(valueId.DataEncoding)) { return(StatusCodes.BadDataEncodingInvalid); } } // initialize as empty. valueId.ParsedIndexRange = NumericRange.Empty; // parse the index range if specified. if (!String.IsNullOrEmpty(valueId.IndexRange)) { try { valueId.ParsedIndexRange = NumericRange.Parse(valueId.IndexRange); } catch (Exception e) { return(ServiceResult.Create(e, StatusCodes.BadIndexRangeInvalid, String.Empty)); } } else { valueId.ParsedIndexRange = NumericRange.Empty; } // passed basic validation. return(null); }
/// <summary> /// Adds type to the table. A browse name is only required if it is a ReferenceType. /// </summary> /// <param name="subTypeId">The sub type identifier.</param> /// <param name="superTypeId">The super type identifier.</param> /// <param name="browseName">Name of the browse.</param> /// <remarks> /// Updates the any existing entry. /// </remarks> private void AddSubtype(NodeId subTypeId, NodeId superTypeId, QualifiedName browseName) { lock (m_lock) { // lookup the supertype. TypeInfo superTypeInfo = null; if (!NodeId.IsNull(superTypeId)) { if (!m_nodes.TryGetValue(superTypeId, out superTypeInfo)) { throw ServiceResultException.Create(StatusCodes.BadNodeIdInvalid, "A valid supertype identifier is required."); } } // create the type info. TypeInfo typeInfo = null; if (!m_nodes.TryGetValue(subTypeId, out typeInfo)) { typeInfo = new TypeInfo(); m_nodes.Add(subTypeId, typeInfo); } // update the info. typeInfo.NodeId = subTypeId; typeInfo.SuperType = superTypeInfo; typeInfo.Deleted = false; // add to supertype. if (superTypeInfo != null) { superTypeInfo.AddSubType(typeInfo); } // remove the encodings. if (typeInfo.Encodings != null) { foreach (NodeId encoding in typeInfo.Encodings) { m_encodings.Remove(encoding); } } // add reference type. if (!QualifiedName.IsNull(browseName)) { typeInfo.BrowseName = browseName; m_referenceTypes[browseName] = typeInfo; } } }
/// <summary> /// Removes a subtype. /// </summary> /// <param name="typeId">The type identifier.</param> public void Remove(ExpandedNodeId typeId) { if (NodeId.IsNull(typeId) || typeId.ServerIndex != 0) { return; } NodeId localId = ExpandedNodeId.ToNodeId(typeId, m_namespaceUris); if (localId == null) { return; } lock (m_lock) { // remove type. TypeInfo typeInfo = null; if (!m_nodes.TryGetValue(localId, out typeInfo)) { return; } m_nodes.Remove(localId); // setting the flag to deleted ensures references from subtypes are not broken. typeInfo.Deleted = true; // remove from subtype list. if (typeInfo.SuperType != null) { typeInfo.SuperType.RemoveSubType(localId); } // remove encodings. if (typeInfo.Encodings != null) { for (int ii = 0; ii < typeInfo.Encodings.Length; ii++) { m_encodings.Remove(typeInfo.Encodings[ii]); } } // remove reference type. if (!QualifiedName.IsNull(typeInfo.BrowseName)) { m_referenceTypes.Remove(typeInfo.BrowseName); } } }
/// <summary> /// Adds a reference to target entity. /// </summary> /// <remarks> /// Will not add the reference if the browse name does not match the browse name filter. /// </remarks> public virtual void Add(NodeId referenceTypeId, bool isInverse, NodeState target) { lock (DataLock) { // do not return add target unless the browse name matches. if (!QualifiedName.IsNull(m_browseName)) { if (target.BrowseName != m_browseName) { return; } } m_references.Add(new NodeStateReference(referenceTypeId, isInverse, target)); } }
/// <summary> /// Initializes a new event. /// </summary> /// <param name="context">The current system context.</param> /// <param name="source">The source of the event.</param> /// <param name="severity">The severity for the event.</param> /// <param name="message">The default message.</param> public virtual void Initialize( ISystemContext context, NodeState source, EventSeverity severity, LocalizedText message) { m_eventId = new PropertyState<byte[]>(this); m_eventId.Value = Guid.NewGuid().ToByteArray(); m_eventType = new PropertyState<NodeId>(this); m_eventType.Value = GetDefaultTypeDefinitionId(context.NamespaceUris); TypeDefinitionId = m_eventType.Value; if (source != null) { if (!NodeId.IsNull(source.NodeId)) { m_sourceNode = new PropertyState<NodeId>(this); m_sourceNode.Value = source.NodeId; m_sourceNode.RolePermissions = source.RolePermissions; m_sourceNode.UserRolePermissions = source.UserRolePermissions; m_sourceNode.NodeId = source.NodeId; } if (!QualifiedName.IsNull(source.BrowseName)) { m_sourceName = new PropertyState<string>(this); m_sourceName.Value = source.BrowseName.Name; } } m_time = new PropertyState<DateTime>(this); m_time.Value = DateTime.UtcNow; m_receiveTime = new PropertyState<DateTime>(this); m_receiveTime.Value = DateTime.UtcNow; m_severity = new PropertyState<ushort>(this); m_severity.Value = (ushort)severity; m_message = new PropertyState<LocalizedText>(this); m_message.Value = message; }
/// <summary> /// Returns the string representation of the object. /// </summary> public string ToString(string format, IFormatProvider formatProvider) { if (format == null) { if (m_displayName != null && !String.IsNullOrEmpty(m_displayName.Text)) { return(m_displayName.Text); } if (!QualifiedName.IsNull(m_browseName)) { return(m_browseName.Name); } return(Utils.Format("(unknown {0})", ((NodeClass)m_nodeClass).ToString().ToLower())); } throw new FormatException(Utils.Format("Invalid format string: '{0}'.", format)); }
/// <summary cref="ITypeTable.FindReferenceType" /> public NodeId FindReferenceType(QualifiedName browseName) { // check for empty name. if (QualifiedName.IsNull(browseName)) { return(null); } lock (m_lock) { TypeInfo typeInfo = null; if (!m_referenceTypes.TryGetValue(browseName, out typeInfo)) { return(null); } return(typeInfo.NodeId); } }
/// <summary> /// Updates the nodeset string tables and returns a NodeId that references those tables. /// </summary> /// <param name="qname">The qualified name.</param> /// <param name="targetNamespaceUris">The target namespace URIs.</param> /// <param name="sourceNamespaceUris">The source namespace URIs.</param> /// <returns>A NodeId that references those tables.</returns> private static QualifiedName Translate( QualifiedName qname, NamespaceTable targetNamespaceUris, NamespaceTable sourceNamespaceUris) { if (targetNamespaceUris == null) { throw new ArgumentNullException("targetNamespaceUris"); } if (sourceNamespaceUris == null) { throw new ArgumentNullException("sourceNamespaceUris"); } if (QualifiedName.IsNull(qname)) { return(qname); } ushort namespaceIndex = 0; if (qname.NamespaceIndex > 0) { string uri = sourceNamespaceUris.GetString(qname.NamespaceIndex); if (uri == null) { return(qname); } int index = targetNamespaceUris.GetIndex(uri); if (index == -1) { index = targetNamespaceUris.Append(uri); } namespaceIndex = (ushort)index; } return(new QualifiedName(qname.Name, namespaceIndex)); }
/// <summary> /// Formats a browse path. /// </summary> public static string Format(IList <QualifiedName> browsePath) { if (browsePath == null || browsePath.Count == 0) { return(String.Empty); } StringBuilder buffer = new StringBuilder(); for (int ii = 0; ii < browsePath.Count; ii++) { QualifiedName browseName = browsePath[ii]; if (QualifiedName.IsNull(browseName)) { throw ServiceResultException.Create(StatusCodes.BadBrowseNameInvalid, "BrowseName cannot be null"); } buffer.Append('/'); if (browseName.NamespaceIndex != 0) { buffer.AppendFormat("{0}:", browseName.NamespaceIndex); } for (int jj = 0; jj < browseName.Name.Length; jj++) { char ch = browseName.Name[jj]; if (ch == '&' || ch == '/') { buffer.Append('&'); } buffer.Append(ch); } } return(buffer.ToString()); }
/// <summary> /// Applies the data encoding to the value. /// </summary> public static ServiceResult ApplyDataEncoding(ServiceMessageContext context, QualifiedName dataEncoding, ref object value) { // check if nothing to do. if (QualifiedName.IsNull(dataEncoding) || value == null) { return(ServiceResult.Good); } // check for supported encoding type. if (dataEncoding.NamespaceIndex != 0) { return(StatusCodes.BadDataEncodingUnsupported); } bool useXml = dataEncoding.Name == DefaultXml; if (!useXml && dataEncoding.Name != DefaultBinary) { return(StatusCodes.BadDataEncodingUnsupported); } try { // check for array of encodeables. IList <IEncodeable> encodeables = value as IList <IEncodeable>; if (encodeables == null) { // check for array of extension objects. IList <ExtensionObject> extensions = value as IList <ExtensionObject>; if (extensions != null) { // convert extension objects to encodeables. encodeables = new IEncodeable[extensions.Count]; for (int ii = 0; ii < encodeables.Count; ii++) { if (ExtensionObject.IsNull(extensions[ii])) { encodeables[ii] = null; continue; } IEncodeable element = extensions[ii].Body as IEncodeable; if (element == null) { return(StatusCodes.BadTypeMismatch); } encodeables[ii] = element; } } } // apply data encoding to the array. if (encodeables != null) { ExtensionObject[] extensions = new ExtensionObject[encodeables.Count]; for (int ii = 0; ii < extensions.Length; ii++) { extensions[ii] = Encode(context, encodeables[ii], useXml); } value = extensions; return(ServiceResult.Good); } // check for scalar value. IEncodeable encodeable = value as IEncodeable; if (encodeable == null) { ExtensionObject extension = value as ExtensionObject; if (extension == null) { return(StatusCodes.BadDataEncodingUnsupported); } encodeable = extension.Body as IEncodeable; } if (encodeable == null) { return(StatusCodes.BadDataEncodingUnsupported); } // do conversion. value = Encode(context, encodeable, useXml); return(ServiceResult.Good); } catch (Exception e) { return(ServiceResult.Create(e, StatusCodes.BadTypeMismatch, "Could not convert value to requested format.")); } }
/// <summary> /// Adds a node to the type table if it is a type and does not already exist. If it exists references are updated. /// </summary> /// <param name="node">The node.</param> public void Add(ILocalNode node) { // ignore null. if (node == null || NodeId.IsNull(node.NodeId)) { return; } // ignore non-types. if ((node.NodeClass & (NodeClass.ObjectType | NodeClass.VariableType | NodeClass.ReferenceType | NodeClass.DataType)) == 0) { return; } NodeId localsuperTypeId = null; // find the supertype. ExpandedNodeId superTypeId = node.References.FindTarget(ReferenceTypeIds.HasSubtype, true, false, null, 0); 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) { // lookup the supertype. TypeInfo superTypeInfo = null; if (localsuperTypeId != null) { if (!m_nodes.TryGetValue(localsuperTypeId, out superTypeInfo)) { throw ServiceResultException.Create(StatusCodes.BadNodeIdInvalid, "A valid supertype identifier is required."); } } // create the type info. TypeInfo typeInfo = null; if (!m_nodes.TryGetValue(node.NodeId, out typeInfo)) { typeInfo = new TypeInfo(); m_nodes.Add(node.NodeId, typeInfo); } // update the info. typeInfo.NodeId = node.NodeId; typeInfo.SuperType = superTypeInfo; typeInfo.Deleted = false; // add to supertype. if (superTypeInfo != null) { superTypeInfo.AddSubType(typeInfo); } // remove the encodings. if (typeInfo.Encodings != null) { foreach (NodeId encoding in typeInfo.Encodings) { m_encodings.Remove(encoding); } } // any new encodings. IList <IReference> encodings = node.References.Find(ReferenceTypeIds.HasEncoding, false, false, null); if (encodings.Count > 0) { typeInfo.Encodings = new NodeId[encodings.Count]; for (int ii = 0; ii < encodings.Count; ii++) { typeInfo.Encodings[ii] = ExpandedNodeId.ToNodeId(encodings[ii].TargetId, m_namespaceUris); m_encodings[typeInfo.Encodings[ii]] = typeInfo; } } // add reference type. if ((node.NodeClass & NodeClass.ReferenceType) != 0) { if (!QualifiedName.IsNull(typeInfo.BrowseName)) { m_referenceTypes.Remove(typeInfo.BrowseName); } typeInfo.BrowseName = node.BrowseName; m_referenceTypes[node.BrowseName] = typeInfo; } } }
/// <summary> /// Adds a set of nodes to the table. /// </summary> /// <param name="nodeSet">The node set.</param> /// <param name="externalReferences">The external references.</param> /// <returns></returns> public List <Node> Import(NodeSet nodeSet, IDictionary <NodeId, IList <IReference> > externalReferences) { List <Node> importedNodes = new List <Node>(); if (nodeSet == null) { return(importedNodes); } // add the nodes. foreach (Node nodeToImport in nodeSet.Nodes) { // ignore empty nodes. if (nodeToImport == null || NodeId.IsNull(nodeToImport.NodeId)) { continue; } Node node = nodeSet.Copy(nodeToImport, m_namespaceUris, m_serverUris); // assign a browse name. if (QualifiedName.IsNull(node.BrowseName)) { node.BrowseName = new QualifiedName(node.NodeId.ToString(), 1); } // assign a display name. if (LocalizedText.IsNullOrEmpty(node.DisplayName)) { node.DisplayName = new LocalizedText(node.BrowseName.Name); } // index references (the node ids in the references were translated by the Copy() call above). foreach (ReferenceNode reference in node.References) { // ignore invalid references. if (NodeId.IsNull(reference.ReferenceTypeId) || NodeId.IsNull(reference.TargetId)) { continue; } // ignore missing targets. ExpandedNodeId targetId = reference.TargetId; if (NodeId.IsNull(targetId)) { continue; } // index reference. node.ReferenceTable.Add(reference.ReferenceTypeId, reference.IsInverse, targetId); // see if a remote node needs to be created. if (targetId.ServerIndex != 0) { RemoteNode remoteNode = Find(targetId) as RemoteNode; if (remoteNode == null) { remoteNode = new RemoteNode(this, targetId); InternalAdd(remoteNode); } remoteNode.AddRef(); } } // clear imported references. node.References.Clear(); // add the node. InternalAdd(node); importedNodes.Add(node); } // import the nodes. foreach (Node node in importedNodes) { // ignore invalid nodes. if (node == null || NodeId.IsNull(node.NodeId)) { continue; } // add reverse references. foreach (IReference reference in node.ReferenceTable) { Node targetNode = Find(reference.TargetId) as Node; if (targetNode == null) { if (reference.TargetId.ServerIndex != 0) { continue; } // return the reverse reference to a node outside the table. if (externalReferences != null) { NodeId targetId = ExpandedNodeId.ToNodeId(reference.TargetId, m_namespaceUris); if (targetId == null) { continue; } IList <IReference> referenceList = null; if (!externalReferences.TryGetValue(targetId, out referenceList)) { externalReferences[targetId] = referenceList = new List <IReference>(); } ReferenceNode reverseReference = new ReferenceNode(); reverseReference.ReferenceTypeId = reference.ReferenceTypeId; reverseReference.IsInverse = !reference.IsInverse; reverseReference.TargetId = node.NodeId; referenceList.Add(reverseReference); } continue; } // type definition and modelling rule references are one way. if (reference.ReferenceTypeId != ReferenceTypeIds.HasTypeDefinition && reference.ReferenceTypeId != ReferenceTypeIds.HasModellingRule) { targetNode.ReferenceTable.Add(reference.ReferenceTypeId, !reference.IsInverse, node.NodeId); } } // see if it is a type. if (m_typeTree != null) { m_typeTree.Add(node); } } return(importedNodes); }
/// <summary> /// Initializes the instance from an event notification. /// </summary> /// <param name="context">The context.</param> /// <param name="fields">The fields selected for the event notification.</param> /// <param name="e">The event notification.</param> /// <remarks> /// This method creates components based on the browse paths in the event field and sets /// the NodeId or Value based on values in the event notification. /// </remarks> public void Update( ISystemContext context, SimpleAttributeOperandCollection fields, EventFieldList e) { for (int ii = 0; ii < fields.Count; ii++) { SimpleAttributeOperand field = fields[ii]; object value = e.EventFields[ii].Value; // check if value provided. if (value == null) { continue; } // extract the NodeId for the event. if (field.BrowsePath.Count == 0) { if (field.AttributeId == Attributes.NodeId) { this.NodeId = value as NodeId; continue; } } // extract the type definition for the event. if (field.BrowsePath.Count == 1) { if (field.AttributeId == Attributes.Value) { if (field.BrowsePath[0] == BrowseNames.EventType) { m_typeDefinitionId = value as NodeId; continue; } } } // save value for child node. NodeState parent = this; for (int jj = 0; jj < field.BrowsePath.Count; jj++) { // find a predefined child identified by the browse name. BaseInstanceState child = parent.CreateChild(context, field.BrowsePath[jj]); // create a placeholder for unknown children. if (child == null) { if (field.AttributeId == Attributes.Value) { child = new BaseDataVariableState(parent); } else { child = new BaseObjectState(parent); } parent.AddChild(child); } // ensure the browse name is set. if (QualifiedName.IsNull(child.BrowseName)) { child.BrowseName = field.BrowsePath[jj]; } // ensure the display name is set. if (LocalizedText.IsNullOrEmpty(child.DisplayName)) { child.DisplayName = child.BrowseName.Name; } // process next element in path. if (jj < field.BrowsePath.Count - 1) { parent = child; continue; } // save the variable value. if (field.AttributeId == Attributes.Value) { BaseVariableState variable = child as BaseVariableState; if (variable != null && field.AttributeId == Attributes.Value) { try { variable.WrappedValue = e.EventFields[ii]; } catch (Exception) { variable.Value = null; } } break; } // save the node id. child.NodeId = value as NodeId; } } }
/// <summary> /// Finds the child with the specified browse name. /// </summary> protected override BaseInstanceState FindChild( ISystemContext context, QualifiedName browseName, bool createOrReplace, BaseInstanceState replacement) { if (QualifiedName.IsNull(browseName)) { return(null); } BaseInstanceState instance = null; switch (browseName.Name) { case BrowseNames.InputArguments: { if (createOrReplace) { if (InputArguments == null) { if (replacement == null) { InputArguments = new PropertyState <Argument[]>(this); } else { InputArguments = (PropertyState <Argument[]>)replacement; } } } instance = InputArguments; break; } case BrowseNames.OutputArguments: { if (createOrReplace) { if (OutputArguments == null) { if (replacement == null) { OutputArguments = new PropertyState <Argument[]>(this); } else { OutputArguments = (PropertyState <Argument[]>)replacement; } } } instance = OutputArguments; break; } } if (instance != null) { return(instance); } return(base.FindChild(context, browseName, createOrReplace, replacement)); }