Exemple #1
0
        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 node ids for a set of relative paths.
        /// </summary>
        /// <param name="session">An open session with the server to use.</param>
        /// <param name="startNodeId">The starting node for the relative paths.</param>
        /// <param name="namespacesUris">The namespace URIs referenced by the relative paths.</param>
        /// <param name="relativePaths">The relative paths.</param>
        /// <returns>A collection of local nodes.</returns>
        public static List <NodeId> TranslateBrowsePaths(
            Session session,
            NodeId startNodeId,
            NamespaceTable namespacesUris,
            params string[] relativePaths)
        {
            // build the list of browse paths to follow by parsing the relative paths.
            BrowsePathCollection browsePaths = new BrowsePathCollection();

            if (relativePaths != null)
            {
                for (int ii = 0; ii < relativePaths.Length; ii++)
                {
                    BrowsePath browsePath = new BrowsePath();

                    // The relative paths used indexes in the namespacesUris table. These must be
                    // converted to indexes used by the server. An error occurs if the relative path
                    // refers to a namespaceUri that the server does not recognize.

                    // The relative paths may refer to ReferenceType by their BrowseName. The TypeTree object
                    // allows the parser to look up the server's NodeId for the ReferenceType.

                    browsePath.RelativePath = RelativePath.Parse(
                        relativePaths[ii],
                        session.TypeTree,
                        namespacesUris,
                        session.NamespaceUris);

                    browsePath.StartingNode = startNodeId;

                    browsePaths.Add(browsePath);
                }
            }

            // make the call to the server.
            BrowsePathResultCollection results;
            DiagnosticInfoCollection   diagnosticInfos;

            ResponseHeader responseHeader = session.TranslateBrowsePathsToNodeIds(
                null,
                browsePaths,
                out results,
                out diagnosticInfos);

            // ensure that the server returned valid results.
            Session.ValidateResponse(results, browsePaths);
            Session.ValidateDiagnosticInfos(diagnosticInfos, browsePaths);

            // collect the list of node ids found.
            List <NodeId> nodes = new List <NodeId>();

            for (int ii = 0; ii < results.Count; ii++)
            {
                // check if the start node actually exists.
                if (StatusCode.IsBad(results[ii].StatusCode))
                {
                    nodes.Add(null);
                    continue;
                }

                // an empty list is returned if no node was found.
                if (results[ii].Targets.Count == 0)
                {
                    nodes.Add(null);
                    continue;
                }

                // Multiple matches are possible, however, the node that matches the type model is the
                // one we are interested in here. The rest can be ignored.
                BrowsePathTarget target = results[ii].Targets[0];

                if (target.RemainingPathIndex != UInt32.MaxValue)
                {
                    nodes.Add(null);
                    continue;
                }

                // The targetId is an ExpandedNodeId because it could be node in another server.
                // The ToNodeId function is used to convert a local NodeId stored in a ExpandedNodeId to a NodeId.
                nodes.Add(ExpandedNodeId.ToNodeId(target.TargetId, session.NamespaceUris));
            }

            // return whatever was found.
            return(nodes);
        }
