Beispiel #1
0
        private void SetOperatorMI_Click(object sender, EventArgs e)
        {
            try
            {
                ContentFilterElement element = SelectedTag as ContentFilterElement;

                if (element == null)
                {
                    return;
                }

                FilterOperator op = element.FilterOperator;

                if (!new FilterOperatorEditDlg().ShowDialog(ref op))
                {
                    return;
                }

                element.FilterOperator = op;
                UpdateItem(ItemsLV.SelectedItems[0], element);
                AdjustColumns();
            }
            catch (Exception exception)
            {
                GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception);
            }
        }
Beispiel #2
0
        public void InList(object operandFirst1, object operandFirst2, object operandFirst3, object operandFirst4, object expectedResult)
        {
            LiteralOperand loperand1 = new LiteralOperand();
            LiteralOperand loperand2 = new LiteralOperand();
            LiteralOperand loperand3 = new LiteralOperand();
            LiteralOperand loperand4 = new LiteralOperand();

            loperand1.Value = new Variant(operandFirst1);
            loperand2.Value = new Variant(operandFirst2);
            loperand3.Value = new Variant(operandFirst3);
            loperand4.Value = new Variant(operandFirst4);

            ContentFilterElement filterElement = new ContentFilterElement();

            filterElement.FilterOperator = FilterOperator.InList;
            filterElement.SetOperands(new List <LiteralOperand>()
            {
                loperand1, loperand2, loperand3, loperand4
            });
            Filter.WhereClause.Elements = new[] { filterElement };

            // apply filter.
            object result = Filter.WhereClause.Evaluate(FilterContext, TestFilterTarget);

            Assert.AreEqual(expectedResult, result);
        }
Beispiel #3
0
        public void BinaryFilterOperators(object operandFirst1, object operandFirst2, FilterOperator filterOp, object expectedResult)
        {
            LiteralOperand loperand1 = new LiteralOperand();
            LiteralOperand loperand2 = new LiteralOperand();

            loperand1.Value = new Variant(operandFirst1);
            if (filterOp == FilterOperator.Cast)
            {
                NodeId uintNoid = new NodeId(operandFirst2, 0);
                loperand2.Value = new Variant(uintNoid);
            }
            else
            {
                loperand2.Value = new Variant(operandFirst2);
            }


            ContentFilterElement filterElement = new ContentFilterElement();

            filterElement.FilterOperator = filterOp;
            filterElement.SetOperands(new List <LiteralOperand>()
            {
                loperand1, loperand2
            });
            Filter.WhereClause.Elements = new[] { filterElement };

            // apply filter.
            object result = Filter.WhereClause.Evaluate(FilterContext, TestFilterTarget);

            Assert.AreEqual(expectedResult, result);
        }
Beispiel #4
0
        /// <summary>
        /// Returns the where clause defined by the filter declaration.
        /// </summary>
        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);
        }
        public void NonBoolWithUnary(object operandFirst1, object operandFirst2, FilterOperator filterOp1, FilterOperator filterOp2, object expectedResult)
        {
            // Setup the First ContentfilterElement (the BitwiseOr or BitwiseAnd filter operation)
            LiteralOperand loperand1 = new LiteralOperand();
            LiteralOperand loperand2 = new LiteralOperand();
            loperand1.Value = new Variant(operandFirst1);
            if (filterOp1 == FilterOperator.Cast)
            {
                NodeId uintNoid = new NodeId(operandFirst2, 0);
                loperand2.Value = new Variant(uintNoid);
            }
            else
            {
                loperand2.Value = new Variant(operandFirst2);
            }
            

            ContentFilterElement filterElement1 = new ContentFilterElement();
            filterElement1.FilterOperator = filterOp1;
            filterElement1.SetOperands(new List<FilterOperand>() { loperand1, loperand2 });

            // Setup the Second ContentfilterElement
            ElementOperand elementOperand = new ElementOperand();
            elementOperand.Index = 1; // link to filterElement1

            ContentFilterElement filterElement2 = new ContentFilterElement();
            filterElement2.FilterOperator = filterOp2;
            filterElement2.SetOperands(new List<FilterOperand>() { elementOperand });

            Filter.WhereClause.Elements = new[] { filterElement2, filterElement1 };

            // apply filter.
            object result = Filter.WhereClause.Evaluate(FilterContext, TestFilterTarget);
            Assert.AreEqual(expectedResult, result);
        }
