/// <summary> /// Updates the object with the results of a translate browse path request. /// </summary> public void SetResolvePathResult( BrowsePathResult result, int index, DiagnosticInfoCollection diagnosticInfos, ResponseHeader responseHeader) { ServiceResult error = null; if (StatusCode.IsBad(result.StatusCode)) { error = ClientBase.GetResult(result.StatusCode, index, diagnosticInfos, responseHeader); } else { ResolvedNodeId = NodeId.Null; // update the node id. if (result.Targets.Count > 0) { ResolvedNodeId = ExpandedNodeId.ToNodeId(result.Targets[0].TargetId, m_subscription.Session.NamespaceUris); } } m_status.SetResolvePathResult(result, error); }
public BrowsePathResult GetBrowseResultForOneNode(string nodeId) { var result = new BrowsePathResult { StatusCode = StatusCodes.Bad }; try { SysLog.Debug($"Trying to locate {nodeId}.\n"); //This call is a synchronous call (Polling). This type of call for some nodes it is too quickly var node = this._session?.ReadNode(nodeId); var target = new BrowsePathTarget { TargetId = node?.NodeId }; result.StatusCode = node?.NodeId is null ? StatusCodes.Bad : StatusCodes.Good; result.Targets.Add(target); } catch (ServiceResultException ex) { if (StatusCodes.BadNodeIdUnknown == ex.StatusCode || StatusCodes.BadNodeIdInvalid == ex.StatusCode) { //We know the nodeId does not exist because the OPC server has reported that if (SysLog.IsDebugEnabled) { SysLog.Error($"Failed to retrieve node id for item {nodeId}. "); } result.StatusCode = ex.StatusCode; } //We know the Node is not bad because the OPC Server has not report that . //We continue searching for the Node. SysLog.Debug($"Node {nodeId} was not located in a normal way.\n"); } catch (Exception ex) { SysLog.Error($"Failed to retrieve node id for item {nodeId}. ", ex); } return(result); }
/// <summary> /// Returns the target nodes found by following a browse path from a starting node. /// </summary> public TranslateBrowsePathsToNodeIdsResponseMessage TranslateBrowsePathsToNodeIds(TranslateBrowsePathsToNodeIdsMessage request) { try { lock (m_lock) { // verify that the session is still valid. VerifySession(request.RequestHeader, false); // process each path being followed. ListOfBrowsePathResult results = new ListOfBrowsePathResult(); ListOfDiagnosticInfo diagnosticInfos = new ListOfDiagnosticInfo(); for (int ii = 0; ii < request.BrowsePaths.Count; ii++) { BrowsePathResult result = new BrowsePathResult(); DiagnosticInfo diagnosticInfo = new DiagnosticInfo(); m_nodeManager.TranslateBrowsePath( request.BrowsePaths[ii], result, diagnosticInfo); results.Add(result); diagnosticInfos.Add(diagnosticInfo); } // return the response. TranslateBrowsePathsToNodeIdsResponseMessage response = new TranslateBrowsePathsToNodeIdsResponseMessage(); response.ResponseHeader = CreateResponseHeader(request.RequestHeader); response.Results = results; response.DiagnosticInfos = diagnosticInfos; return(response); } } catch (Exception e) { throw CreateSoapFault(request.RequestHeader, e); } }
/// <summary> /// Returns the target nodes found by following a browse path from a starting node. /// </summary> public TranslateBrowsePathsToNodeIdsResponseMessage TranslateBrowsePathsToNodeIds(TranslateBrowsePathsToNodeIdsMessage request) { try { lock (m_lock) { // verify that the session is still valid. VerifySession(request.RequestHeader, false); // process each path being followed. ListOfBrowsePathResult results = new ListOfBrowsePathResult(); ListOfDiagnosticInfo diagnosticInfos = new ListOfDiagnosticInfo(); for (int ii = 0; ii < request.BrowsePaths.Count; ii++) { BrowsePathResult result = new BrowsePathResult(); DiagnosticInfo diagnosticInfo = new DiagnosticInfo(); m_nodeManager.TranslateBrowsePath( request.BrowsePaths[ii], result, diagnosticInfo); results.Add(result); diagnosticInfos.Add(diagnosticInfo); } // return the response. TranslateBrowsePathsToNodeIdsResponseMessage response = new TranslateBrowsePathsToNodeIdsResponseMessage(); response.ResponseHeader = CreateResponseHeader(request.RequestHeader); response.Results = results; response.DiagnosticInfos = diagnosticInfos; return response; } } catch (Exception e) { throw CreateSoapFault(request.RequestHeader, e); } }
/// <summary> /// Updates the EUInfo for the items. /// </summary> /// <param name="group">The group.</param> /// <param name="items">The items. Null entries are ignored.</param> public void UpdateItemEuInfo( ComDaGroup group, IList <ComDaGroupItem> items) { // get the session to use for the operation. Session session = m_session; if (session == null) { throw ComUtils.CreateComException(ResultIds.E_FAIL); } // build list of properties that need to be read. BrowsePathCollection browsePaths = new BrowsePathCollection(); for (int ii = 0; ii < items.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)items[ii]; // ignore invalid items or items which have already checked their EU type. if (item == null || item.EuType >= 0) { continue; } BrowsePath browsePath = new BrowsePath(); browsePath.StartingNode = item.NodeId; RelativePathElement element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasProperty; element.IsInverse = false; element.IncludeSubtypes = false; element.TargetName = Opc.Ua.BrowseNames.EURange; browsePath.RelativePath.Elements.Add(element); browsePath.Handle = item; browsePaths.Add(browsePath); browsePath = new BrowsePath(); browsePath.StartingNode = item.NodeId; element = new RelativePathElement(); element.ReferenceTypeId = ReferenceTypeIds.HasProperty; element.IsInverse = false; element.IncludeSubtypes = false; element.TargetName = Opc.Ua.BrowseNames.EnumStrings; browsePath.RelativePath.Elements.Add(element); browsePath.Handle = item; browsePaths.Add(browsePath); } // check if nothing to do. if (browsePaths.Count == 0) { return; } // translate browse paths. BrowsePathResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; try { session.TranslateBrowsePathsToNodeIds( null, browsePaths, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, browsePaths); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, browsePaths); } catch (Exception) { for (int ii = 0; ii < browsePaths.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)browsePaths[ii].Handle; item.EuType = 0; } return; } // build list of properties that need to be read. ReadValueIdCollection propertiesToRead = new ReadValueIdCollection(); for (int ii = 0; ii < results.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)browsePaths[ii].Handle; BrowsePathResult result = results[ii]; if (StatusCode.IsBad(result.StatusCode)) { if (item.EuType < 0 && result.StatusCode == StatusCodes.BadNoMatch) { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_NOENUM; } continue; } if (result.Targets.Count == 0 || result.Targets[0].TargetId.IsAbsolute) { if (item.EuType < 0) { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_NOENUM; } continue; } ReadValueId propertyToRead = new ReadValueId(); propertyToRead.NodeId = (NodeId)result.Targets[0].TargetId; propertyToRead.AttributeId = Attributes.Value; propertyToRead.Handle = item; propertiesToRead.Add(propertyToRead); if (browsePaths[ii].RelativePath.Elements[0].TargetName.Name == Opc.Ua.BrowseNames.EURange) { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG; } else { item.EuType = (int)OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED; } } // check if nothing to do. if (propertiesToRead.Count == 0) { return; } // read attribute values from the server. DataValueCollection values = null; try { session.Read( null, 0, TimestampsToReturn.Neither, propertiesToRead, out values, out diagnosticInfos); ClientBase.ValidateResponse(values, propertiesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, propertiesToRead); } catch (Exception) { for (int ii = 0; ii < propertiesToRead.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)propertiesToRead[ii].Handle; item.EuType = 0; } return; } // process results. for (int ii = 0; ii < values.Count; ii++) { ComDaGroupItem item = (ComDaGroupItem)propertiesToRead[ii].Handle; if (StatusCode.IsBad(values[ii].StatusCode)) { item.EuType = 0; continue; } if (item.EuType == (int)OpcRcw.Da.OPCEUTYPE.OPC_ANALOG) { Range range = (Range)values[ii].GetValue <Range>(null); if (range == null) { item.EuType = 0; continue; } item.EuInfo = new double[] { range.Low, range.High }; continue; } if (item.EuType == (int)OpcRcw.Da.OPCEUTYPE.OPC_ENUMERATED) { LocalizedText[] texts = (LocalizedText[])values[ii].GetValue <LocalizedText[]>(null); if (texts == null) { item.EuType = 0; continue; } string[] strings = new string[texts.Length]; for (int jj = 0; jj < strings.Length; jj++) { if (!LocalizedText.IsNullOrEmpty(texts[jj])) { strings[jj] = texts[jj].Text; } } item.EuInfo = strings; continue; } } }
/// <summary> /// Updates the object with the results of a translate browse paths request. /// </summary> internal void SetResolvePathResult( BrowsePathResult result, ServiceResult error) { m_error = error; }
/// <summary> /// Verifies that the timestamps match the requested filter. /// </summary> private bool VerifyPaths( Node node, BrowsePath request, BrowsePathResult result) { // check empty path. if (request.RelativePath.Elements == null || request.RelativePath.Elements.Count == 0) { if (result.StatusCode != StatusCodes.BadBrowseNameInvalid) { Log( "Unexpected error returned during translate for Node '{0}'. NodeId = {1}, Expected = {2}, Actual = {3}", node, node.NodeId, (StatusCode)StatusCodes.BadBrowseNameInvalid, result.StatusCode); return(false); } } BrowsePathResult expectedResult = new BrowsePathResult(); GetTargets(node, request.RelativePath.Elements, 0, expectedResult); if (result.StatusCode == StatusCodes.BadNoMatch) { if (expectedResult.Targets.Count > 0) { Log( "Translate returned BadNoMatch when targets expected '{0}'. NodeId = {1}, Path = {2}, ExpectedCount = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), expectedResult.Targets.Count); return(false); } if (result.Targets.Count > 0) { Log( "Translate returned targets with a BadNoMatch code '{0}'. NodeId = {1}, Path = {2}, ActualCount = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), result.Targets.Count); return(false); } return(true); } if (expectedResult.Targets.Count == 0) { Log( "Translate returned invalided error code when no targets exist '{0}'. NodeId = {1}, Path = {2}, StatusCode = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), (StatusCode)result.StatusCode); return(false); } // check status code. if (result.StatusCode != StatusCodes.Good) { Log( "Translate returned an error for Node '{0}'. NodeId = {1}, Path = {2}, StatusCode = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), (StatusCode)result.StatusCode); return(false); } // check for expected targets. for (int ii = 0; ii < expectedResult.Targets.Count; ii++) { BrowsePathTarget expectedTarget = expectedResult.Targets[ii]; bool found = false; for (int jj = 0; jj < result.Targets.Count; jj++) { BrowsePathTarget actualTarget = result.Targets[jj]; if (actualTarget.TargetId != expectedTarget.TargetId) { continue; } found = true; if (actualTarget.RemainingPathIndex != expectedTarget.RemainingPathIndex) { Log( "Translate did not return correct remaining path index for target Node '{0}'. NodeId = {1}, Path = {2}, Expected = {3}, Actual = {4}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), expectedTarget.RemainingPathIndex, actualTarget.RemainingPathIndex); return(false); } break; } if (!found) { Log( "Translate did not return expected target Node '{0}'. NodeId = {1}, Path = {2}, TargetId = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), expectedTarget.TargetId); return(false); } } // check for unexpected targets. for (int ii = 0; ii < result.Targets.Count; ii++) { BrowsePathTarget actualTarget = result.Targets[ii]; bool found = false; for (int jj = 0; jj < expectedResult.Targets.Count; jj++) { BrowsePathTarget expectedTarget = expectedResult.Targets[jj]; if (actualTarget.TargetId == expectedTarget.TargetId) { found = true; break; } } if (!found) { Log( "Translate returned unexpected target Node '{0}'. NodeId = {1}, Path = {2}, TargetId = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), actualTarget.TargetId); return(false); } } // all ok. return(true); }
/// <summary> /// Recursively finds the targets of the specified path. /// </summary> private void GetTargets(Node start, IList <RelativePathElement> path, int index, BrowsePathResult result) { // check for invalid parameters. if (index >= path.Count) { return; } // look for list of references for node. ReferenceDescriptionCollection references = start.Handle as ReferenceDescriptionCollection; if (references == null || references.Count == 0) { return; } RelativePathElement element = path[index]; // each list of references. for (int ii = 0; ii < references.Count; ii++) { ReferenceDescription reference = references[ii]; // check for a reference match. if (element.IsInverse == reference.IsForward) { continue; } if (element.ReferenceTypeId != reference.ReferenceTypeId) { if (!element.IncludeSubtypes) { continue; } if (!Session.TypeTree.IsTypeOf(reference.ReferenceTypeId, element.ReferenceTypeId)) { continue; } } // check for a browse name match. if (element.TargetName != reference.BrowseName) { continue; } // check for end of list. if (index == path.Count - 1) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = reference.NodeId; item.RemainingPathIndex = UInt32.MaxValue; result.Targets.Add(item); continue; } // check for external reference. if (reference.NodeId.IsAbsolute) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = reference.NodeId; item.RemainingPathIndex = (uint)index + 1; result.Targets.Add(item); continue; } // check for targets. Node target = null; if (!AvailableNodes.TryGetValue((NodeId)reference.NodeId, out target)) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = reference.NodeId; item.RemainingPathIndex = (uint)index + 1; result.Targets.Add(item); continue; } // recursively follow targets. GetTargets(target, path, index + 1, result); } }
/// <summary> /// Verifies that the timestamps match the requested filter. /// </summary> private bool VerifyPaths( Node node, BrowsePath request, BrowsePathResult result) { // check empty path. if (request.RelativePath.Elements == null || request.RelativePath.Elements.Count == 0) { if (result.StatusCode != StatusCodes.BadBrowseNameInvalid) { Log( "Unexpected error returned during translate for Node '{0}'. NodeId = {1}, Expected = {2}, Actual = {3}", node, node.NodeId, (StatusCode)StatusCodes.BadBrowseNameInvalid, result.StatusCode); return false; } } BrowsePathResult expectedResult = new BrowsePathResult(); GetTargets(node, request.RelativePath.Elements, 0, expectedResult); if (result.StatusCode == StatusCodes.BadNoMatch) { if (expectedResult.Targets.Count > 0) { Log( "Translate returned BadNoMatch when targets expected '{0}'. NodeId = {1}, Path = {2}, ExpectedCount = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), expectedResult.Targets.Count); return false; } if (result.Targets.Count > 0) { Log( "Translate returned targets with a BadNoMatch code '{0}'. NodeId = {1}, Path = {2}, ActualCount = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), result.Targets.Count); return false; } return true; } if (expectedResult.Targets.Count == 0) { Log( "Translate returned invalided error code when no targets exist '{0}'. NodeId = {1}, Path = {2}, StatusCode = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), (StatusCode)result.StatusCode); return false; } // check status code. if (result.StatusCode != StatusCodes.Good) { Log( "Translate returned an error for Node '{0}'. NodeId = {1}, Path = {2}, StatusCode = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), (StatusCode)result.StatusCode); return false; } // check for expected targets. for (int ii = 0; ii < expectedResult.Targets.Count; ii++) { BrowsePathTarget expectedTarget = expectedResult.Targets[ii]; bool found = false; for (int jj = 0; jj < result.Targets.Count; jj++) { BrowsePathTarget actualTarget = result.Targets[jj]; if (actualTarget.TargetId != expectedTarget.TargetId) { continue; } found = true; if (actualTarget.RemainingPathIndex != expectedTarget.RemainingPathIndex) { Log( "Translate did not return correct remaining path index for target Node '{0}'. NodeId = {1}, Path = {2}, Expected = {3}, Actual = {4}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), expectedTarget.RemainingPathIndex, actualTarget.RemainingPathIndex); return false; } break; } if (!found) { Log( "Translate did not return expected target Node '{0}'. NodeId = {1}, Path = {2}, TargetId = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), expectedTarget.TargetId); return false; } } // check for unexpected targets. for (int ii = 0; ii < result.Targets.Count; ii++) { BrowsePathTarget actualTarget = result.Targets[ii]; bool found = false; for (int jj = 0; jj < expectedResult.Targets.Count; jj++) { BrowsePathTarget expectedTarget = expectedResult.Targets[jj]; if (actualTarget.TargetId == expectedTarget.TargetId) { found = true; break; } } if (!found) { Log( "Translate returned unexpected target Node '{0}'. NodeId = {1}, Path = {2}, TargetId = {3}", node, node.NodeId, GetRelativePath(request.RelativePath.Elements), actualTarget.TargetId); return false; } } // all ok. return true; }
/// <summary> /// Recursively finds the targets of the specified path. /// </summary> private void GetTargets(Node start, IList<RelativePathElement> path, int index, BrowsePathResult result) { // check for invalid parameters. if (index >= path.Count) { return; } // look for list of references for node. ReferenceDescriptionCollection references = start.Handle as ReferenceDescriptionCollection; if (references == null || references.Count == 0) { return; } RelativePathElement element = path[index]; // each list of references. for (int ii = 0; ii < references.Count; ii++) { ReferenceDescription reference = references[ii]; // check for a reference match. if (element.IsInverse == reference.IsForward) { continue; } if (element.ReferenceTypeId != reference.ReferenceTypeId) { if (!element.IncludeSubtypes) { continue; } if (!Session.TypeTree.IsTypeOf(reference.ReferenceTypeId, element.ReferenceTypeId)) { continue; } } // check for a browse name match. if (element.TargetName != reference.BrowseName) { continue; } // check for end of list. if (index == path.Count-1) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = reference.NodeId; item.RemainingPathIndex = UInt32.MaxValue; result.Targets.Add(item); continue; } // check for external reference. if (reference.NodeId.IsAbsolute) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = reference.NodeId; item.RemainingPathIndex = (uint)index+1; result.Targets.Add(item); continue; } // check for targets. Node target = null; if (!AvailableNodes.TryGetValue((NodeId)reference.NodeId, out target)) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = reference.NodeId; item.RemainingPathIndex = (uint)index+1; result.Targets.Add(item); continue; } // recursively follow targets. GetTargets(target, path, index+1, result); } }
private async Task <bool> TryConnect() { if (connection != null) { return(true); } if (string.IsNullOrEmpty(config.Address)) { return(false); } try { var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = config.Address, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; GetEndpointsResponse endpoints = await UaTcpDiscoveryService.GetEndpointsAsync(getEndpointsRequest); EndpointDescription[] noSecurityEndpoints = endpoints.Endpoints.Where(e => e.SecurityPolicyUri == SecurityPolicyUris.None).ToArray(); var(endpoint, userIdentity) = FirstEndpointWithLogin(noSecurityEndpoints); if (endpoint == null || userIdentity == null) { throw new Exception("No matching endpoint"); } var channel = new UaTcpSessionChannel( this.appDescription, null, userIdentity, endpoint, loggerFactory); await channel.OpenAsync(); this.connection = channel; PrintLine($"Opened session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); PrintLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); PrintLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); PrintLine($"UserIdentityToken: '{channel.UserIdentity}'."); ItemInfo[] nodesNeedingResolve = mapId2Info.Values.Where(n => n.Node == null).ToArray(); if (nodesNeedingResolve.Length > 0) { PrintLine($"Resolving node ids for {nodesNeedingResolve.Length} items..."); TranslateBrowsePathsToNodeIdsRequest req = new TranslateBrowsePathsToNodeIdsRequest() { BrowsePaths = nodesNeedingResolve.Select(n => new BrowsePath() { StartingNode = n.StartingNode, RelativePath = n.RelativePath }).ToArray() }; TranslateBrowsePathsToNodeIdsResponse resp = await connection.TranslateBrowsePathsToNodeIdsAsync(req); if (resp.Results.Length != nodesNeedingResolve.Length) { LogWarn("Mismatch", "TranslateBrowsePathsToNodeIds failed"); } else { for (int i = 0; i < resp.Results.Length; ++i) { BrowsePathResult x = resp.Results[i]; if (StatusCode.IsGood(x.StatusCode) && x.Targets.Length > 0) { NodeId id = x.Targets[0].TargetId.NodeId; nodesNeedingResolve[i].Node = id; PrintLine($"Resolved item '{nodesNeedingResolve[i].Name}' => {id}"); } else { PrintLine($"Could not resolve item '{nodesNeedingResolve[i].Name}'!"); } } } } return(true); } catch (Exception exp) { Exception baseExp = exp.GetBaseException() ?? exp; LogWarn("OpenChannel", "Open channel error: " + baseExp.Message, dataItem: null, details: baseExp.StackTrace); await CloseChannel(); return(false); } }
/// <summary> /// Translates a browse path. /// </summary> protected ServiceResult TranslateBrowsePath( OperationContext context, BrowsePath browsePath, BrowsePathResult result) { Debug.Assert(browsePath != null); Debug.Assert(result != null); // check for valid start node. INodeManager nodeManager = null; object sourceHandle = GetManagerHandle(browsePath.StartingNode, out nodeManager); if (sourceHandle == null) { return StatusCodes.BadNodeIdUnknown; } // check the relative path. RelativePath relativePath = browsePath.RelativePath; if (relativePath.Elements == null || relativePath.Elements.Count == 0) { return StatusCodes.BadNothingToDo; } for (int ii = 0; ii < relativePath.Elements.Count; ii++) { RelativePathElement element = relativePath.Elements[ii]; if (element == null || QualifiedName.IsNull(relativePath.Elements[ii].TargetName)) { return StatusCodes.BadBrowseNameInvalid; } if (NodeId.IsNull(element.ReferenceTypeId)) { element.ReferenceTypeId = ReferenceTypeIds.References; } } // translate path. TranslateBrowsePath( context, nodeManager, sourceHandle, relativePath, result.Targets, 0); return ServiceResult.Good; }
/// <summary> /// Translates a start node id plus a relative paths into a node id. /// </summary> public virtual void TranslateBrowsePathsToNodeIds( OperationContext context, BrowsePathCollection browsePaths, out BrowsePathResultCollection results, out DiagnosticInfoCollection diagnosticInfos) { if (browsePaths == null)throw new ArgumentNullException("browsePaths"); bool diagnosticsExist = false; results = new BrowsePathResultCollection(browsePaths.Count); diagnosticInfos = new DiagnosticInfoCollection(browsePaths.Count); for (int ii = 0; ii < browsePaths.Count; ii++) { // check if request has timed out or been cancelled. if (StatusCode.IsBad(context.OperationStatus)) { throw new ServiceResultException(context.OperationStatus); } BrowsePath browsePath = browsePaths[ii]; BrowsePathResult result = new BrowsePathResult(); result.StatusCode = StatusCodes.Good; results.Add(result); ServiceResult error = null; // need to trap unexpected exceptions to handle bugs in the node managers. try { error = TranslateBrowsePath(context, browsePath, result); } catch (Exception e) { error = ServiceResult.Create(e, StatusCodes.BadUnexpectedError, "Unexpected error translating browse path."); } if (ServiceResult.IsGood(error)) { // check for no match. if (result.Targets.Count == 0) { error = StatusCodes.BadNoMatch; } // put a placeholder for diagnostics. else if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { diagnosticInfos.Add(null); } } // check for error. if (error != null && error.Code != StatusCodes.Good) { result.StatusCode = error.StatusCode; if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, error); diagnosticInfos.Add(diagnosticInfo); diagnosticsExist = true; } } } // clear the diagnostics array if no diagnostics requested or no errors occurred. UpdateDiagnostics(context, diagnosticsExist, ref diagnosticInfos); }
/// <summary> /// Follows the browse path and returns any targets found. /// </summary> public void TranslateBrowsePath( BrowsePath request, BrowsePathResult result, DiagnosticInfo diagnosticInfo) { lock (m_lock) { // find the starting node. Node source = m_nodes.Find(request.StartingNode); if (source == null) { result.StatusCode = new StatusCode(StatusCodes.BadNodeIdUnknown); return; } // check if there is nothing to do. if (request.RelativePath.Elements == null || request.RelativePath.Elements.Count == 0) { result.StatusCode = new StatusCode(StatusCodes.BadNothingToDo); return; } result.Targets = new ListOfBrowsePathTarget(); Node current = source; // follow each element in the browse path. for (int ii = 0; ii < request.RelativePath.Elements.Count; ii++) { RelativePathElement element = request.RelativePath.Elements[ii]; bool found = false; // need to find any matching reference. foreach (ReferenceNode reference in current.References) { // inverse is a quick check - do that first. if (reference.IsInverse != element.IsInverse) { continue; } // check for reference type matches. if (reference.ReferenceTypeId != element.ReferenceTypeId) { if (!element.IncludeSubtypes) { continue; } if (!IsTypeOf(reference.ReferenceTypeId, element.ReferenceTypeId)) { continue; } } // The UA type model requires that the browse names of all targets of hierarchial references // be unique within a parent. This means most browse paths will point to no more than one node. // However, instances are allowed to add additional nodes with duplicate browse names. If the server // allows this it must keep track of the child that matches the type model and return it as the // first target. // need to find the target to check the browse name. Node target = m_nodes.Find(reference.TargetId); if (target != null) { if (element.TargetName == target.BrowseName) { found = true; current = target; break; } } } if (found) { // check if the complete path has been followed. if (ii == request.RelativePath.Elements.Count - 1) { BrowsePathTarget item = new BrowsePathTarget(); item.TargetId = new ExpandedNodeId(current.NodeId); item.RemainingPathIndex = UInt32.MaxValue; result.Targets.Add(item); } } } } }