Exemple #3
0
        /// <summary>
        /// Finds an element identified by the path from the root.
        /// </summary>
        private AeBrowseElement Find(Session session, string itemId, AeBrowseElement root, Stack <string> names, bool isArea)
        {
            string browseText = null;

            BrowsePath browsePath = new BrowsePath();

            browsePath.StartingNode = root.NodeId;

            while (names.Count > 0)
            {
                RelativePathElement path = new RelativePathElement();

                path.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasNotifier;
                path.IsInverse       = false;
                path.IncludeSubtypes = true;

                // final hop can be HasEventSource for sources.
                if (!isArea && names.Count == 1)
                {
                    path.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasEventSource;
                }

                browseText      = names.Pop();
                path.TargetName = m_mapper.GetRemoteBrowseName(browseText);
                browsePath.RelativePath.Elements.Add(path);
            }

            BrowsePathCollection browsePaths = new BrowsePathCollection();

            browsePaths.Add(browsePath);

            // make the call to the server.
            BrowsePathResultCollection results;
            DiagnosticInfoCollection   diagnosticInfos;

            ResponseHeader responseHeader = session.TranslateBrowsePathsToNodeIds(
                null,
                browsePaths,
                out results,
                out diagnosticInfos);

            // ensure that the server returned valid results.
            Session.ValidateResponse(results, browsePaths);
            Session.ValidateDiagnosticInfos(diagnosticInfos, browsePaths);

            // check if the start node actually exists.
            if (StatusCode.IsBad(results[0].StatusCode))
            {
                return(null);
            }

            // must be exact one target.
            if (results[0].Targets.Count != 1)
            {
                return(null);
            }

            // can't be an external reference.
            BrowsePathTarget target = results[0].Targets[0];

            if (target.RemainingPathIndex != UInt32.MaxValue)
            {
                return(null);
            }

            // need to check if at the end of the tree.
            BrowseDescription nodeToBrowse = new BrowseDescription();

            nodeToBrowse.NodeId          = (NodeId)target.TargetId;
            nodeToBrowse.ReferenceTypeId = Opc.Ua.ReferenceTypeIds.HasEventSource;
            nodeToBrowse.BrowseDirection = BrowseDirection.Forward;
            nodeToBrowse.IncludeSubtypes = true;

            ReferenceDescriptionCollection children = ComAeUtils.Browse(session, nodeToBrowse, false);

            if (!isArea)
            {
                if (children != null && children.Count > 0)
                {
                    return(null);
                }
            }
            else
            {
                if (children == null || children.Count == 0)
                {
                    return(null);
                }
            }

            // construct the element.
            AeBrowseElement element = new AeBrowseElement();

            element.NodeId     = (NodeId)target.TargetId;
            element.ItemId     = itemId;
            element.BrowseText = browseText;
            element.IsArea     = isArea;

            return(element);
        }
        /// <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);
            }
        }