Beispiel #6
0
        private void EditValueMI_Click(object sender, EventArgs e)
        {
            try
            {
                ContentFilterElement element = SelectedTag as ContentFilterElement;

                if (element == null)
                {
                    return;
                }

                List <FilterOperand> operands = element.GetOperands();

                if (operands.Count != 2)
                {
                    return;
                }

                LiteralOperand literal = operands[1] as LiteralOperand;

                if (literal == null)
                {
                    return;
                }

                // get the current value.
                object currentValue = literal.Value.Value;

                if (currentValue == null)
                {
                    currentValue = String.Empty;
                }

                // edit the value.
                object value = new SimpleValueEditDlg().ShowDialog(currentValue, currentValue.GetType());

                if (value == null)
                {
                    return;
                }

                // update value.
                literal.Value = new Variant(value);
                ContentFilter filter = GetFilter();
                Update(filter);
            }
            catch (Exception exception)
            {
                GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception);
            }
        }
Beispiel #7
0
        /// <see cref="BaseListCtrl.UpdateItem" />
        protected override void UpdateItem(ListViewItem listItem, object item, int index)
        {
            ContentFilterElement element = item as ContentFilterElement;

            if (element == null)
            {
                base.UpdateItem(listItem, item);
                return;
            }

            listItem.SubItems[0].Text = String.Format("[{0}]", index);
            listItem.SubItems[1].Text = String.Format("{0}", element.ToString(m_session.NodeCache));

            listItem.Tag = element;
        }
        public void UnaryFilterOperators(object operandFirst1, FilterOperator filterOp, object expectedResult)
        {
            LiteralOperand loperand1 = new LiteralOperand();

            loperand1.Value = new Variant(operandFirst1);

            ContentFilterElement filterElement = new ContentFilterElement();
            filterElement.FilterOperator = filterOp;
            filterElement.SetOperands(new List<LiteralOperand>() { loperand1 });
            Filter.WhereClause.Elements = new[] { filterElement };

            // apply filter.
            object result = Filter.WhereClause.Evaluate(FilterContext, TestFilterTarget);
            Assert.AreEqual(expectedResult, result);
        }
Beispiel #9
0
        /// <summary>
        /// Returns the list of elements in the control.
        /// </summary>
        public List <ContentFilterElement> GetElements()
        {
            List <ContentFilterElement> elements = new List <ContentFilterElement>();

            for (int ii = 0; ii < ItemsLV.Items.Count; ii++)
            {
                ContentFilterElement element = ItemsLV.Items[ii].Tag as ContentFilterElement;

                if (element != null)
                {
                    elements.Add(element);
                }
            }

            return(elements);
        }
Beispiel #10
0
        /// <summary>
        /// Returns the filter in the control.
        /// </summary>
        public ContentFilter GetFilter()
        {
            ContentFilter filter = new ContentFilter();

            for (int ii = 0; ii < ItemsLV.Items.Count; ii++)
            {
                ContentFilterElement element = ItemsLV.Items[ii].Tag as ContentFilterElement;

                if (element != null)
                {
                    filter.Elements.Add(element);
                }
            }

            return(filter);
        }
 /// <summary>
 /// Convert to service model
 /// </summary>
 /// <param name="model"></param>
 /// <param name="encoder"></param>
 /// <returns></returns>
 public static ContentFilterElementModel Encode(this IVariantEncoder encoder,
                                                ContentFilterElement model)
 {
     if (model == null)
     {
         return(null);
     }
     return(new ContentFilterElementModel {
         FilterOperands = model.FilterOperands
                          .Select(e => e.Body)
                          .Cast <FilterOperand>()
                          .Select(o => encoder.Encode(o))
                          .ToList(),
         FilterOperator = model.FilterOperator.ToServiceType()
     });
 }
