/// <summary> /// Restores a continuation point for a session. /// </summary> /// <remarks> /// The caller is responsible for disposing the continuation point returned. /// </remarks> public ContinuationPoint RestoreContinuationPoint(byte[] continuationPoint) { lock (m_lock) { if (m_browseContinuationPoints == null) { return(null); } if (continuationPoint == null || continuationPoint.Length != 16) { return(null); } Guid id = new Guid(continuationPoint); for (int ii = 0; ii < m_browseContinuationPoints.Count; ii++) { if (m_browseContinuationPoints[ii].Id == id) { ContinuationPoint cp = m_browseContinuationPoints[ii]; m_browseContinuationPoints.RemoveAt(ii); return(cp); } } return(null); } }
/// <summary> /// Saves a continuation point for a session. /// </summary> /// <remarks> /// If the session has too many continuation points the oldest one is dropped. /// </remarks> public void SaveContinuationPoint(ContinuationPoint continuationPoint) { if (continuationPoint == null) { throw new ArgumentNullException("continuationPoint"); } lock (m_lock) { if (m_browseContinuationPoints == null) { m_browseContinuationPoints = new List <ContinuationPoint>(); } // remove the first continuation point if too many points. while (m_browseContinuationPoints.Count > m_maxBrowseContinuationPoints) { ContinuationPoint cp = m_browseContinuationPoints[0]; m_browseContinuationPoints.RemoveAt(0); Utils.SilentDispose(cp); } // add to end of list. m_browseContinuationPoints.Add(continuationPoint); } }
/// <summary> /// Browses the references from a node managed by the node manager. /// </summary> /// <remarks> /// The continuation point is created for every browse operation and contains the browse parameters. /// The node manager can store its state information in the Data and Index properties. /// </remarks> public virtual void Browse( OperationContext context, ref ContinuationPoint continuationPoint, IList<ReferenceDescription> references) { if (continuationPoint == null) throw new ArgumentNullException("continuationPoint"); if (references == null) throw new ArgumentNullException("references"); // check for view. if (!ViewDescription.IsDefault(continuationPoint.View)) { throw new ServiceResultException(StatusCodes.BadViewIdUnknown); } ServerSystemContext systemContext = m_systemContext.Copy(context); lock (Lock) { // verify that the node exists. NodeState source = IsHandleInNamespace(continuationPoint.NodeToBrowse); if (source == null) { throw new ServiceResultException(StatusCodes.BadNodeIdUnknown); } // validate node. if (!ValidateNode(systemContext, source)) { throw new ServiceResultException(StatusCodes.BadNodeIdUnknown); } // check for previous continuation point. INodeBrowser browser = continuationPoint.Data as INodeBrowser; // fetch list of references. if (browser == null) { // create a new browser. browser = source.CreateBrowser( systemContext, continuationPoint.View, continuationPoint.ReferenceTypeId, continuationPoint.IncludeSubtypes, continuationPoint.BrowseDirection, null, null, false); } // apply filters to references. for (IReference reference = browser.Next(); reference != null; reference = browser.Next()) { // create the type definition reference. ReferenceDescription description = GetReferenceDescription(context, reference, continuationPoint); if (description == null) { continue; } // check if limit reached. if (continuationPoint.MaxResultsToReturn != 0 && references.Count >= continuationPoint.MaxResultsToReturn) { browser.Push(reference); continuationPoint.Data = browser; return; } references.Add(description); } // release the continuation point if all done. continuationPoint.Dispose(); continuationPoint = null; } }
/// <summary> /// Returns the references for the node that meets the criteria specified. /// </summary> private ReferenceDescription GetReferenceDescription( OperationContext context, IReference reference, ContinuationPoint continuationPoint) { // create the type definition reference. ReferenceDescription description = new ReferenceDescription(); description.NodeId = reference.TargetId; description.SetReferenceType(continuationPoint.ResultMask, reference.ReferenceTypeId, !reference.IsInverse); // do not cache target parameters for remote nodes. if (reference.TargetId.IsAbsolute) { // only return remote references if no node class filter is specified. if (continuationPoint.NodeClassMask != 0) { return null; } return description; } NodeState target = null; // check for local reference. NodeStateReference referenceInfo = reference as NodeStateReference; if (referenceInfo != null) { target = referenceInfo.Target; } // check for internal reference. if (target == null) { NodeId targetId = (NodeId)reference.TargetId; if (IsNodeIdInNamespace(targetId)) { if (!PredefinedNodes.TryGetValue(targetId, out target)) { target = null; } } } // the target may be a reference to a node in another node manager. In these cases // the target attributes must be fetched by the caller. The Unfiltered flag tells the // caller to do that. if (target == null) { description.Unfiltered = true; return description; } // apply node class filter. if (continuationPoint.NodeClassMask != 0 && ((continuationPoint.NodeClassMask & (uint)target.NodeClass) == 0)) { return null; } NodeId typeDefinition = null; BaseInstanceState instance = target as BaseInstanceState; if (instance != null) { typeDefinition = instance.TypeDefinitionId; } // set target attributes. description.SetTargetAttributes( continuationPoint.ResultMask, target.NodeClass, target.BrowseName, target.DisplayName, typeDefinition); return description; }
/// <summary> /// Checks if the reference is in the view. /// </summary> protected override bool IsReferenceInView(ServerSystemContext context, ContinuationPoint continuationPoint, IReference reference) { if (continuationPoint.View != null) { // guard against absolute node ids. if (reference.TargetId.IsAbsolute) { return true; } // find the node. NodeState node = FindPredefinedNode((NodeId)reference.TargetId, typeof(NodeState)); if (node != null) { return IsNodeInView(context, continuationPoint, node); } } return true; }
/// <summary> /// Checks if the node is in the view. /// </summary> protected override bool IsNodeInView(ServerSystemContext context, ContinuationPoint continuationPoint, NodeState node) { if (continuationPoint.View != null) { if (continuationPoint.View.ViewId == new NodeId(Quickstarts.Views.Views.Engineering, NamespaceIndex)) { // suppress operations properties. if (node != null && node.BrowseName.NamespaceIndex == NamespaceIndexes[2]) { return false; } } if (continuationPoint.View.ViewId == new NodeId(Quickstarts.Views.Views.Operations, NamespaceIndex)) { // suppress engineering properties. if (node != null && node.BrowseName.NamespaceIndex == NamespaceIndexes[1]) { return false; } } } return true; }
/// <summary> /// Returns the references for the node that meets the criteria specified. /// </summary> protected virtual ReferenceDescription GetReferenceDescription( ServerSystemContext context, Dictionary<NodeId,NodeState> cache, IReference reference, ContinuationPoint continuationPoint) { ServerSystemContext systemContext = m_systemContext.Copy(context); // create the type definition reference. ReferenceDescription description = new ReferenceDescription(); description.NodeId = reference.TargetId; description.SetReferenceType(continuationPoint.ResultMask, reference.ReferenceTypeId, !reference.IsInverse); // check if reference is in the view. if (!IsReferenceInView(context, continuationPoint, reference)) { return null; } // do not cache target parameters for remote nodes. if (reference.TargetId.IsAbsolute) { // only return remote references if no node class filter is specified. if (continuationPoint.NodeClassMask != 0) { return null; } return description; } NodeState target = null; // check for local reference. NodeStateReference referenceInfo = reference as NodeStateReference; if (referenceInfo != null) { target = referenceInfo.Target; } // check for internal reference. if (target == null) { NodeHandle handle = GetManagerHandle(context, (NodeId)reference.TargetId, null) as NodeHandle; if (handle != null) { target = ValidateNode(context, handle, null); } } // the target may be a reference to a node in another node manager. In these cases // the target attributes must be fetched by the caller. The Unfiltered flag tells the // caller to do that. if (target == null) { description.Unfiltered = true; return description; } // apply node class filter. if (continuationPoint.NodeClassMask != 0 && ((continuationPoint.NodeClassMask & (uint)target.NodeClass) == 0)) { return null; } // check if target is in the view. if (!IsNodeInView(context, continuationPoint, target)) { return null; } // look up the type definition. NodeId typeDefinition = null; BaseInstanceState instance = target as BaseInstanceState; if (instance != null) { typeDefinition = instance.TypeDefinitionId; } // set target attributes. description.SetTargetAttributes( continuationPoint.ResultMask, target.NodeClass, target.BrowseName, target.DisplayName, typeDefinition); return description; }
/// <summary> /// Checks if the reference is in the view. /// </summary> protected virtual bool IsReferenceInView(ServerSystemContext context, ContinuationPoint continuationPoint, IReference reference) { return true; }
/// <summary> /// Checks if the node is in the view. /// </summary> protected virtual bool IsNodeInView(ServerSystemContext context, ContinuationPoint continuationPoint, NodeState node) { return true; }
/// <summary> /// Browses the references from a node managed by the node manager. /// </summary> /// <remarks> /// The continuation point is created for every browse operation and contains the browse parameters. /// The node manager can store its state information in the Data and Index properties. /// </remarks> public virtual void Browse( OperationContext context, ref ContinuationPoint continuationPoint, IList<ReferenceDescription> references) { if (continuationPoint == null) throw new ArgumentNullException("continuationPoint"); if (references == null) throw new ArgumentNullException("references"); ServerSystemContext systemContext = m_systemContext.Copy(context); // check for valid view. ValidateViewDescription(systemContext, continuationPoint.View); INodeBrowser browser = null; lock (Lock) { // check for valid handle. NodeHandle handle = IsHandleInNamespace(continuationPoint.NodeToBrowse); if (handle == null) { throw new ServiceResultException(StatusCodes.BadNodeIdUnknown); } // validate node. NodeState source = ValidateNode(systemContext, handle, null); if (source == null) { throw new ServiceResultException(StatusCodes.BadNodeIdUnknown); } // check if node is in the view. if (!IsNodeInView(systemContext, continuationPoint, source)) { throw new ServiceResultException(StatusCodes.BadNodeNotInView); } // check for previous continuation point. browser = continuationPoint.Data as INodeBrowser; // fetch list of references. if (browser == null) { // create a new browser. continuationPoint.Data = browser = source.CreateBrowser( systemContext, continuationPoint.View, continuationPoint.ReferenceTypeId, continuationPoint.IncludeSubtypes, continuationPoint.BrowseDirection, null, null, false); } } // prevent multiple access the browser object. lock (browser) { // apply filters to references. Dictionary<NodeId, NodeState> cache = new Dictionary<NodeId, NodeState>(); for (IReference reference = browser.Next(); reference != null; reference = browser.Next()) { // create the type definition reference. ReferenceDescription description = GetReferenceDescription(systemContext, cache, reference, continuationPoint); if (description == null) { continue; } // check if limit reached. if (continuationPoint.MaxResultsToReturn != 0 && references.Count >= continuationPoint.MaxResultsToReturn) { browser.Push(reference); return; } references.Add(description); } // release the continuation point if all done. continuationPoint.Dispose(); continuationPoint = null; } }
/// <summary> /// Saves a continuation point for a session. /// </summary> /// <remarks> /// If the session has too many continuation points the oldest one is dropped. /// </remarks> public void SaveContinuationPoint(ContinuationPoint continuationPoint) { if (continuationPoint == null) throw new ArgumentNullException("continuationPoint"); lock (m_lock) { if (m_browseContinuationPoints == null) { m_browseContinuationPoints = new List<ContinuationPoint>(); } // remove the first continuation point if too many points. while (m_browseContinuationPoints.Count > m_maxBrowseContinuationPoints) { ContinuationPoint cp = m_browseContinuationPoints[0]; m_browseContinuationPoints.RemoveAt(0); Utils.SilentDispose(cp); } // add to end of list. m_browseContinuationPoints.Add(continuationPoint); } }
/// <see cref="INodeManager.Browse" /> public void Browse( OperationContext context, ref ContinuationPoint continuationPoint, IList<ReferenceDescription> references) { if (context == null) throw new ArgumentNullException("context"); if (continuationPoint == null) throw new ArgumentNullException("continuationPoint"); if (references == null) throw new ArgumentNullException("references"); // check for valid handle. ILocalNode source = continuationPoint.NodeToBrowse as ILocalNode; if (source == null) { throw new ServiceResultException(StatusCodes.BadNodeIdUnknown); } // check for view. if (!ViewDescription.IsDefault(continuationPoint.View)) { throw new ServiceResultException(StatusCodes.BadViewIdUnknown); } lock (m_lock) { // construct list of references. uint maxResultsToReturn = continuationPoint.MaxResultsToReturn; // get previous enumerator. IEnumerator<IReference> enumerator = continuationPoint.Data as IEnumerator<IReference>; // fetch a snapshot all references for node. if (enumerator == null) { List<IReference> copy = new List<IReference>(source.References); enumerator = copy.GetEnumerator(); enumerator.MoveNext(); } do { IReference reference = enumerator.Current; // silently ignore bad values. if (reference == null || NodeId.IsNull(reference.ReferenceTypeId) || NodeId.IsNull(reference.TargetId)) { continue; } // apply browse filters. bool include = ApplyBrowseFilters( reference, continuationPoint.BrowseDirection, continuationPoint.ReferenceTypeId, continuationPoint.IncludeSubtypes); if (include) { ReferenceDescription description = new ReferenceDescription(); description.NodeId = reference.TargetId; description.SetReferenceType(continuationPoint.ResultMask, reference.ReferenceTypeId, !reference.IsInverse); // only fetch the metadata if it is requested. if (continuationPoint.TargetAttributesRequired) { // get the metadata for the node. NodeMetadata metadata = GetNodeMetadata(context, GetManagerHandle(reference.TargetId), continuationPoint.ResultMask); // update description with local node metadata. if (metadata != null) { description.SetTargetAttributes( continuationPoint.ResultMask, metadata.NodeClass, metadata.BrowseName, metadata.DisplayName, metadata.TypeDefinition); // check node class mask. if (!CheckNodeClassMask(continuationPoint.NodeClassMask, description.NodeClass)) { continue; } } // any target that is not remote must be owned by another node manager. else if (!reference.TargetId.IsAbsolute) { description.Unfiltered = true; } } // add reference to list. references.Add(description); // construct continuation point if max results reached. if (maxResultsToReturn > 0 && references.Count >= maxResultsToReturn) { continuationPoint.Index = 0; continuationPoint.Data = enumerator; enumerator.MoveNext(); return; } } } while (enumerator.MoveNext()); // nothing more to browse if it exits from the loop normally. continuationPoint.Dispose(); continuationPoint = null; } }
/// <summary> /// Loops until browse is complete for max results reached. /// </summary> protected ServiceResult FetchReferences( OperationContext context, bool assignContinuationPoint, ref ContinuationPoint cp, ref ReferenceDescriptionCollection references) { Debug.Assert(context != null); Debug.Assert(cp != null); Debug.Assert(references != null); INodeManager nodeManager = cp.Manager; NodeClass nodeClassMask = (NodeClass)cp.NodeClassMask; BrowseResultMask resultMask = cp.ResultMask; // loop until browse is complete or max results. while (cp != null) { // fetch next batch. nodeManager.Browse(context, ref cp, references); ReferenceDescriptionCollection referencesToKeep = new ReferenceDescriptionCollection(references.Count); // check for incomplete reference descriptions. for (int ii = 0; ii < references.Count; ii++) { ReferenceDescription reference = references[ii]; // check if filtering must be applied. if (reference.Unfiltered) { // ignore unknown external references. if (reference.NodeId.IsAbsolute) { continue; } // update the description. bool include = UpdateReferenceDescription( context, (NodeId)reference.NodeId, nodeClassMask, resultMask, reference); if (!include) { continue; } } // add to list. referencesToKeep.Add(reference); } // replace list. references = referencesToKeep; // check if browse limit reached. if (cp != null && references.Count >= cp.MaxResultsToReturn) { if (!assignContinuationPoint) { return StatusCodes.BadNoContinuationPoints; } cp.Id = Guid.NewGuid(); context.Session.SaveContinuationPoint(cp); break; } } // all is good. return ServiceResult.Good; }
/// <summary> /// Returns the set of references that meet the filter criteria. /// </summary> private ServiceResult Browse( OperationContext context, ViewDescription view, uint maxReferencesPerNode, bool assignContinuationPoint, BrowseDescription nodeToBrowse, BrowseResult result) { Debug.Assert(context != null); Debug.Assert(nodeToBrowse != null); Debug.Assert(result != null); // find node manager that owns the node. INodeManager nodeManager = null; object handle = GetManagerHandle(nodeToBrowse.NodeId, out nodeManager); if (handle == null) { return StatusCodes.BadNodeIdUnknown; } if (!NodeId.IsNull(nodeToBrowse.ReferenceTypeId) && !m_server.TypeTree.IsKnown(nodeToBrowse.ReferenceTypeId)) { return StatusCodes.BadReferenceTypeIdInvalid; } if (nodeToBrowse.BrowseDirection < BrowseDirection.Forward || nodeToBrowse.BrowseDirection > BrowseDirection.Both) { return StatusCodes.BadBrowseDirectionInvalid; } // create a continuation point. ContinuationPoint cp = new ContinuationPoint(); cp.Manager = nodeManager; cp.View = view; cp.NodeToBrowse = handle; cp.MaxResultsToReturn = maxReferencesPerNode; cp.BrowseDirection = nodeToBrowse.BrowseDirection; cp.ReferenceTypeId = nodeToBrowse.ReferenceTypeId; cp.IncludeSubtypes = nodeToBrowse.IncludeSubtypes; cp.NodeClassMask = nodeToBrowse.NodeClassMask; cp.ResultMask = (BrowseResultMask)nodeToBrowse.ResultMask; cp.Index = 0; cp.Data = null; // check if reference type left unspecified. if (NodeId.IsNull(cp.ReferenceTypeId)) { cp.ReferenceTypeId = ReferenceTypeIds.References; cp.IncludeSubtypes = true; } // loop until browse is complete or max results. ReferenceDescriptionCollection references = result.References; ServiceResult error = FetchReferences(context, assignContinuationPoint, ref cp, ref references); result.References = references; // save continuation point. if (cp != null) { result.StatusCode = StatusCodes.Good; result.ContinuationPoint = cp.Id.ToByteArray(); } // all is good. return error; }
/// <summary> /// Checks if the node is in the view. /// </summary> protected virtual bool IsNodeInView(ServerSystemContext context, ContinuationPoint continuationPoint, NodeState node) { if (continuationPoint == null || ViewDescription.IsDefault(continuationPoint.View)) { return true; } return IsNodeInView(context, continuationPoint.View.ViewId, node); }