/// <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> /// Subscribes or unsubscribes to events produced by all event sources. /// </summary> /// <remarks> /// This method is called when a event subscription is created or deleted. The node /// manager must start/stop reporting events for all objects that it manages. /// </remarks> public override ServiceResult SubscribeToAllEvents( Opc.Ua.Server.OperationContext context, uint subscriptionId, IEventMonitoredItem monitoredItem, bool unsubscribe) { ServerSystemContext serverSystemContext = SystemContext.Copy(context); lock (Lock) { // A client has subscribed to the Server object which means all events produced // by this manager must be reported. This is done by incrementing the monitoring // reference count for all root notifiers. if (_rootNotifiers != null) { for (int ii = 0; ii < _rootNotifiers.Count; ii++) { SubscribeToEvents(serverSystemContext, _rootNotifiers[ii], monitoredItem, unsubscribe); } } return(ServiceResult.Good); } }
/// <summary> /// Subscribes or unsubscribes to events produced by all event sources. /// </summary> /// <remarks> /// This method is called when a event subscription is created or deleted. The node /// manager must start/stop reporting events for all objects that it manages. /// </remarks> public override ServiceResult SubscribeToAllEvents( OperationContext context, uint subscriptionId, IEventMonitoredItem monitoredItem, bool unsubscribe) { ServerSystemContext systemContext = SystemContext.Copy(context); ComAeClientManager system = (ComAeClientManager)this.SystemContext.SystemHandle; ComAeClient client = (ComAeClient)system.SelectClient(systemContext, false); // need to wait until the cache is refreshed for the first time. if (!WaitForTypeCache()) { return(StatusCodes.BadOutOfService); } lock (Lock) { SubscriptionIndex index = new SubscriptionIndex(); index.NodeId = Opc.Ua.ObjectIds.Server; index.LocaleId = client.LocaleId; if (unsubscribe) { ComAeSubscriptionClient subscription = null; if (!m_monitoredItems.TryGetValue(monitoredItem.Id, out subscription)) { return(ServiceResult.Good); } m_monitoredItems.Remove(monitoredItem.Id); // Utils.Trace("REMOVED ITEM {0}", monitoredItem.Id); if (subscription.RemoveItem(monitoredItem as MonitoredItem) == 0) { subscription.Delete(); m_subscriptions.Remove(index); // Utils.Trace("DELETED SUBSCRIPTION {0}", index.NodeId); } } else { ComAeSubscriptionClient subscription = null; if (!m_subscriptions.TryGetValue(index, out subscription)) { subscription = new ComAeSubscriptionClient(systemContext, m_configuration, m_typeCache, NamespaceIndex, system, monitoredItem as MonitoredItem); m_subscriptions.Add(index, subscription); subscription.Create(); // Utils.Trace("ADDED NEW SUBSCRIPTION {0}", index.NodeId); } else { subscription.AddItem(monitoredItem as MonitoredItem); } m_monitoredItems[monitoredItem.Id] = subscription; // Utils.Trace("ADDED NEW ITEM {0}", monitoredItem.Id); } } return(ServiceResult.Good); }
/// <summary> /// Writes the value for the specified attributes. /// </summary> public override void Write( OperationContext context, IList <WriteValue> nodesToWrite, IList <ServiceResult> errors) { ServerSystemContext systemContext = SystemContext.Copy(context); IDictionary <NodeId, NodeState> operationCache = new NodeIdDictionary <NodeState>(); List <DataSourceClient.WriteRequest> writeRequests = new List <DataSourceClient.WriteRequest>(); lock (Lock) { for (int ii = 0; ii < nodesToWrite.Count; ii++) { WriteValue nodeToWrite = nodesToWrite[ii]; // skip items that have already been processed. if (nodeToWrite.Processed) { continue; } // check for valid handle. NodeHandle handle = GetManagerHandle(systemContext, nodeToWrite.NodeId, operationCache); if (handle == null) { continue; } // owned by this node manager. nodeToWrite.Processed = true; // index range is not supported. if (nodeToWrite.AttributeId != Attributes.Value) { if (!String.IsNullOrEmpty(nodeToWrite.IndexRange)) { errors[ii] = StatusCodes.BadWriteNotSupported; continue; } } // check if the node is a area in memory. if (handle.Node == null) { errors[ii] = StatusCodes.BadNodeIdUnknown; continue; } // check if the request if for a remote node. RemoteNode remoteNode = null; if (m_remoteNodes.TryGetValue(handle.NodeId, out remoteNode)) { // check for theorectical access. BaseVariableState variable = handle.Node as BaseVariableState; if (variable == null || nodeToWrite.AttributeId != Attributes.Value || (variable.AccessLevel & AccessLevels.CurrentWrite) == 0) { errors[ii] = StatusCodes.BadNotWritable; continue; } // check for access based on current user credentials. if (!CheckWriteAccess(systemContext, remoteNode)) { errors[ii] = StatusCodes.BadUserAccessDenied; continue; } DataSourceClient.WriteRequest request = new DataSourceClient.WriteRequest(); request.RemoteId = remoteNode.RemoteId; request.WriteValue = nodeToWrite; request.Index = ii; writeRequests.Add(request); errors[ii] = StatusCodes.BadNoCommunication; continue; } // write the attribute value. errors[ii] = handle.Node.WriteAttribute( systemContext, nodeToWrite.AttributeId, nodeToWrite.ParsedIndexRange, nodeToWrite.Value); // updates to source finished - report changes to monitored items. handle.Node.ClearChangeMasks(systemContext, false); } // check for nothing to do. if (writeRequests.Count == 0) { return; } } // update the remote data source. List <ServiceResult> results = m_source.Write(writeRequests); for (int ii = 0; ii < writeRequests.Count; ii++) { errors[writeRequests[ii].Index] = results[ii]; } }
/// <summary> /// Reads the value for the specified attribute. /// </summary> public override void Read( OperationContext context, double maxAge, IList <ReadValueId> nodesToRead, IList <DataValue> values, IList <ServiceResult> errors) { ServerSystemContext systemContext = SystemContext.Copy(context); IDictionary <NodeId, NodeState> operationCache = new NodeIdDictionary <NodeState>(); List <DataSourceClient.ReadRequest> readRequests = new List <DataSourceClient.ReadRequest>(); lock (Lock) { for (int ii = 0; ii < nodesToRead.Count; ii++) { ReadValueId nodeToRead = nodesToRead[ii]; // skip items that have already been processed. if (nodeToRead.Processed) { continue; } // check for valid handle. NodeHandle handle = GetManagerHandle(systemContext, nodeToRead.NodeId, operationCache); if (handle == null) { continue; } // owned by this node manager. nodeToRead.Processed = true; // create an initial value. DataValue value = values[ii] = new DataValue(); value.Value = null; value.ServerTimestamp = DateTime.UtcNow; value.SourceTimestamp = DateTime.MinValue; value.StatusCode = StatusCodes.Good; // check if the node is a area in memory. if (handle.Node == null) { errors[ii] = StatusCodes.BadNodeIdUnknown; continue; } if (nodeToRead.AttributeId == Attributes.Value) { // check if the request if for a remote node. RemoteNode remoteNode = null; if (m_remoteNodes.TryGetValue(handle.NodeId, out remoteNode)) { DataSourceClient.ReadRequest request = new DataSourceClient.ReadRequest(); request.RemoteId = remoteNode.RemoteId; request.ReadValueId = nodeToRead; request.Value = value; request.Index = ii; readRequests.Add(request); errors[ii] = StatusCodes.BadNoCommunication; continue; } } // read the attribute value. errors[ii] = handle.Node.ReadAttribute( systemContext, nodeToRead.AttributeId, nodeToRead.ParsedIndexRange, nodeToRead.DataEncoding, value); } // check for nothing to do. if (readRequests.Count == 0) { return; } } // read from the remote data source. List <ServiceResult> results = m_source.Read(readRequests); for (int ii = 0; ii < readRequests.Count; ii++) { values[readRequests[ii].Index] = readRequests[ii].Value; errors[readRequests[ii].Index] = results[ii]; } }
/// <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> /// Calls a method on the specified nodes. /// </summary> public override void Call( OperationContext context, IList <CallMethodRequest> methodsToCall, IList <CallMethodResult> results, IList <ServiceResult> errors) { ServerSystemContext systemContext = SystemContext.Copy(context); IDictionary <NodeId, NodeState> operationCache = new NodeIdDictionary <NodeState>(); bool didRefresh = false; for (int ii = 0; ii < methodsToCall.Count; ii++) { CallMethodRequest methodToCall = methodsToCall[ii]; bool refreshMethod = methodToCall.MethodId.Equals(Opc.Ua.MethodIds.ConditionType_ConditionRefresh) || methodToCall.MethodId.Equals(Opc.Ua.MethodIds.ConditionType_ConditionRefresh2); if (refreshMethod) { if (didRefresh) { errors[ii] = StatusCodes.BadRefreshInProgress; methodToCall.Processed = true; continue; } else { didRefresh = true; } } bool ackMethod = methodToCall.MethodId.Equals(Opc.Ua.MethodIds.AcknowledgeableConditionType_Acknowledge); bool confirmMethod = methodToCall.MethodId.Equals(Opc.Ua.MethodIds.AcknowledgeableConditionType_Confirm); bool commentMethod = methodToCall.MethodId.Equals(Opc.Ua.MethodIds.ConditionType_AddComment); bool ackConfirmMethod = ackMethod || confirmMethod || commentMethod; // Need to try to capture any calls to ConditionType::Acknowledge if (methodToCall.ObjectId.Equals(Opc.Ua.ObjectTypeIds.ConditionType) && (ackConfirmMethod)) { // Mantis Issue 6944 which is a duplicate of 5544 - result is Confirm should be Bad_NodeIdInvalid // Override any other errors that may be there, even if this is 'Processed' errors[ii] = StatusCodes.BadNodeIdInvalid; methodToCall.Processed = true; continue; } // skip items that have already been processed. if (methodToCall.Processed) { continue; } MethodState method = null; lock (Lock) { // check for valid handle. NodeHandle initialHandle = GetManagerHandle(systemContext, methodToCall.ObjectId, operationCache); if (initialHandle == null) { if (ackConfirmMethod) { // Mantis 6944 errors[ii] = StatusCodes.BadNodeIdUnknown; methodToCall.Processed = true; } continue; } // owned by this node manager. methodToCall.Processed = true; // Look for an alarm branchId to operate on. NodeHandle handle = FindBranchNodeHandle(systemContext, initialHandle, methodToCall); // validate the source node. NodeState source = ValidateNode(systemContext, handle, operationCache); if (source == null) { errors[ii] = StatusCodes.BadNodeIdUnknown; continue; } // find the method. method = source.FindMethod(systemContext, methodToCall.MethodId); if (method == null) { // check for loose coupling. if (source.ReferenceExists(ReferenceTypeIds.HasComponent, false, methodToCall.MethodId)) { method = (MethodState)FindPredefinedNode(methodToCall.MethodId, typeof(MethodState)); } if (method == null) { errors[ii] = StatusCodes.BadMethodInvalid; continue; } } } // call the method. CallMethodResult result = results[ii] = new CallMethodResult(); errors[ii] = Call( systemContext, methodToCall, method, result); } }