Beispiel #12
0
        private void CreateElementNotMI_Click(object sender, EventArgs e)
        {
            try {
                if (ItemsLV.SelectedItems.Count != 1)
                {
                    return;
                }

                ContentFilterElement element1 = ItemsLV.SelectedItems[0].Tag as ContentFilterElement;

                ContentFilter filter = GetFilter();
                filter.Push(FilterOperator.Not, element1);

                Update(filter);
            } catch (Exception exception) {
                GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception);
            }
        }
Beispiel #13
0
        private static void QueryFirstCall(Session session)
        {
            ViewDescription vd = new ViewDescription();

            vd.ViewId      = 5000;
            vd.ViewVersion = 0;
            NodeTypeDescriptionCollection nt  = new NodeTypeDescriptionCollection();
            NodeTypeDescription           ntd = new NodeTypeDescription();

            ExpandedNodeId enid = new ExpandedNodeId("ns=3;s=AirConditioner_1");

            ntd.TypeDefinitionNode = enid;
            nt.Add(ntd);

            ContentFilterElement           cfe  = new ContentFilterElement();
            ContentFilterElementCollection cfec = new ContentFilterElementCollection();


            cfec.Add(cfe);
            ContentFilter cf = new ContentFilter();

            cf.Elements = cfec;

            QueryDataSetCollection qdsc = new QueryDataSetCollection();

            byte[] cp = new byte[100];
            ParsingResultCollection  prc = new ParsingResultCollection();
            DiagnosticInfoCollection dic = new DiagnosticInfoCollection();
            ContentFilterResult      cfr = new ContentFilterResult();

            try
            {
                var rs = session.QueryFirst(null, vd, nt, cf, 1000, 1000, out qdsc, out cp, out prc, out dic, out cfr);
            }
            catch (Exception eX)
            {
                Console.WriteLine("EXCEPTION:  QueryFirst  :  {0}", eX.Message);
            }
        }
        /// <summary>
        /// Returns the subscription filter to use.
        /// </summary>
        public EventFilter GetFilter()
        {
            ContentFilter        whereClause = new ContentFilter();
            ContentFilterElement element1    = whereClause.Push(FilterOperator.OfType, EventTypeId);

            EventFilter filter = new EventFilter();

            for (int ii = 0; ii < Fields.Count; ii++)
            {
                filter.SelectClauses.Add(Fields[ii].Operand);

                if (Fields[ii].FilterValue != Variant.Null)
                {
                    LiteralOperand operand = new LiteralOperand();
                    operand.Value = Fields[ii].FilterValue;
                    ContentFilterElement element2 = whereClause.Push(Fields[ii].FilterOperator, Fields[ii].Operand, operand);
                    element1 = whereClause.Push(FilterOperator.And, element1, element2);
                }
            }

            filter.WhereClause = whereClause;

            return(filter);
        }
