/// <summary> /// Adds the specified property to the event filter. /// </summary> public void AddSelectClause(NodeId eventTypeId, QualifiedName propertyName) { SimpleAttributeOperand clause = new SimpleAttributeOperand(); clause.TypeDefinitionId = eventTypeId; clause.AttributeId = Attributes.Value; clause.BrowsePath.Add(propertyName); SelectClauses.Add(clause); }
/// <summary> /// Adds the specified browse path to the event filter. /// </summary> public void AddSelectClause(NodeId eventTypeId, string browsePath, uint attributeId) { SimpleAttributeOperand clause = new SimpleAttributeOperand(); clause.TypeDefinitionId = eventTypeId; clause.AttributeId = attributeId; if (!String.IsNullOrEmpty(browsePath)) { clause.BrowsePath = SimpleAttributeOperand.Parse(browsePath); } SelectClauses.Add(clause); }
/// <summary> /// Initializes a new instance of the <see cref="EventFieldDefinition"/> class. /// </summary> /// <param name="parentField">The parent field.</param> /// <param name="reference">The reference to the instance declaration node.</param> public EventFieldDefinition(EventFieldDefinition parentField, ReferenceDescription reference) { DeclarationNode = reference; Operand = new SimpleAttributeOperand(); // setting the typedefinition id to null ignores the event type when evaluating the operand. Operand.TypeDefinitionId = null; // event filters only support the NodeId attribute for objects and the Value attribute for Variables. Operand.AttributeId = (reference.NodeClass == NodeClass.Variable) ? Attributes.Value : Attributes.NodeId; // prefix the browse path with the parent browse path. if (parentField != null) { Operand.BrowsePath = new QualifiedNameCollection(parentField.Operand.BrowsePath); } // add the child browse name. Operand.BrowsePath.Add(reference.BrowseName); // may select sub-sets of array values. Not used in this sample. Operand.IndexRange = null; // construct the display name. StringBuilder buffer = new StringBuilder(); for (int ii = 0; ii < Operand.BrowsePath.Count; ii++) { if (buffer.Length > 0) { buffer.Append('/'); } buffer.Append(Operand.BrowsePath[ii].Name); } DisplayName = buffer.ToString(); }
/// <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> /// Collects the fields for the instance node. /// </summary> /// <param name="session">The session.</param> /// <param name="nodeId">The node id.</param> /// <param name="parentPath">The parent path.</param> /// <param name="fields">The event fields.</param> /// <param name="fieldNodeIds">The node id for the declaration of the field.</param> /// <param name="foundNodes">The table of found nodes.</param> private static void CollectFields( Session session, NodeId nodeId, QualifiedNameCollection parentPath, SimpleAttributeOperandCollection fields, List<NodeId> fieldNodeIds, Dictionary<NodeId, QualifiedNameCollection> foundNodes) { // find all of the children of the field. BrowseDescription nodeToBrowse = new BrowseDescription(); nodeToBrowse.NodeId = nodeId; nodeToBrowse.BrowseDirection = BrowseDirection.Forward; nodeToBrowse.ReferenceTypeId = ReferenceTypeIds.Aggregates; nodeToBrowse.IncludeSubtypes = true; nodeToBrowse.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable); nodeToBrowse.ResultMask = (uint)BrowseResultMask.All; ReferenceDescriptionCollection children = ClientUtils.Browse(session, nodeToBrowse, false); if (children == null) { return; } // process the children. for (int ii = 0; ii < children.Count; ii++) { ReferenceDescription child = children[ii]; if (child.NodeId.IsAbsolute) { continue; } // construct browse path. QualifiedNameCollection browsePath = new QualifiedNameCollection(parentPath); browsePath.Add(child.BrowseName); // check if the browse path is already in the list. int index = ContainsPath(fields, browsePath); if (index < 0) { SimpleAttributeOperand field = new SimpleAttributeOperand(); field.TypeDefinitionId = ObjectTypeIds.BaseEventType; field.BrowsePath = browsePath; field.AttributeId = (child.NodeClass == NodeClass.Variable) ? Attributes.Value : Attributes.NodeId; fields.Add(field); fieldNodeIds.Add((NodeId)child.NodeId); } // recusively find all of the children. NodeId targetId = (NodeId)child.NodeId; // need to guard against loops. if (!foundNodes.ContainsKey(targetId)) { foundNodes.Add(targetId, browsePath); CollectFields(session, (NodeId)child.NodeId, browsePath, fields, fieldNodeIds, foundNodes); } } }
/// <summary> /// Constructs the event filter for the subscription. /// </summary> /// <returns>The event filter.</returns> public EventFilter ConstructFilter(Session session) { EventFilter filter = new EventFilter(); // the select clauses specify the values returned with each event notification. filter.SelectClauses = SelectClauses; // the where clause restricts the events returned by the server. // it works a lot like the WHERE clause in a SQL statement and supports // arbitrary expession trees where the operands are literals or event fields. ContentFilter whereClause = new ContentFilter(); // the code below constructs a filter that looks like this: // (Severity >= X OR LastSeverity >= X) AND (SuppressedOrShelved == False) AND (OfType(A) OR OfType(B)) // add the severity. ContentFilterElement element1 = null; ContentFilterElement element2 = null; if (Severity > EventSeverity.Min) { // select the Severity property of the event. SimpleAttributeOperand operand1 = new SimpleAttributeOperand(); operand1.TypeDefinitionId = ObjectTypeIds.BaseEventType; operand1.BrowsePath.Add(BrowseNames.Severity); operand1.AttributeId = Attributes.Value; // specify the value to compare the Severity property with. LiteralOperand operand2 = new LiteralOperand(); operand2.Value = new Variant((ushort)Severity); // specify that the Severity property must be GreaterThanOrEqual the value specified. element1 = whereClause.Push(FilterOperator.GreaterThanOrEqual, operand1, operand2); } // add the suppressed or shelved. if (!IgnoreSuppressedOrShelved) { // select the SuppressedOrShelved property of the event. SimpleAttributeOperand operand1 = new SimpleAttributeOperand(); operand1.TypeDefinitionId = ObjectTypeIds.BaseEventType; operand1.BrowsePath.Add(BrowseNames.SuppressedOrShelved); operand1.AttributeId = Attributes.Value; // specify the value to compare the Severity property with. LiteralOperand operand2 = new LiteralOperand(); operand2.Value = new Variant(false); // specify that the Severity property must Equal the value specified. element2 = whereClause.Push(FilterOperator.Equals, operand1, operand2); // chain multiple elements together with an AND clause. if (element1 != null) { element1 = whereClause.Push(FilterOperator.And, element1, element2); } else { element1 = element2; } } // add the event types. if (EventTypes != null && EventTypes.Count > 0) { element2 = null; // save the last element. for (int ii = 0; ii < EventTypes.Count; ii++) { // for this example uses the 'OfType' operator to limit events to thoses with specified event type. LiteralOperand operand1 = new LiteralOperand(); operand1.Value = new Variant(EventTypes[ii]); ContentFilterElement element3 = whereClause.Push(FilterOperator.OfType, operand1); // need to chain multiple types together with an OR clause. if (element2 != null) { element2 = whereClause.Push(FilterOperator.Or, element2, element3); } else { element2 = element3; } } // need to link the set of event types with the previous filters. if (element1 != null) { whereClause.Push(FilterOperator.And, element1, element2); } } filter.WhereClause = whereClause; // return filter. return filter; }
/// <summary> /// Constructs the select clauses for a set of event types. /// </summary> /// <param name="session">The session.</param> /// <param name="eventTypeIds">The event type ids.</param> /// <returns>The select clauses for all fields discovered.</returns> /// <remarks> /// Each event type is an ObjectType in the address space. The fields supported by the /// server are defined as children of the ObjectType. Many of the fields are manadatory /// and are defined by the UA information model, however, indiviudual servers many not /// support all of the optional fields. /// /// This method browses the type model and /// </remarks> public SimpleAttributeOperandCollection ConstructSelectClauses( Session session, params NodeId[] eventTypeIds) { // browse the type model in the server address space to find the fields available for the event type. SimpleAttributeOperandCollection selectClauses = new SimpleAttributeOperandCollection(); // must always request the NodeId for the condition instances. // this can be done by specifying an operand with an empty browse path. SimpleAttributeOperand operand = new SimpleAttributeOperand(); operand.TypeDefinitionId = ObjectTypeIds.BaseEventType; operand.AttributeId = Attributes.NodeId; operand.BrowsePath = new QualifiedNameCollection(); selectClauses.Add(operand); // add the fields for the selected EventTypes. if (eventTypeIds != null) { for (int ii = 0; ii < eventTypeIds.Length; ii++) { CollectFields(session, eventTypeIds[ii], selectClauses); } } // use BaseEventType as the default if no EventTypes specified. else { CollectFields(session, ObjectTypeIds.BaseEventType, selectClauses); } return selectClauses; }