/// <summary> /// Returns a unique handle for the node. /// </summary> protected override NodeHandle GetManagerHandle(ServerSystemContext context, NodeId nodeId, IDictionary <NodeId, NodeState> cache) { lock (Lock) { // quickly exclude nodes that are not in the namespace. if (!IsNodeIdInNamespace(nodeId)) { return(null); } // check for check for nodes that are being currently monitored. MonitoredNode monitoredNode = null; if (MonitoredNodes.TryGetValue(nodeId, out monitoredNode)) { NodeHandle handle = new NodeHandle(); handle.NodeId = nodeId; handle.Validated = true; handle.Node = monitoredNode.Node; return(handle); } if (nodeId.IdType != IdType.String) { NodeState node = null; if (PredefinedNodes.TryGetValue(nodeId, out node)) { NodeHandle handle = new NodeHandle(); handle.NodeId = nodeId; handle.Node = node; handle.Validated = true; return(handle); } } // parse the identifier. ParsedNodeId parsedNodeId = ParsedNodeId.Parse(nodeId); if (parsedNodeId != null) { NodeHandle handle = new NodeHandle(); handle.NodeId = nodeId; handle.Validated = false; handle.Node = null; handle.ParsedNodeId = parsedNodeId; return(handle); } return(null); } }
/// <summary> /// Tells the node manager to refresh any conditions associated with the specified monitored items. /// </summary> /// <remarks> /// This method is called when the condition refresh method is called for a subscription. /// The node manager must create a refresh event for each condition monitored by the subscription. /// </remarks> public override ServiceResult ConditionRefresh( OperationContext context, IList <IEventMonitoredItem> monitoredItems) { ServerSystemContext serverSystemContext = SystemContext.Copy(context); foreach (MonitoredItem monitoredItem in monitoredItems) { if (monitoredItem == null) { continue; } List <IFilterTarget> events = new List <IFilterTarget>(); List <NodeState> nodesToRefresh = new List <NodeState>(); lock (Lock) { // check for server subscription. if (monitoredItem.NodeId == ObjectIds.Server) { if (_rootNotifiers != null) { nodesToRefresh.AddRange(_rootNotifiers); } } else { if (!MonitoredNodes.TryGetValue(monitoredItem.NodeId, out MonitoredNode2 monitoredNode)) { continue; } // get the refresh events. nodesToRefresh.Add(monitoredNode.Node); } } foreach (var node in nodesToRefresh) { node.ConditionRefresh(SystemContext, events, true); } foreach (var @event in events) { monitoredItem.QueueEvent(@event); } } return(ServiceResult.Good); }
/// <summary> /// Returns a unique handle for the node. /// </summary> protected override NodeHandle GetManagerHandle(ServerSystemContext context, NodeId nodeId, IDictionary <NodeId, NodeState> cache) { lock (Lock) { // quickly exclude nodes that are not in the namespace. if (!IsNodeIdInNamespace(nodeId)) { return(null); } // check for check for nodes that are being currently monitored. if (MonitoredNodes.TryGetValue(nodeId, out var monitoredNode)) { var handle = new NodeHandle { NodeId = nodeId, Validated = true, Node = monitoredNode.Node }; return(handle); } // parse the identifier. var parsedNodeId = ParsedNodeId.Parse(nodeId); if (parsedNodeId != null) { var handle = new NodeHandle { NodeId = nodeId, Validated = false, Node = null, ParsedNodeId = parsedNodeId }; return(handle); } return(null); } }
/// <summary> /// Creates a new set of monitored items for a set of variables. /// </summary> /// <remarks> /// This method only handles data change subscriptions. Event subscriptions are created by the SDK. /// </remarks> protected override ServiceResult CreateMonitoredItem(ServerSystemContext context, NodeHandle handle, uint subscriptionId, double publishingInterval, DiagnosticsMasks diagnosticsMasks, TimestampsToReturn timestampsToReturn, MonitoredItemCreateRequest itemToCreate, ref long globalIdCounter, out MonitoringFilterResult filterResult, out IMonitoredItem monitoredItem) { filterResult = null; monitoredItem = null; // validate parameters. MonitoringParameters parameters = itemToCreate.RequestedParameters; // validate attribute. if (!Attributes.IsValid(handle.Node.NodeClass, itemToCreate.ItemToMonitor.AttributeId)) { return(StatusCodes.BadAttributeIdInvalid); } NodeState cachedNode = AddNodeToComponentCache(context, handle, handle.Node); // check if the node is already being monitored. MonitoredNode2 monitoredNode = null; if (!MonitoredNodes.TryGetValue(handle.Node.NodeId, out monitoredNode)) { MonitoredNodes[handle.Node.NodeId] = monitoredNode = new MonitoredNode2(this, cachedNode); } handle.Node = monitoredNode.Node; handle.MonitoredNode = monitoredNode; // create a globally unique identifier. uint monitoredItemId = Utils.IncrementIdentifier(ref globalIdCounter); // determine the sampling interval. double samplingInterval = itemToCreate.RequestedParameters.SamplingInterval; if (samplingInterval < 0) { samplingInterval = publishingInterval; } // ensure minimum sampling interval is not exceeded. if (itemToCreate.ItemToMonitor.AttributeId == Attributes.Value) { BaseVariableState variable = handle.Node as BaseVariableState; if (variable != null && samplingInterval < variable.MinimumSamplingInterval) { samplingInterval = variable.MinimumSamplingInterval; } } // put a large upper limit on sampling. if (samplingInterval == Double.MaxValue) { samplingInterval = 365 * 24 * 3600 * 1000.0; } // put an upper limit on queue size. uint queueSize = itemToCreate.RequestedParameters.QueueSize; if (queueSize > MaxQueueSize) { queueSize = MaxQueueSize; } // validate the monitoring filter. Range euRange = null; MonitoringFilter filterToUse = null; ServiceResult error = ValidateMonitoringFilter( context, handle, itemToCreate.ItemToMonitor.AttributeId, samplingInterval, queueSize, parameters.Filter, out filterToUse, out euRange, out filterResult); if (ServiceResult.IsBad(error)) { return(error); } // create the item. MonitoredItem datachangeItem = new ComMonitoredItem( Server, this, handle, subscriptionId, monitoredItemId, context.OperationContext.Session, itemToCreate.ItemToMonitor, diagnosticsMasks, timestampsToReturn, itemToCreate.MonitoringMode, itemToCreate.RequestedParameters.ClientHandle, filterToUse, filterToUse, euRange, samplingInterval, queueSize, itemToCreate.RequestedParameters.DiscardOldest, 0); // report the initial value. ReadInitialValue(context, handle, datachangeItem); // update monitored item list. monitoredItem = datachangeItem; // save the monitored item. MonitoredItems.Add(monitoredItemId, datachangeItem); monitoredNode.Add(datachangeItem); // report change. OnMonitoredItemCreated(context, handle, datachangeItem); return(error); }
/// <summary> /// Returns a unique handle for the node. /// </summary> protected override NodeHandle GetManagerHandle(ServerSystemContext context, NodeId nodeId, IDictionary <NodeId, NodeState> cache) { lock (Lock) { // quickly exclude nodes that are not in the namespace. if (!IsNodeIdInNamespace(nodeId)) { return(null); } // check cache. if (cache != null) { NodeState node = null; if (cache.TryGetValue(nodeId, out node)) { return(new NodeHandle(nodeId, node)); } } NodeHandle handle = null; try { // check if node already being monitored. if (MonitoredNodes != null) { MonitoredNode2 monitoredNode2 = null; if (MonitoredNodes.TryGetValue(nodeId, out monitoredNode2)) { handle = new NodeHandle(nodeId, monitoredNode2.Node); handle.MonitoredNode = monitoredNode2; return(handle); } } // check for predefined nodes. if (PredefinedNodes != null) { NodeState node = null; if (PredefinedNodes.TryGetValue(nodeId, out node)) { return(handle = new NodeHandle(nodeId, node)); } } // parse the identifier. AeParsedNodeId parsedNodeId = AeParsedNodeId.Parse(nodeId); if (parsedNodeId != null) { if (parsedNodeId.RootType == AeModelUtils.AeEventTypeMapping && m_typeCache != null) { AeEventTypeMappingState mappingNode = m_typeCache.GetMappingNode(SystemContext, nodeId); if (mappingNode != null) { return(handle = new NodeHandle(nodeId, mappingNode)); } return(null); } handle = new NodeHandle(); handle.NodeId = nodeId; handle.Validated = false; handle.Node = null; handle.ParsedNodeId = parsedNodeId; return(handle); } } finally { if (handle != null && handle.Node != null && cache != null) { cache.Add(nodeId, handle.Node); } } return(null); } }
/// <summary> /// Override ConditionRefresh. /// </summary> public override ServiceResult ConditionRefresh( OperationContext context, IList <IEventMonitoredItem> monitoredItems) { ServerSystemContext systemContext = SystemContext.Copy(context); for (int ii = 0; ii < monitoredItems.Count; ii++) { // the IEventMonitoredItem should always be MonitoredItems since they are created by the MasterNodeManager. MonitoredItem monitoredItem = monitoredItems[ii] as MonitoredItem; if (monitoredItem == null) { continue; } List <IFilterTarget> events = new List <IFilterTarget>(); List <NodeState> nodesToRefresh = new List <NodeState>(); lock (Lock) { // check for server subscription. if (monitoredItem.NodeId == ObjectIds.Server) { if (RootNotifiers != null) { nodesToRefresh.AddRange(RootNotifiers); } } else { // check for existing monitored node. MonitoredNode2 monitoredNode = null; if (!MonitoredNodes.TryGetValue(monitoredItem.NodeId, out monitoredNode)) { continue; } // get the refresh events. nodesToRefresh.Add(monitoredNode.Node); } } // block and wait for the refresh. for (int jj = 0; jj < nodesToRefresh.Count; jj++) { nodesToRefresh[jj].ConditionRefresh(systemContext, events, true); } lock (Lock) { // This is where I can add branch events GetBranchesForConditionRefresh(events); } // queue the events. for (int jj = 0; jj < events.Count; jj++) { monitoredItem.QueueEvent(events[jj]); } } // all done. return(ServiceResult.Good); }
/// <summary> /// Subscribes to events. /// </summary> /// <param name="context">The context.</param> /// <param name="source">The source.</param> /// <param name="monitoredItem">The monitored item.</param> /// <param name="unsubscribe">if set to <c>true</c> [unsubscribe].</param> /// <returns>Any error code.</returns> protected override ServiceResult SubscribeToEvents( ServerSystemContext context, NodeState source, IEventMonitoredItem monitoredItem, bool unsubscribe) { // handle unsubscribe. if (unsubscribe) { // check for existing monitored node. if (!MonitoredNodes.TryGetValue(source.NodeId, out MonitoredNode2 monitoredNode2)) { return(StatusCodes.BadNodeIdUnknown); } monitoredNode2.Remove(monitoredItem); // check if node is no longer being monitored. if (!monitoredNode2.HasMonitoredItems) { MonitoredNodes.Remove(source.NodeId); } // update flag. source.SetAreEventsMonitored(context, !unsubscribe, true); // call subclass. OnSubscribeToEvents(context, monitoredNode2, unsubscribe); // all done. return(ServiceResult.Good); } // only objects or views can be subscribed to. BaseObjectState instance = source as BaseObjectState; if (instance == null || (instance.EventNotifier & EventNotifiers.SubscribeToEvents) == 0) { ViewState view = source as ViewState; if (view == null || (view.EventNotifier & EventNotifiers.SubscribeToEvents) == 0) { return(StatusCodes.BadNotSupported); } } // check for existing monitored node. if (!MonitoredNodes.TryGetValue(source.NodeId, out MonitoredNode2 monitoredNode)) { MonitoredNodes[source.NodeId] = monitoredNode = new MonitoredNode2(this, source); } // this links the node to specified monitored item and ensures all events // reported by the node are added to the monitored item's queue. monitoredNode.Add(monitoredItem); // This call recursively updates a reference count all nodes in the notifier // hierarchy below the area. Sources with a reference count of 0 do not have // any active subscriptions so they do not need to report events. source.SetAreEventsMonitored(context, !unsubscribe, true); // signal update. OnSubscribeToEvents(context, monitoredNode, unsubscribe); // all done. return(ServiceResult.Good); }