Beispiel #15
0
        private void SelectNodeMI_Click(object sender, EventArgs e)
        {
            try
            {
                ReferenceDescription reference = new SelectNodeDlg().ShowDialog(m_browser, ObjectTypes.BaseEventType);

                if (reference != null)
                {
                    Node node = m_session.NodeCache.Find(reference.NodeId) as Node;

                    if (node == null)
                    {
                        return;
                    }

                    ContentFilterElement element = null;

                    // build the relative path.
                    QualifiedNameCollection browsePath = new QualifiedNameCollection();
                    NodeId typeId = m_session.NodeCache.BuildBrowsePath(node, browsePath);

                    switch (node.NodeClass)
                    {
                    case NodeClass.Variable:
                    {
                        IVariable variable = node as IVariable;

                        if (variable == null)
                        {
                            break;
                        }

                        // create attribute operand.
                        SimpleAttributeOperand attribute = new SimpleAttributeOperand(
                            m_session.FilterContext,
                            typeId,
                            browsePath);

                        // create default value.
                        object value = GuiUtils.GetDefaultValue(variable.DataType, variable.ValueRank);

                        // create attribute filter.
                        element = m_filter.Push(FilterOperator.Equals, attribute, value);
                        break;
                    }

                    case NodeClass.Object:
                    {
                        // create attribute operand.
                        SimpleAttributeOperand attribute = new SimpleAttributeOperand(
                            m_session.FilterContext,
                            typeId,
                            browsePath);

                        attribute.AttributeId = Attributes.NodeId;

                        // create attribute filter.
                        element = m_filter.Push(FilterOperator.IsNull, attribute);
                        break;
                    }

                    case NodeClass.ObjectType:
                    {
                        element = m_filter.Push(FilterOperator.OfType, node.NodeId);
                        break;
                    }

                    default:
                    {
                        throw new ArgumentException("Selected an invalid node.");
                    }
                    }

                    // add element.
                    if (element != null)
                    {
                        AddItem(element);
                        AdjustColumns();
                    }
                }
            }
            catch (Exception exception)
            {
                GuiUtils.HandleException(this.Text, MethodBase.GetCurrentMethod(), exception);
            }
        }
        /// <summary>
        /// Returns the where clause defined by the filter declaration.
        /// </summary>
        private ContentFilter GetWhereClause()
        {
            ContentFilter whereClause = new ContentFilter();

            ContentFilterElement element1 = null;

            // filter by source.
            if (SelectedSources != null && SelectedSources.Count > 0)
            {
                SimpleAttributeOperand operand1 = new SimpleAttributeOperand();
                operand1.TypeDefinitionId = Opc.Ua.ObjectTypeIds.BaseEventType;
                operand1.AttributeId      = Attributes.Value;
                operand1.BrowsePath.Add(new QualifiedName(Opc.Ua.BrowseNames.SourceNode));

                for (int ii = 0; ii < SelectedSources.Count; ii++)
                {
                    LiteralOperand operand2 = new LiteralOperand();
                    operand2.Value = SelectedSources[ii];
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.Equals, operand1, operand2);
                    element1 = (element1 != null)?whereClause.Push(FilterOperator.Or, element1, element2):element2;
                }
            }

            // add condition/tracking categories if no other categories selected.
            if (RevisedCategories == null || RevisedCategories.Count == 0)
            {
                if (EventTypes == (OpcRcw.Ae.Constants.SIMPLE_EVENT | OpcRcw.Ae.Constants.TRACKING_EVENT))
                {
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.ConditionType);
                    ContentFilterElement element3 = whereClause.Push(FilterOperator.Not, element2);

                    element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element3) : element3;
                }

                else if (EventTypes == (OpcRcw.Ae.Constants.SIMPLE_EVENT | OpcRcw.Ae.Constants.CONDITION_EVENT))
                {
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.AuditEventType);
                    ContentFilterElement element3 = whereClause.Push(FilterOperator.Not, element2);
                    ContentFilterElement element4 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.TransitionEventType);
                    ContentFilterElement element5 = whereClause.Push(FilterOperator.Not, element4);
                    ContentFilterElement element6 = whereClause.Push(FilterOperator.Or, element3, element5);

                    element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element6) : element6;
                }

                else if (EventTypes == (OpcRcw.Ae.Constants.TRACKING_EVENT | OpcRcw.Ae.Constants.CONDITION_EVENT))
                {
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.AuditEventType);
                    ContentFilterElement element3 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.TransitionEventType);
                    ContentFilterElement element4 = whereClause.Push(FilterOperator.Or, element2, element3);
                    ContentFilterElement element5 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.ConditionType);
                    ContentFilterElement element6 = whereClause.Push(FilterOperator.Or, element4, element5);

                    element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element6) : element6;
                }

                else if (EventTypes == OpcRcw.Ae.Constants.TRACKING_EVENT)
                {
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.AuditEventType);
                    ContentFilterElement element3 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.TransitionEventType);
                    ContentFilterElement element4 = whereClause.Push(FilterOperator.Or, element2, element3);

                    element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element4) : element4;
                }

                else if (EventTypes == OpcRcw.Ae.Constants.CONDITION_EVENT)
                {
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.ConditionType);

                    element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element2) : element2;
                }

                else if (EventTypes == OpcRcw.Ae.Constants.SIMPLE_EVENT)
                {
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.AuditEventType);
                    ContentFilterElement element3 = whereClause.Push(FilterOperator.Not, element2);
                    ContentFilterElement element4 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.TransitionEventType);
                    ContentFilterElement element5 = whereClause.Push(FilterOperator.Not, element4);
                    ContentFilterElement element6 = whereClause.Push(FilterOperator.Or, element3, element5);
                    ContentFilterElement element7 = whereClause.Push(FilterOperator.OfType, Opc.Ua.ObjectTypeIds.ConditionType);
                    ContentFilterElement element8 = whereClause.Push(FilterOperator.Not, element7);

                    element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element8) : element8;
                }
            }

            // filter by event type.
            if (RevisedCategories.Count > 0)
            {
                SimpleAttributeOperand operand1 = new SimpleAttributeOperand();
                operand1.TypeDefinitionId = Opc.Ua.ObjectTypeIds.BaseEventType;
                operand1.AttributeId      = Attributes.Value;
                operand1.BrowsePath.Add(new QualifiedName(Opc.Ua.BrowseNames.EventType));

                ContentFilterElement element3 = null;

                for (int ii = 0; ii < RevisedCategories.Count; ii++)
                {
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.Equals, operand1, RevisedCategories[ii].TypeId);
                    element3 = (element3 != null) ? whereClause.Push(FilterOperator.Or, element2, element3) : element2;
                }

                element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element3) : element3;
            }

            // filter by severity.
            if (LowSeverity > 1 || HighSeverity < 1000)
            {
                SimpleAttributeOperand operand1 = new SimpleAttributeOperand();
                operand1.TypeDefinitionId = Opc.Ua.ObjectTypeIds.BaseEventType;
                operand1.AttributeId      = Attributes.Value;
                operand1.BrowsePath.Add(new QualifiedName(Opc.Ua.BrowseNames.Severity));

                if (LowSeverity > 1)
                {
                    LiteralOperand operand2 = new LiteralOperand();
                    operand2.Value = LowSeverity;
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.GreaterThanOrEqual, operand1, operand2);
                    element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element2) : element2;
                }

                if (HighSeverity < 1000)
                {
                    LiteralOperand operand2 = new LiteralOperand();
                    operand2.Value = HighSeverity;
                    ContentFilterElement element2 = whereClause.Push(FilterOperator.LessThanOrEqual, operand1, operand2);
                    element1 = (element1 != null) ? whereClause.Push(FilterOperator.And, element1, element2) : element2;
                }
            }

            return(whereClause);
        }
