/* ======================================================================== * Copyright (c) 2005-2019 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.Text; using System.Collections.Generic; using Opc.Ua; using Opc.Ua.Client; namespace OpcUaHelper { /// /// Stores a type declaration retrieved from a server. /// public class TypeDeclaration { /// /// The node if for the type. /// public NodeId NodeId; /// /// The fully inhierited list of instance declarations for the type. /// public List Declarations; } /// /// Stores an instance declaration fetched from the server. /// public class InstanceDeclaration { /// /// The type that the declaration belongs to. /// public NodeId RootTypeId; /// /// The browse path to the instance declaration. /// public QualifiedNameCollection BrowsePath; /// /// The browse path to the instance declaration. /// public string BrowsePathDisplayText; /// /// A localized path to the instance declaration. /// public string DisplayPath; /// /// The node id for the instance declaration. /// public NodeId NodeId; /// /// The node class of the instance declaration. /// public NodeClass NodeClass; /// /// The browse name for the instance declaration. /// public QualifiedName BrowseName; /// /// The display name for the instance declaration. /// public string DisplayName; /// /// The description for the instance declaration. /// public string Description; /// /// The modelling rule for the instance declaration (i.e. Mandatory or Optional). /// public NodeId ModellingRule; /// /// The data type for the instance declaration. /// public NodeId DataType; /// /// The value rank for the instance declaration. /// public int ValueRank; /// /// The built-in type parent for the data type. /// public BuiltInType BuiltInType; /// /// A localized name for the data type. /// public string DataTypeDisplayText; /// /// An instance declaration that has been overridden by the current instance. /// public InstanceDeclaration OverriddenDeclaration; } /// /// A field in a filter declaration. /// public class FilterDeclarationField { /// /// Creates a new instance of a FilterDeclarationField. /// public FilterDeclarationField() { Selected = true; DisplayInList = false; FilterEnabled = false; FilterOperator = FilterOperator.Equals; FilterValue = Variant.Null; InstanceDeclaration = null; } /// /// Creates a new instance of a FilterDeclarationField. /// public FilterDeclarationField( InstanceDeclaration instanceDeclaration ) { Selected = true; DisplayInList = false; FilterEnabled = false; FilterOperator = FilterOperator.Equals; FilterValue = Variant.Null; InstanceDeclaration = instanceDeclaration; } /// /// Creates a new instance of a FilterDeclarationField. /// public FilterDeclarationField( FilterDeclarationField field ) { Selected = field.Selected; DisplayInList = field.DisplayInList; FilterEnabled = field.FilterEnabled; FilterOperator = field.FilterOperator; FilterValue = field.FilterValue; InstanceDeclaration = field.InstanceDeclaration; } /// /// Whether the field is returned as part of the event notification. /// public bool Selected; /// /// Whether the field is displayed in the list view. /// public bool DisplayInList; /// /// Whether the filter is enabled. /// public bool FilterEnabled; /// /// The filter operator to use in the where clause. /// public FilterOperator FilterOperator; /// /// The filter value to use in the where clause. /// public Variant FilterValue; /// /// The instance declaration associated with the field. /// public InstanceDeclaration InstanceDeclaration; } /// /// A declararion of an event filter. /// public class FilterDeclaration { /// /// Creates a new instance of a FilterDeclaration. /// public FilterDeclaration() { EventTypeId = Opc.Ua.ObjectTypeIds.BaseEventType; Fields = new List( ); } /// /// Creates a new instance of a FilterDeclaration. /// public FilterDeclaration( TypeDeclaration eventType, FilterDeclaration template ) { EventTypeId = eventType.NodeId; Fields = new List( ); foreach (InstanceDeclaration instanceDeclaration in eventType.Declarations) { if (instanceDeclaration.NodeClass == NodeClass.Method) { continue; } if (NodeId.IsNull( instanceDeclaration.ModellingRule )) { continue; } FilterDeclarationField element = new FilterDeclarationField( instanceDeclaration ); Fields.Add( element ); // set reasonable defaults. if (template == null) { if (instanceDeclaration.RootTypeId == Opc.Ua.ObjectTypeIds.BaseEventType && instanceDeclaration.BrowseName != Opc.Ua.BrowseNames.EventId) { element.DisplayInList = true; } } // preserve filter settings. else { foreach (FilterDeclarationField field in template.Fields) { if (field.InstanceDeclaration.BrowsePathDisplayText == element.InstanceDeclaration.BrowsePathDisplayText) { element.DisplayInList = field.DisplayInList; element.FilterEnabled = field.FilterEnabled; element.FilterOperator = field.FilterOperator; element.FilterValue = field.FilterValue; break; } } } } } /// /// Creates a new instance of a FilterDeclaration. /// public FilterDeclaration( FilterDeclaration declaration ) { EventTypeId = declaration.EventTypeId; Fields = new List( declaration.Fields.Count ); for (int ii = 0; ii < declaration.Fields.Count; ii++) { Fields.Add( new FilterDeclarationField( declaration.Fields[ii] ) ); } } /// /// Returns the event filter defined by the filter declaration. /// public EventFilter GetFilter() { EventFilter filter = new EventFilter( ); filter.SelectClauses = GetSelectClause( ); filter.WhereClause = GetWhereClause( ); return filter; } /// /// Adds a simple field to the declaration. /// public void AddSimpleField( QualifiedName browseName, BuiltInType dataType, bool displayInList ) { AddSimpleField( new QualifiedName[] { browseName }, NodeClass.Variable, dataType, ValueRanks.Scalar, displayInList ); } /// /// Adds a simple field to the declaration. /// public void AddSimpleField( QualifiedName browseName, BuiltInType dataType, int valueRank, bool displayInList ) { AddSimpleField( new QualifiedName[] { browseName }, NodeClass.Variable, dataType, valueRank, displayInList ); } /// /// Adds a simple field to the declaration. /// public void AddSimpleField( QualifiedName[] browseNames, BuiltInType dataType, int valueRank, bool displayInList ) { AddSimpleField( browseNames, NodeClass.Variable, dataType, valueRank, displayInList ); } /// /// Adds a simple field to the declaration. /// public void AddSimpleField( QualifiedName[] browseNames, NodeClass nodeClass, BuiltInType dataType, int valueRank, bool displayInList ) { FilterDeclarationField field = new FilterDeclarationField( ); field.DisplayInList = displayInList; field.InstanceDeclaration = new InstanceDeclaration( ); field.InstanceDeclaration.NodeClass = nodeClass; if (browseNames != null) { field.InstanceDeclaration.BrowseName = browseNames[browseNames.Length - 1]; field.InstanceDeclaration.BrowsePath = new QualifiedNameCollection( ); StringBuilder path = new StringBuilder( ); for (int ii = 0; ii < browseNames.Length; ii++) { if (path.Length > 0) { path.Append( '/' ); } path.Append( browseNames[ii] ); field.InstanceDeclaration.BrowsePath.Add( browseNames[ii] ); } field.InstanceDeclaration.BrowsePathDisplayText = path.ToString( ); } field.InstanceDeclaration.BuiltInType = dataType; field.InstanceDeclaration.DataType = (uint)dataType; field.InstanceDeclaration.ValueRank = valueRank; field.InstanceDeclaration.DataTypeDisplayText = dataType.ToString( ); if (valueRank >= 0) { field.InstanceDeclaration.DataTypeDisplayText += "[]"; } field.InstanceDeclaration.DisplayName = field.InstanceDeclaration.BrowseName.Name; field.InstanceDeclaration.DisplayPath = field.InstanceDeclaration.BrowsePathDisplayText; field.InstanceDeclaration.RootTypeId = ObjectTypeIds.BaseEventType; Fields.Add( field ); } /// /// Returns the select clause defined by the filter declaration. /// public SimpleAttributeOperandCollection GetSelectClause() { SimpleAttributeOperandCollection selectClause = new SimpleAttributeOperandCollection( ); SimpleAttributeOperand operand = new SimpleAttributeOperand( ); operand.TypeDefinitionId = Opc.Ua.ObjectTypeIds.BaseEventType; operand.AttributeId = Attributes.NodeId; selectClause.Add( operand ); foreach (FilterDeclarationField field in Fields) { if (field.Selected) { operand = new SimpleAttributeOperand( ); operand.TypeDefinitionId = field.InstanceDeclaration.RootTypeId; operand.AttributeId = (field.InstanceDeclaration.NodeClass == NodeClass.Object) ? Attributes.NodeId : Attributes.Value; operand.BrowsePath = field.InstanceDeclaration.BrowsePath; selectClause.Add( operand ); } } return selectClause; } /// /// Returns the where clause defined by the filter declaration. /// public ContentFilter GetWhereClause() { ContentFilter whereClause = new ContentFilter( ); ContentFilterElement element1 = whereClause.Push( FilterOperator.OfType, EventTypeId ); EventFilter filter = new EventFilter( ); foreach (FilterDeclarationField field in Fields) { if (field.FilterEnabled) { SimpleAttributeOperand operand1 = new SimpleAttributeOperand( ); operand1.TypeDefinitionId = field.InstanceDeclaration.RootTypeId; operand1.AttributeId = (field.InstanceDeclaration.NodeClass == NodeClass.Object) ? Attributes.NodeId : Attributes.Value; operand1.BrowsePath = field.InstanceDeclaration.BrowsePath; LiteralOperand operand2 = new LiteralOperand( ); operand2.Value = field.FilterValue; ContentFilterElement element2 = whereClause.Push( field.FilterOperator, operand1, operand2 ); element1 = whereClause.Push( FilterOperator.And, element1, element2 ); } } return whereClause; } /// /// Returns the value for the specified browse name. /// public T GetValue( QualifiedName browseName, VariantCollection fields, T defaultValue ) { if (fields == null || fields.Count == 0) { return defaultValue; } if (browseName == null) { browseName = QualifiedName.Null; } for (int ii = 0; ii < this.Fields.Count; ii++) { if (this.Fields[ii].InstanceDeclaration.BrowseName == browseName) { if (ii >= fields.Count + 1) { return defaultValue; } object value = fields[ii + 1].Value; if (typeof( T ).IsInstanceOfType( value )) { return (T)value; } break; } } return defaultValue; } /// /// The type of event. /// public NodeId EventTypeId; /// /// The list of declarations for the fields. /// public List Fields; } }