Exemple #6
0
        /// <summary>
        /// Gets the available attributes for an HDA item.
        /// </summary>
        /// <param name="session">The session.</param>
        /// <param name="nodeId">The node id.</param>
        /// <returns></returns>
        private ReadValueIdCollection GetAvailableAttributes(Session session, NodeId nodeId)
        {
            ReadValueIdCollection supportedAttributes = new ReadValueIdCollection();

            // add mandatory HDA attributes.
            supportedAttributes.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_ITEMID, Attributes.DisplayName));
            supportedAttributes.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_DATA_TYPE, Attributes.DataType));
            supportedAttributes.Add(Construct(nodeId, ComHdaProxy.INTERNAL_ATTRIBUTE_VALUE_RANK, Attributes.ValueRank));
            supportedAttributes.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_DESCRIPTION, Attributes.Description));
            supportedAttributes.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_ARCHIVING, Attributes.Historizing));

            // check if nodes are defined for all optional HDA attributes.
            BrowsePathCollection pathsToRead = new BrowsePathCollection();

            pathsToRead.Add(Construct(nodeId, ComHdaProxy.INTERNAL_ATTRIBUTE_ANNOTATION, Opc.Ua.BrowseNames.Annotations));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_ENG_UNITS, Opc.Ua.BrowseNames.EngineeringUnits));;
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_DERIVE_EQUATION, Opc.Ua.BrowseNames.Definition));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_NORMAL_MAXIMUM, Opc.Ua.BrowseNames.EURange));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_NORMAL_MINIMUM, Opc.Ua.BrowseNames.EURange));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_HIGH_ENTRY_LIMIT, Opc.Ua.BrowseNames.InstrumentRange));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_LOW_ENTRY_LIMIT, Opc.Ua.BrowseNames.InstrumentRange));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_STEPPED, Opc.Ua.BrowseNames.HAConfiguration, Opc.Ua.BrowseNames.Stepped));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_MAX_TIME_INT, Opc.Ua.BrowseNames.HAConfiguration, Opc.Ua.BrowseNames.MaxTimeInterval));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_MIN_TIME_INT, Opc.Ua.BrowseNames.HAConfiguration, Opc.Ua.BrowseNames.MinTimeInterval));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_EXCEPTION_DEV, Opc.Ua.BrowseNames.HAConfiguration, Opc.Ua.BrowseNames.ExceptionDeviation));
            pathsToRead.Add(Construct(nodeId, OpcRcw.Hda.Constants.OPCHDA_EXCEPTION_DEV_TYPE, Opc.Ua.BrowseNames.HAConfiguration, Opc.Ua.BrowseNames.ExceptionDeviationFormat));

            BrowsePathResultCollection results         = null;
            DiagnosticInfoCollection   diagnosticInfos = null;

            session.TranslateBrowsePathsToNodeIds(
                null,
                pathsToRead,
                out results,
                out diagnosticInfos);

            Session.ValidateResponse(results, pathsToRead);
            Session.ValidateDiagnosticInfos(diagnosticInfos, pathsToRead);

            for (int ii = 0; ii < pathsToRead.Count; ii++)
            {
                uint attributeId = (uint)pathsToRead[ii].Handle;

                // path does not exist.
                if (StatusCode.IsBad(results[ii].StatusCode))
                {
                    continue;
                }

                // nothing found.
                if (results[ii].Targets.Count == 0)
                {
                    continue;
                }

                // choose the first valid target.
                for (int jj = 0; jj < results[ii].Targets.Count; jj++)
                {
                    BrowsePathTarget target = results[ii].Targets[jj];

                    if (target.RemainingPathIndex == UInt32.MaxValue && !NodeId.IsNull(target.TargetId) && !target.TargetId.IsAbsolute)
                    {
                        supportedAttributes.Add(Construct((NodeId)target.TargetId, attributeId, Attributes.Value));
                        break;
                    }
                }
            }

            return(supportedAttributes);
        }
        /// <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>
        /// Recursively processes the elements in the RelativePath starting at the specified index.
        /// </summary>
        private void TranslateBrowsePath(
            OperationContext           context,
            INodeManager               nodeManager,
            object                     sourceHandle,
            RelativePath               relativePath,
            BrowsePathTargetCollection targets,
            int                        index)
        {
            Debug.Assert(nodeManager != null);
            Debug.Assert(sourceHandle != null);
            Debug.Assert(relativePath != null);
            Debug.Assert(targets != null);

            // check for end of list.
            if (index < 0 || index >= relativePath.Elements.Count)
            {
                return;
            }
            
            // follow the next hop.
            RelativePathElement element = relativePath.Elements[index];

            // check for valid reference type.
            if (!element.IncludeSubtypes && NodeId.IsNull(element.ReferenceTypeId))
            {
                return;
            }

            // check for valid target name.
            if (QualifiedName.IsNull(element.TargetName))
            {
                throw new ServiceResultException(StatusCodes.BadBrowseNameInvalid);
            }

            List<ExpandedNodeId> targetIds = new List<ExpandedNodeId>();
            List<NodeId> externalTargetIds = new List<NodeId>();

            try
            {
                nodeManager.TranslateBrowsePath(
                    context,
                    sourceHandle,
                    element,
                    targetIds,
                    externalTargetIds);
            }
            catch (Exception e)
            {
                Utils.Trace(e, "Unexpected error translating browse path.");
                return;
            }

            // must check the browse name on all external targets.
            for (int ii = 0; ii < externalTargetIds.Count; ii++)
            {
                // get the browse name from another node manager.
                ReferenceDescription description = new ReferenceDescription();

                UpdateReferenceDescription(
                    context,
                    externalTargetIds[ii],
                    NodeClass.Unspecified,
                    BrowseResultMask.BrowseName,
                    description);    
                
                // add to list if target name matches.
                if (description.BrowseName == element.TargetName)
                {
                    bool found = false;

                    for (int jj = 0; jj < targetIds.Count; jj++)
                    {
                        if (targetIds[jj] == externalTargetIds[ii])
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        targetIds.Add(externalTargetIds[ii]);
                    }
                }
            }

            // check if done after a final hop.
            if (index == relativePath.Elements.Count-1)
            {
                for (int ii = 0; ii < targetIds.Count; ii++)
                {
                    BrowsePathTarget target = new BrowsePathTarget();   
                 
                    target.TargetId = targetIds[ii];
                    target.RemainingPathIndex = UInt32.MaxValue;

                    targets.Add(target);
                }

                return;
            }

            // process next hops.
            for (int ii = 0; ii < targetIds.Count; ii++)
            {
                ExpandedNodeId targetId = targetIds[ii];

                // check for external reference.
                if (targetId.IsAbsolute)
                {
                    BrowsePathTarget target = new BrowsePathTarget();   
                 
                    target.TargetId = targetId;
                    target.RemainingPathIndex = (uint)(index+1);

                    targets.Add(target);
                    continue;
                }

                // check for valid start node.   
                sourceHandle = GetManagerHandle((NodeId)targetId, out nodeManager);

                if (sourceHandle == null)
                {
                    continue;
                }
            
                // recusively follow hops.
                TranslateBrowsePath(
                    context,
                    nodeManager,
                    sourceHandle,
                    relativePath,
                    targets,
                    index+1);
            }
        }