Beispiel #17
0
        /// <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 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);
        }
Beispiel #18
0
        /// <summary>
        /// Monitoring for an event source starts if it is required.
        /// </summary>
        public async Task MonitorEventsAsync(CancellationToken ct)
        {
            bool sessionLocked = false;

            try
            {
                try
                {
                    sessionLocked = await LockSessionAsync().ConfigureAwait(false);

                    // if the session is not connected or shutdown in progress, return
                    if (!sessionLocked || ct.IsCancellationRequested || State != SessionState.Connected)
                    {
                        return;
                    }
                }
                catch (Exception)
                {
                    throw;
                }

                // ensure all nodes in all subscriptions of this session are monitored.
                foreach (var opcEventSubscription in OpcEventSubscriptions)
                {
                    // create the subscription, if it is not yet there.
                    if (opcEventSubscription.OpcUaClientSubscription == null)
                    {
                        opcEventSubscription.OpcUaClientSubscription = CreateSubscription(opcEventSubscription.RequestedPublishingInterval, out int revisedPublishingInterval);
                        opcEventSubscription.PublishingInterval      = revisedPublishingInterval;
                        Logger.Information($"Create Event subscription on endpoint '{EndpointUrl}' requested OPC publishing interval is {opcEventSubscription.RequestedPublishingInterval} ms. (revised: {revisedPublishingInterval} ms)");
                    }

                    // process all unmonitored events.
                    var  unmonitoredEvents = opcEventSubscription.OpcMonitoredItems.Where(i => (i.State == OpcMonitoredItemState.Unmonitored || i.State == OpcMonitoredItemState.UnmonitoredNamespaceUpdateRequested));
                    int  additionalMonitoredEventsCount = 0;
                    int  monitoredEventsCount           = 0;
                    bool haveUnmonitoredEvents          = false;
                    if (unmonitoredEvents.Count() != 0)
                    {
                        haveUnmonitoredEvents = true;
                        monitoredEventsCount  = opcEventSubscription.OpcMonitoredItems.Count(i => (i.State == OpcMonitoredItemState.Monitored));
                        Logger.Information($"Start monitoring events on endpoint '{EndpointUrl}'. Currently monitoring {monitoredEventsCount} events.");
                    }

                    // init perf data
                    Stopwatch stopWatch = new Stopwatch();
                    stopWatch.Start();
                    foreach (var unmonitoredEvent in unmonitoredEvents)
                    {
                        // if the session is not connected or a shutdown is in progress, we stop trying and wait for the next cycle
                        if (ct.IsCancellationRequested || State != SessionState.Connected)
                        {
                            break;
                        }

                        NodeId currentNodeId = null;
                        try
                        {
                            // update the namespace of the node if requested. there are two cases where this is requested:
                            // 1) publishing requests via the OPC server method are raised using a NodeId format. for those
                            //    the NodeId format is converted into an ExpandedNodeId format
                            // 2) ExpandedNodeId configuration file entries do not have at parsing time a session to get
                            //    the namespace index. this is set now.
                            if (unmonitoredEvent.State == OpcMonitoredItemState.UnmonitoredNamespaceUpdateRequested)
                            {
                                if (unmonitoredEvent.ConfigType == OpcMonitoredItemConfigurationType.ExpandedNodeId)
                                {
                                    ExpandedNodeId expandedNodeId = ExpandedNodeId.Parse(unmonitoredEvent.Id);
                                    int            namespaceIndex = _namespaceTable.GetIndex(expandedNodeId.NamespaceUri);
                                    if (namespaceIndex < 0)
                                    {
                                        Logger.Information($"The namespace URI of node '{expandedNodeId.ToString()}' can be not mapped to a namespace index.");
                                    }
                                    else
                                    {
                                        unmonitoredEvent.IdAsExpandedNodeId = expandedNodeId;
                                    }
                                }
                                if (unmonitoredEvent.ConfigType == OpcMonitoredItemConfigurationType.NodeId)
                                {
                                    NodeId nodeId       = NodeId.Parse(unmonitoredEvent.Id);
                                    string namespaceUri = _namespaceTable.ToArray().ElementAtOrDefault(nodeId.NamespaceIndex);
                                    if (string.IsNullOrEmpty(namespaceUri))
                                    {
                                        Logger.Information($"The namespace index of node '{nodeId.ToString()}' is invalid and the node format can not be updated.");
                                    }
                                    else
                                    {
                                        unmonitoredEvent.IdAsExpandedNodeId = new ExpandedNodeId(nodeId.Identifier, nodeId.NamespaceIndex, namespaceUri, 0);
                                        unmonitoredEvent.ConfigType         = OpcMonitoredItemConfigurationType.ExpandedNodeId;
                                    }
                                }
                                unmonitoredEvent.State = OpcMonitoredItemState.Unmonitored;
                            }

                            // lookup namespace index if ExpandedNodeId format has been used and build NodeId identifier.
                            if (unmonitoredEvent.ConfigType == OpcMonitoredItemConfigurationType.ExpandedNodeId)
                            {
                                ExpandedNodeId expandedNodeId = ExpandedNodeId.Parse(unmonitoredEvent.Id);
                                int            namespaceIndex = _namespaceTable.GetIndex(expandedNodeId.NamespaceUri);
                                if (namespaceIndex < 0)
                                {
                                    Logger.Warning($"Syntax or namespace URI of ExpandedNodeId '{expandedNodeId.ToString()}' is invalid and will be ignored.");
                                    continue;
                                }
                                unmonitoredEvent.IdAsNodeId = new NodeId(expandedNodeId.Identifier, expandedNodeId.NamespaceIndex);
                                currentNodeId = unmonitoredEvent.IdAsNodeId;
                            }
                            else
                            {
                                NodeId nodeId       = NodeId.Parse(unmonitoredEvent.Id);
                                string namespaceUri = _namespaceTable.ToArray().ElementAtOrDefault(nodeId.NamespaceIndex);
                                if (string.IsNullOrEmpty(namespaceUri))
                                {
                                    Logger.Information($"The namespace index of node '{nodeId.ToString()}' is invalid and the node format can not be updated.");
                                }
                                else
                                {
                                    unmonitoredEvent.IdAsExpandedNodeId = new ExpandedNodeId(nodeId.Identifier, nodeId.NamespaceIndex, namespaceUri, 0);
                                    currentNodeId = nodeId;
                                }
                            }

                            // if configured, get the key for the node, otherwise use the nodeId
                            Node node;
                            if (string.IsNullOrEmpty(unmonitoredEvent.Key))
                            {
                                if (FetchOpcNodeDisplayName == true)
                                {
                                    node = OpcUaClientSession.ReadNode(currentNodeId);
                                    unmonitoredEvent.Key = node.DisplayName.Text ?? currentNodeId.ToString();
                                }
                                else
                                {
                                    unmonitoredEvent.Key = currentNodeId.ToString();
                                }
                            }

                            // resolve all node and namespace references in the select and where clauses
                            EventFilter eventFilter = new EventFilter();
                            foreach (var selectClause in unmonitoredEvent.EventConfiguration.SelectClauses)
                            {
                                SimpleAttributeOperand simpleAttributeOperand = new SimpleAttributeOperand();
                                simpleAttributeOperand.AttributeId = selectClause.AttributeId.ResolveAttributeId();
                                simpleAttributeOperand.IndexRange  = selectClause.IndexRange;
                                NodeId typeId = selectClause.TypeId.ToNodeId(_namespaceTable);
                                simpleAttributeOperand.TypeDefinitionId = new NodeId(typeId);
                                QualifiedNameCollection browsePaths = new QualifiedNameCollection();
                                foreach (var browsePath in selectClause.BrowsePaths)
                                {
                                    browsePaths.Add(QualifiedName.Parse(browsePath));
                                }
                                simpleAttributeOperand.BrowsePath = browsePaths;
                                eventFilter.SelectClauses.Add(simpleAttributeOperand);
                            }
                            foreach (var whereClauseElement in unmonitoredEvent.EventConfiguration.WhereClause)
                            {
                                ContentFilterElement contentFilterElement = new ContentFilterElement();
                                contentFilterElement.FilterOperator = whereClauseElement.Operator.ResolveFilterOperator();
                                switch (contentFilterElement.FilterOperator)
                                {
                                case FilterOperator.OfType:
                                case FilterOperator.InView:
                                    if (whereClauseElement.Operands.Count != 1)
                                    {
                                        Logger.Error($"The where clause element '{whereClauseElement.ToString()}' must contain 1 operands.");
                                        continue;
                                    }
                                    FilterOperand[] filterOperands = new FilterOperand[1];
                                    TypeInfo        typeInfo       = new TypeInfo(BuiltInType.NodeId, ValueRanks.Scalar);
                                    filterOperands[0] = whereClauseElement.Operands[0].GetOperand(typeInfo);
                                    eventFilter.WhereClause.Push(contentFilterElement.FilterOperator, filterOperands);
                                    break;

                                case FilterOperator.Equals:
                                case FilterOperator.IsNull:
                                case FilterOperator.GreaterThan:
                                case FilterOperator.LessThan:
                                case FilterOperator.GreaterThanOrEqual:
                                case FilterOperator.LessThanOrEqual:
                                case FilterOperator.Like:
                                case FilterOperator.Not:
                                case FilterOperator.Between:
                                case FilterOperator.InList:
                                case FilterOperator.And:
                                case FilterOperator.Or:
                                case FilterOperator.Cast:
                                case FilterOperator.BitwiseAnd:
                                case FilterOperator.BitwiseOr:
                                case FilterOperator.RelatedTo:
                                default:
                                    Logger.Error($"The operator '{contentFilterElement.FilterOperator.ToString()}' is not supported.");
                                    break;
                                }
                            }

                            // add the new monitored event.
                            IOpcUaMonitoredItem monitoredItem = new OpcUaMonitoredItem()
                            {
                                StartNodeId      = currentNodeId,
                                AttributeId      = Attributes.EventNotifier,
                                DisplayName      = unmonitoredEvent.Key,
                                MonitoringMode   = unmonitoredEvent.MonitoringMode,
                                SamplingInterval = 0,
                                QueueSize        = unmonitoredEvent.QueueSize,
                                DiscardOldest    = unmonitoredEvent.DiscardOldest,
                                Filter           = eventFilter
                            };

                            monitoredItem.Notification += unmonitoredEvent.NotificationEventHandler;
                            opcEventSubscription.OpcUaClientSubscription.AddItem(monitoredItem);
                            unmonitoredEvent.OpcUaClientMonitoredItem = monitoredItem;
                            unmonitoredEvent.State       = OpcMonitoredItemState.Monitored;
                            unmonitoredEvent.EndpointUrl = EndpointUrl;
                            Logger.Verbose($"Created monitored event for node '{currentNodeId.ToString()}' in subscription with id '{opcEventSubscription.OpcUaClientSubscription.Id}' on endpoint '{EndpointUrl}' (version: {NodeConfigVersion:X8})");
                            if (unmonitoredEvent.RequestedSamplingInterval != monitoredItem.SamplingInterval)
                            {
                                Logger.Information($"Sampling interval: requested: {unmonitoredEvent.RequestedSamplingInterval}; revised: {monitoredItem.SamplingInterval}");
                                unmonitoredEvent.SamplingInterval = monitoredItem.SamplingInterval;
                            }
                            if (additionalMonitoredEventsCount % 10000 == 0)
                            {
                                Logger.Information($"Now monitoring {monitoredEventsCount + additionalMonitoredEventsCount} events in subscription with id '{opcEventSubscription.OpcUaClientSubscription.Id}'");
                            }
                        }
                        catch (Exception e) when(e.GetType() == typeof(ServiceResultException))
                        {
                            ServiceResultException sre = (ServiceResultException)e;

                            switch ((uint)sre.Result.StatusCode)
                            {
                            case StatusCodes.BadSessionIdInvalid:
                            {
                                Logger.Information($"Session with Id {OpcUaClientSession.SessionId} is no longer available on endpoint '{EndpointUrl}'. Cleaning up.");
                                // clean up the session
                                InternalDisconnect();
                                break;
                            }

                            case StatusCodes.BadNodeIdInvalid:
                            case StatusCodes.BadNodeIdUnknown:
                            {
                                Logger.Error($"Failed to monitor node '{currentNodeId}' on endpoint '{EndpointUrl}'.");
                                Logger.Error($"OPC UA ServiceResultException is '{sre.Result}'. Please check your publisher configuration for this node.");
                                break;
                            }

                            default:
                            {
                                Logger.Error($"Unhandled OPC UA ServiceResultException '{sre.Result}' when monitoring node '{currentNodeId}' on endpoint '{EndpointUrl}'. Continue.");
                                break;
                            }
                            }
                        }
                        catch (Exception e)
                        {
                            Logger.Error(e, $"Failed to monitor node '{currentNodeId}' on endpoint '{EndpointUrl}'");
                        }
                    }
                    opcEventSubscription.OpcUaClientSubscription.SetPublishingMode(true);
                    opcEventSubscription.OpcUaClientSubscription.ApplyChanges();
                    stopWatch.Stop();
                    if (haveUnmonitoredEvents == true)
                    {
                        monitoredEventsCount = opcEventSubscription.OpcMonitoredItems.Count(i => (i.State == OpcMonitoredItemState.Monitored));
                        Logger.Information($"Done processing unmonitored events on endpoint '{EndpointUrl}' took {stopWatch.ElapsedMilliseconds} msec. Now monitoring {monitoredEventsCount} events in subscription with id '{opcEventSubscription.OpcUaClientSubscription.Id}'.");
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Error(e, "Exception");
            }
            finally
            {
                if (sessionLocked)
                {
                    ReleaseSession();
                }
            }
        }