Exemple #9
0
        /// <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);
                        }
                    }
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// Provides a way to move �up� or �down� in a hierarchical space from the current position, or a way to move to a specific position in the area space tree. The target szString must represent an area, rather than a source.
        /// </summary>
        /// <param name="dwBrowseDirection">OPCAE_BROWSE_UP, OPCAE_BROWSE_DOWN, or OPCAE_BROWSE_TO</param>
        /// <param name="szString">
        /// For DOWN, the partial area name of the area to move into. This would be one of the strings returned from BrowseOPCAreas.
        /// For UP this parameter is ignored and should point to a NULL string.
        /// For BROWSE_TO, the fully qualified area name (as obtained from GetQualifiedAreaName method) or a pointer to a NUL string to go to the root.
        /// </param>
        public void ChangeBrowsePosition(OPCAEBROWSEDIRECTION dwBrowseDirection, string szString)
        {
            lock (m_lock)
            {
                try
                {
                    switch (dwBrowseDirection)
                    {
                    // move to a specified position or root.
                    case OPCAEBROWSEDIRECTION.OPCAE_BROWSE_TO:
                    {
                        try
                        {
                            // move to root.
                            if (String.IsNullOrEmpty(szString))
                            {
                                m_browseStack.Clear();
                                m_browseStack.Push(m_session.NodeCache.Find(Objects.Server));
                                break;
                            }

                            // Translate the fully qualified area name to NodeId
                            List <string> szAreas = new List <string>();
                            szAreas.Add(szString);
                            BrowsePathResultCollection results = m_server.GetBrowseTargets(szAreas);
                            if (StatusCode.IsBad(results[0].StatusCode))
                            {
                                throw ComUtils.CreateComException(ResultIds.E_INVALIDBRANCHNAME);
                            }

                            BrowsePathTarget target = results[0].Targets[0];
                            INode            node   = m_session.NodeCache.Find(target.TargetId);
                            if (node == null)
                            {
                                throw ComUtils.CreateComException(ResultIds.E_INVALIDBRANCHNAME);
                            }

                            // build a new browse stack.
                            Stack <INode> browseStack = new Stack <INode>();

                            if (!FindPathToNode(node, browseStack))
                            {
                                throw ComUtils.CreateComException(ResultIds.E_INVALIDBRANCHNAME);
                            }

                            // push target node onto stack.
                            browseStack.Push(node);

                            m_browseStack = browseStack;
                        }
                        catch
                        {
                            throw ComUtils.CreateComException(ResultIds.E_INVALIDBRANCHNAME);
                        }
                        break;
                    }

                    // move to a child branch.
                    case OPCAEBROWSEDIRECTION.OPCAE_BROWSE_DOWN:
                    {
                        // check for invalid name.
                        if (String.IsNullOrEmpty(szString))
                        {
                            throw ComUtils.CreateComException(ResultIds.E_INVALIDBRANCHNAME);
                        }

                        // find the current node.
                        INode parent = m_browseStack.Peek();

                        if (parent == null)
                        {
                            throw ComUtils.CreateComException(ResultIds.E_FAIL);
                        }

                        // find the child.
                        INode child = FindChildByName(parent.NodeId, szString);

                        if (child == null)
                        {
                            throw ComUtils.CreateComException(ResultIds.E_INVALIDBRANCHNAME);
                        }
                        // save the new position.
                        m_browseStack.Push(child);
                        break;
                    }

                    // move to a parent branch.
                    case OPCAEBROWSEDIRECTION.OPCAE_BROWSE_UP:
                    {
                        // check for invalid name.
                        if (!String.IsNullOrEmpty(szString))
                        {
                            throw ComUtils.CreateComException(ResultIds.E_FAIL);
                        }

                        // can't move up from root.
                        if (m_browseStack.Count <= 1)
                        {
                            throw ComUtils.CreateComException(ResultIds.E_FAIL);
                        }

                        // move up the stack.
                        m_browseStack.Pop();
                        break;
                    }

                    default:
                    {
                        throw ComUtils.CreateComException(ResultIds.E_INVALIDARG);
                    }
                    }
                }
                catch (COMException e)
                {
                    throw ComUtils.CreateComException(e);
                }
                catch (Exception e)
                {
                    Utils.Trace(e, "Unexpected error in ChangeBrowsePosition");
                    throw ComUtils.CreateComException(e);
                }
            }
        }
Exemple #11
0
        /// <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);
                        }
                    }
                }
            }
        }