/// <summary> /// Validates the ContentFilter. /// </summary> /// <param name="context">The context.</param> /// <returns>The result of validation.</returns> public Result Validate(FilterContext context) { Result result = new Result(null); // check for empty filter. if (m_elements == null || m_elements.Count == 0) { return result; } bool error = false; for (int ii = 0; ii < m_elements.Count; ii++) { ContentFilterElement element = m_elements[ii]; // check for null. if (element == null) { ServiceResult nullResult = ServiceResult.Create( StatusCodes.BadStructureMissing, "ContentFilterElement is null (Index={0}).", ii); result.ElementResults.Add(new ElementResult(nullResult)); error = true; continue; } element.Parent = this; // validate element. ElementResult elementResult = element.Validate(context, ii); if (ServiceResult.IsBad(elementResult.Status)) { result.ElementResults.Add(elementResult); error = true; continue; } result.ElementResults.Add(null); } // ensure the global error code. if (error) { result.Status = StatusCodes.BadContentFilterInvalid; } else { result.ElementResults.Clear(); } return result; }
/// <summary> /// Returns true if the snapshort is an instance of the specified type. /// </summary> /// <param name="context">The context to use when checking the type definition.</param> /// <param name="typeDefinitionId">The type of the instance.</param> /// <returns> /// True if the object is an instance of the specified type. /// </returns> public bool IsTypeOf(FilterContext context, NodeId typeDefinitionId) { if (!NodeId.IsNull(typeDefinitionId)) { if (!context.TypeTree.IsTypeOf(m_typeDefinitionId, typeDefinitionId)) { return false; } } return true; }
/// <summary> /// Evaluates the first element in the ContentFilter. If the first or any /// subsequent element has dependent elements, the dependent elements are /// evaluated before the root element (recursive descent). Elements which /// are not linked (directly or indirectly) to the first element will not /// be evaluated (they have no influence on the result). /// </summary> /// <param name="context">The context to use when evaluating the filter.</param> /// <param name="target">The target to use when evaluating elements that reference the type model.</param> /// <returns>Returns true, false or null.</returns> public bool Evaluate(FilterContext context, IFilterTarget target) { // check if nothing to do. if (this.Elements.Count == 0) { return true; } bool? result = Evaluate(context, target, 0) as bool?; if (result == null) { return false; } return result.Value; }
/// <summary> /// Creates a new history request. /// </summary> private HistoryReadRequest CreateHistoryReadRequest( ServerSystemContext context, ReadEventDetails details, NodeHandle handle, HistoryReadValueId nodeToRead) { FilterContext filterContext = new FilterContext(context.NamespaceUris, context.TypeTable, context.PreferredLocales); LinkedList<BaseEventState> events = new LinkedList<BaseEventState>(); for (ReportType ii = ReportType.FluidLevelTest; ii <= ReportType.InjectionTest; ii++) { DataView view = null; if (handle.Node is WellState) { view = m_generator.ReadHistoryForWellId( ii, (string)handle.Node.NodeId.Identifier, details.StartTime, details.EndTime); } else { view = m_generator.ReadHistoryForArea( ii, handle.Node.NodeId.Identifier as string, details.StartTime, details.EndTime); } LinkedListNode<BaseEventState> pos = events.First; bool sizeLimited = (details.StartTime == DateTime.MinValue || details.EndTime == DateTime.MinValue); foreach (DataRowView row in view) { // check if reached max results. if (sizeLimited) { if (events.Count >= details.NumValuesPerNode) { break; } } BaseEventState e = m_generator.GetReport(context, NamespaceIndex, ii, row.Row); if (details.Filter.WhereClause != null && details.Filter.WhereClause.Elements.Count > 0) { if (!details.Filter.WhereClause.Evaluate(filterContext, e)) { continue; } } bool inserted = false; for (LinkedListNode<BaseEventState> jj = pos; jj != null; jj = jj.Next) { if (jj.Value.Time.Value > e.Time.Value) { events.AddBefore(jj, e); pos = jj; inserted = true; break; } } if (!inserted) { events.AddLast(e); pos = null; } } } HistoryReadRequest request = new HistoryReadRequest(); request.Events = events; request.TimeFlowsBackward = details.StartTime == DateTime.MinValue || (details.EndTime != DateTime.MinValue && details.EndTime < details.StartTime); request.NumValuesPerNode = details.NumValuesPerNode; request.Filter = details.Filter; request.FilterContext = filterContext; return request; }
/// <summary> /// Cast FilterOperator /// </summary> private object Cast(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 2); // get the value to cast. object value = GetValue(context, operands[0], target); if (value == null) { return null; } // get the datatype to cast to. NodeId datatype = GetValue(context, operands[1], target) as NodeId; if (datatype == null) { return null; } BuiltInType targetType = GetBuiltInType(datatype); // cast the value. return Cast(value, targetType); }
/// <summary> /// Creates an operand that references a component/property of a type. /// </summary> public SimpleAttributeOperand( FilterContext context, ExpandedNodeId typeId, IList<QualifiedName> browsePath) { m_typeDefinitionId = ExpandedNodeId.ToNodeId(typeId, context.NamespaceUris); m_browsePath = new QualifiedNameCollection(browsePath); m_attributeId = Attributes.Value; m_indexRange = null; }
/// <summary> /// Between FilterOperator /// </summary> private bool? Between(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 3); object value = GetValue(context, operands[0], target); object min = GetValue(context, operands[1], target); object max = GetValue(context, operands[2], target); // the min and max could be different data types so the implicit conversion must be done twice. object lhs = value; DoImplicitConversion(ref lhs, ref min); bool? result = null; if (lhs is IComparable && min is IComparable) { // check if never in range no matter what happens with the upper bound. if (((IComparable)lhs).CompareTo(min) < 0) { return false; } result = true; } lhs = value; DoImplicitConversion(ref lhs, ref max); if (lhs is IComparable && max is IComparable) { // check if never in range no matter what happens with the lower bound. if (((IComparable)lhs).CompareTo(max) > 0) { return false; } // can't determine if in range if lower bound could not be resolved. return result != null; } // return null if the types are not comparable. return null; }
/// <summary> /// Like FilterOperator /// </summary> private bool Like(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 2); object firstOperand = GetValue(context, operands[0], target); string lhs; LocalizedText firstOperandLocalizedText = firstOperand as LocalizedText; if (firstOperandLocalizedText != null) { lhs = firstOperandLocalizedText.Text; } else { lhs = firstOperand as string; } object secondOperand = GetValue(context, operands[1], target); string rhs; LocalizedText secondOperandLocalizedText = secondOperand as LocalizedText; if (secondOperandLocalizedText != null) { rhs = secondOperandLocalizedText.Text; } else { rhs = secondOperand as string; } // this operator requires strings. if (lhs == null || rhs == null) { return false; } return Match((string)lhs, (string)rhs); }
/// <summary> /// Validates the operand (sets the ParsedBrowsePath and ParsedIndexRange properties). /// </summary> /// <param name="context">The context.</param> /// <param name="index">The index.</param> /// <returns>The result of the validation.</returns> public override ServiceResult Validate(FilterContext context, int index) { m_validated = false; // verify that the operand refers to a node in the type model. if (!context.TypeTree.IsKnown(m_nodeId)) { return ServiceResult.Create( StatusCodes.BadTypeDefinitionInvalid, "AttributeOperand does not have a known TypeDefinitionId ({0}).", m_nodeId); } // verify attribute id. if (!Attributes.IsValid(m_attributeId)) { return ServiceResult.Create( StatusCodes.BadAttributeIdInvalid, "AttributeOperand does not specify a valid AttributeId ({0}).", m_attributeId); } // initialize as empty. m_parsedIndexRange = NumericRange.Empty; // parse the index range. if (!String.IsNullOrEmpty(m_indexRange)) { try { m_parsedIndexRange = NumericRange.Parse(m_indexRange); } catch (Exception e) { return ServiceResult.Create( e, StatusCodes.BadIndexRangeInvalid, "AttributeOperand does not specify a valid BrowsePath ({0}).", m_indexRange); } if (m_attributeId != Attributes.Value) { return ServiceResult.Create( StatusCodes.BadIndexRangeInvalid, "AttributeOperand specifies an IndexRange for an Attribute other than Value ({0}).", m_attributeId); } } m_validated = true; return ServiceResult.Good; }
/// <summary> /// Equals FilterOperator /// </summary> private bool Equals(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 2); object lhs = GetValue(context, operands[0], target); object rhs = GetValue(context, operands[1], target); DoImplicitConversion(ref lhs, ref rhs); return IsEqual(lhs, rhs); }
/// <summary> /// Validates the object. /// </summary> public Result Validate(FilterContext context) { Result result = new Result(); // check for top level error. if (m_selectClauses == null || m_selectClauses.Count == 0) { result.Status = ServiceResult.Create( StatusCodes.BadStructureMissing, "EventFilter does not specify any Select Clauses."); return(result); } if (m_whereClause == null) { result.Status = ServiceResult.Create( StatusCodes.BadStructureMissing, "EventFilter does not specify any Where Clauses."); return(result); } result.Status = ServiceResult.Good; // validate select clause. bool error = false; foreach (SimpleAttributeOperand clause in m_selectClauses) { ServiceResult clauseResult = null; // check for null. if (clause == null) { clauseResult = ServiceResult.Create( StatusCodes.BadStructureMissing, "EventFilterSelectClause cannot be null in EventFilter SelectClause."); result.SelectClauseResults.Add(clauseResult); error = true; continue; } // validate clause. clauseResult = clause.Validate(context, 0); if (ServiceResult.IsBad(clauseResult)) { result.SelectClauseResults.Add(clauseResult); error = true; continue; } // clause ok. result.SelectClauseResults.Add(null); } if (error) { result.Status = StatusCodes.BadEventFilterInvalid; } else { result.SelectClauseResults.Clear(); } // validate where clause. result.WhereClauseResult = m_whereClause.Validate(context); if (ServiceResult.IsBad(result.WhereClauseResult.Status)) { result.Status = StatusCodes.BadEventFilterInvalid; } return(result); }
/// <summary cref="IFilterTarget.GetAttributeValue" /> public virtual object GetAttributeValue( FilterContext context, NodeId typeDefinitionId, IList<QualifiedName> relativePath, uint attributeId, NumericRange indexRange) { // check the type definition. if (!NodeId.IsNull(typeDefinitionId) && typeDefinitionId != ObjectTypes.BaseEventType) { if (!context.TypeTree.IsTypeOf(TypeDefinitionId, typeDefinitionId)) { return null; } } // read the child attribute. DataValue dataValue = new DataValue(); ServiceResult result = ReadChildAttribute( null, relativePath, 0, attributeId, dataValue); if (ServiceResult.IsBad(result)) { return null; } // apply any index range. object value = dataValue.Value; if (value != null) { result = indexRange.ApplyRange(ref value); if (ServiceResult.IsBad(result)) { return null; } } // return the result. return value; }
/// <summary> /// Validates the operand. /// </summary> /// <param name="context">The context.</param> /// <param name="index">The index.</param> /// <returns>the result of the validation</returns> public virtual ServiceResult Validate(FilterContext context, int index) { return(ServiceResult.Create(StatusCodes.BadEventFilterInvalid, "A sub-class of FilterOperand must be specified.")); }
/// <summary> /// Validates the content filter element. /// </summary> /// <param name="context">The context.</param> /// <param name="index">The index.</param> /// <returns>The results of the validation.</returns> public virtual ContentFilter.ElementResult Validate(FilterContext context, int index) { ContentFilter.ElementResult result = new ContentFilter.ElementResult(null); // check the number of operands. int operandCount = -1; switch (m_filterOperator) { case FilterOperator.Not: case FilterOperator.IsNull: case FilterOperator.InView: case FilterOperator.OfType: { operandCount = 1; break; } case FilterOperator.And: case FilterOperator.Or: case FilterOperator.Equals: case FilterOperator.GreaterThan: case FilterOperator.GreaterThanOrEqual: case FilterOperator.LessThan: case FilterOperator.LessThanOrEqual: case FilterOperator.Like: case FilterOperator.Cast: { operandCount = 2; break; } case FilterOperator.Between: { operandCount = 3; break; } case FilterOperator.RelatedTo: { operandCount = 4; break; } case FilterOperator.InList: { operandCount = -1; break; } default: { break; } } if (operandCount != -1) { if (operandCount != m_filterOperands.Count) { result.Status = ServiceResult.Create( StatusCodes.BadEventFilterInvalid, "ContentFilterElement does not have the correct number of operands (Operator={0} OperandCount={1}).", m_filterOperator, operandCount); return(result); } } else { if (m_filterOperands.Count < 2) { result.Status = ServiceResult.Create( StatusCodes.BadEventFilterInvalid, "ContentFilterElement does not have the correct number of operands (Operator={0} OperandCount={1}).", m_filterOperator, m_filterOperands.Count); return(result); } } // validate the operands. bool error = false; for (int ii = 0; ii < m_filterOperands.Count; ii++) { ServiceResult operandResult = null; ExtensionObject operand = m_filterOperands[ii]; // check for null. if (ExtensionObject.IsNull(operand)) { operandResult = ServiceResult.Create( StatusCodes.BadEventFilterInvalid, "The FilterOperand cannot be Null."); result.OperandResults.Add(operandResult); error = true; continue; } // check that the extension object contains a filter operand. FilterOperand filterOperand = operand.Body as FilterOperand; if (filterOperand == null) { operandResult = ServiceResult.Create( StatusCodes.BadEventFilterInvalid, "The FilterOperand is not a supported type ({0}).", filterOperand.GetType()); result.OperandResults.Add(operandResult); error = true; continue; } // validate the operand. filterOperand.Parent = this; operandResult = filterOperand.Validate(context, index); if (ServiceResult.IsBad(operandResult)) { result.OperandResults.Add(operandResult); error = true; continue; } result.OperandResults.Add(null); } // ensure the global error code. if (error) { result.Status = StatusCodes.BadContentFilterInvalid; } else { result.OperandResults.Clear(); } return(result); }
/// <summary> /// Creates an operand that references a component/property of a type. /// </summary> public SimpleAttributeOperand( FilterContext context, ExpandedNodeId typeDefinitionId, string browsePath, uint attributeId, string indexRange) { m_typeDefinitionId = ExpandedNodeId.ToNodeId(typeDefinitionId, context.NamespaceUris); m_browsePath = Parse(browsePath); m_attributeId = attributeId; m_indexRange = indexRange; }
/// <summary> /// Or FilterOperator /// </summary> private bool? Or(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 2); bool? lhs = GetValue(context, operands[0], target) as bool?; // no need for further processing if first operand is true. if (lhs != null && lhs.Value) { return true; } bool? rhs = GetValue(context, operands[1], target) as bool?; if (lhs == null) { if (rhs == null || rhs == false) { return null; } else { return true; } } if (rhs == null) { if (lhs == null || lhs == false) { return null; } else { return true; } } return lhs.Value || rhs.Value; }
/// <summary> /// Validates the operand. /// </summary> /// <param name="context">The context.</param> /// <param name="index">The index.</param> /// <returns>The result of the validation</returns> public override ServiceResult Validate(FilterContext context, int index) { if (m_index < 0) { return ServiceResult.Create( StatusCodes.BadFilterOperandInvalid, "ElementOperand specifies an Index that is less than zero ({0}).", m_index); } if (m_index <= index) { return ServiceResult.Create( StatusCodes.BadFilterOperandInvalid, "ElementOperand references an element that precedes it in the ContentFilter.", m_index); } if (m_index >= Parent.Parent.Elements.Count) { return ServiceResult.Create( StatusCodes.BadFilterOperandInvalid, "ElementOperand references an element that does not exist.", m_index); } return ServiceResult.Good; }
/// <summary> /// Not FilterOperator /// </summary> private bool? Not(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 1); bool? rhs = GetValue(context, operands[0], target) as bool?; if (rhs == null) { return null; } return !rhs.Value; }
/// <summary> /// Validates the operand. /// </summary> /// <param name="context">The context.</param> /// <param name="index">The index.</param> /// <returns>The result of the validation</returns> public override ServiceResult Validate(FilterContext context, int index) { if (m_value.Value == null) { return ServiceResult.Create( StatusCodes.BadEventFilterInvalid, "LiteralOperand specifies a null Value."); } return ServiceResult.Good; }
/// <summary> /// LessThanOrEqual FilterOperator /// </summary> private bool? LessThanOrEqual(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 2); object lhs = GetValue(context, operands[0], target); object rhs = GetValue(context, operands[1], target); DoImplicitConversion(ref lhs, ref rhs); if (lhs is IComparable && rhs is IComparable) { return ((IComparable)lhs).CompareTo(rhs) <= 0; } // return null if the types are not comparable. return null; }
/// <summary> /// Validates the content filter element. /// </summary> /// <param name="context">The context.</param> /// <param name="index">The index.</param> /// <returns>The results of the validation.</returns> public virtual ContentFilter.ElementResult Validate(FilterContext context, int index) { ContentFilter.ElementResult result = new ContentFilter.ElementResult(null); // check the number of operands. int operandCount = -1; switch (m_filterOperator) { case FilterOperator.Not: case FilterOperator.IsNull: case FilterOperator.InView: case FilterOperator.OfType: { operandCount = 1; break; } case FilterOperator.And: case FilterOperator.Or: case FilterOperator.Equals: case FilterOperator.GreaterThan: case FilterOperator.GreaterThanOrEqual: case FilterOperator.LessThan: case FilterOperator.LessThanOrEqual: case FilterOperator.Like: case FilterOperator.Cast: { operandCount = 2; break; } case FilterOperator.Between: { operandCount = 3; break; } case FilterOperator.RelatedTo: { operandCount = 6; break; } case FilterOperator.InList: { operandCount = -1; break; } default: { break; } } if (operandCount != -1) { if (operandCount != m_filterOperands.Count) { result.Status = ServiceResult.Create( StatusCodes.BadEventFilterInvalid, "ContentFilterElement does not have the correct number of operands (Operator={0} OperandCount={1}).", m_filterOperator, operandCount); return result; } } else { if (m_filterOperands.Count < 2) { result.Status = ServiceResult.Create( StatusCodes.BadEventFilterInvalid, "ContentFilterElement does not have the correct number of operands (Operator={0} OperandCount={1}).", m_filterOperator, m_filterOperands.Count); return result; } } // validate the operands. bool error = false; for (int ii = 0; ii < m_filterOperands.Count; ii++) { ServiceResult operandResult = null; ExtensionObject operand = m_filterOperands[ii]; // check for null. if (ExtensionObject.IsNull(operand)) { operandResult = ServiceResult.Create( StatusCodes.BadEventFilterInvalid, "The FilterOperand cannot be Null."); result.OperandResults.Add(operandResult); error = true; continue; } // check that the extension object contains a filter operand. FilterOperand filterOperand = operand.Body as FilterOperand; if (filterOperand == null) { operandResult = ServiceResult.Create( StatusCodes.BadEventFilterInvalid, "The FilterOperand is not a supported type ({0}).", filterOperand.GetType()); result.OperandResults.Add(operandResult); error = true; continue; } // validate the operand. filterOperand.Parent = this; operandResult = filterOperand.Validate(context, index); if (ServiceResult.IsBad(operandResult)) { result.OperandResults.Add(operandResult); error = true; continue; } result.OperandResults.Add(null); } // ensure the global error code. if (error) { result.Status = StatusCodes.BadContentFilterInvalid; } else { result.OperandResults.Clear(); } return result; }
/// <summary> /// InList FilterOperator /// </summary> private bool? InList(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 0); object value = GetValue(context, operands[0], target); // check for a match. for (int ii = 1; ii < operands.Length; ii++) { object lhs = value; object rhs = GetValue(context, operands[ii], target); DoImplicitConversion(ref lhs, ref rhs); if (IsEqual(lhs, rhs)) { return true; } } // no match. return false; }
/// <summary> /// OfType FilterOperator /// </summary> private bool OfType(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 1); // get the desired type. NodeId typeDefinitionId = GetValue(context, operands[0], target) as NodeId; if (typeDefinitionId == null || target == null) { return false; } // check the type. try { return target.IsTypeOf(context, typeDefinitionId); } catch { return false; } }
/// <summary> /// IsNull FilterOperator /// </summary> private bool IsNull(FilterContext context, IFilterTarget target, ContentFilterElement element) { FilterOperand[] operands = GetOperands(element, 1); object rhs = GetValue(context, operands[0], target); if (rhs == null) { return true; } return false; }
/// <summary> /// RelatedTo FilterOperator /// </summary> private bool RelatedTo(FilterContext context, IFilterTarget target, ContentFilterElement element) { return RelatedTo(context, target, element, null); }
/// <summary> /// Returns the value for the element. /// </summary> private object GetValue(FilterContext context, FilterOperand operand, IFilterTarget target) { // return the contained value for literal operands. LiteralOperand literal = operand as LiteralOperand; if (literal != null) { return literal.Value.Value; } // must query the filter target for simple attribute operands. SimpleAttributeOperand simpleAttribute = operand as SimpleAttributeOperand; if (simpleAttribute != null) { return target.GetAttributeValue( context, simpleAttribute.TypeDefinitionId, simpleAttribute.BrowsePath, simpleAttribute.AttributeId, simpleAttribute.ParsedIndexRange); } // must query the filter target for attribute operands. AttributeOperand attribute = operand as AttributeOperand; if (attribute != null) { // AttributeOperands only supported in advanced filter targets. IAdvancedFilterTarget advancedTarget = target as IAdvancedFilterTarget; if (advancedTarget == null) { return false; } return advancedTarget.GetRelatedAttributeValue( context, attribute.NodeId, attribute.BrowsePath, attribute.AttributeId, attribute.ParsedIndexRange); } // recursively evaluate element operands. ElementOperand element = operand as ElementOperand; if (element != null) { return Evaluate(context, target, (int)element.Index); } // oops - Validate() was not called. throw new ServiceResultException(StatusCodes.BadUnexpectedError, "FilterOperand is not supported."); }
/// <summary> /// Validates the object. /// </summary> public Result Validate(FilterContext context) { Result result = new Result(); // check for top level error. if (m_selectClauses == null || m_selectClauses.Count == 0) { result.Status = ServiceResult.Create( StatusCodes.BadStructureMissing, "EventFilter does not specify any Select Clauses."); return result; } if (m_whereClause == null) { result.Status = ServiceResult.Create( StatusCodes.BadStructureMissing, "EventFilter does not specify any Where Clauses."); return result; } result.Status = ServiceResult.Good; // validate select clause. bool error = false; foreach (SimpleAttributeOperand clause in m_selectClauses) { ServiceResult clauseResult = null; // check for null. if (clause == null) { clauseResult = ServiceResult.Create( StatusCodes.BadStructureMissing, "EventFilterSelectClause cannot be null in EventFilter SelectClause."); result.SelectClauseResults.Add(clauseResult); error = true; continue; } // validate clause. clauseResult = clause.Validate(context, 0); if (ServiceResult.IsBad(clauseResult)) { result.SelectClauseResults.Add(clauseResult); error = true; continue; } // clause ok. result.SelectClauseResults.Add(null); } if (error) { result.Status = StatusCodes.BadEventFilterInvalid; } else { result.SelectClauseResults.Clear(); } // validate where clause. result.WhereClauseResult = m_whereClause.Validate(context); if (ServiceResult.IsBad(result.WhereClauseResult.Status)) { result.Status = StatusCodes.BadEventFilterInvalid; } return result; }
/// <summary> /// InView FilterOperator /// </summary> private bool InView(FilterContext context, IFilterTarget target, ContentFilterElement element) { // views only supported in advanced filter targets. IAdvancedFilterTarget advancedFilter = target as IAdvancedFilterTarget; if (advancedFilter == null) { return false; } FilterOperand[] operands = GetOperands(element, 1); // get the desired type. NodeId viewId = GetValue(context, operands[0], target) as NodeId; if (viewId == null || target == null) { return false; } // check the target. try { return advancedFilter.IsInView(context, viewId); } catch { return false; } }
/// <summary> /// Validates the operand. /// </summary> /// <param name="context">The context.</param> /// <param name="index">The index.</param> /// <returns>the result of the validation</returns> public virtual ServiceResult Validate(FilterContext context, int index) { return ServiceResult.Create(StatusCodes.BadEventFilterInvalid, "A sub-class of FilterOperand must be specified."); }
/// <summary> /// RelatedTo FilterOperator /// </summary> private bool RelatedTo(FilterContext context, IFilterTarget target, ContentFilterElement element, NodeId intermediateNodeId) { // RelatedTo only supported in advanced filter targets. IAdvancedFilterTarget advancedTarget = target as IAdvancedFilterTarget; if (advancedTarget == null) { return false; } FilterOperand[] operands = GetOperands(element, 6); // get the type of the source. NodeId sourceTypeId = GetValue(context, operands[0], target) as NodeId; if (sourceTypeId == null) { return false; } // get the type of reference to follow. NodeId referenceTypeId = GetValue(context, operands[2], target) as NodeId; if (referenceTypeId == null) { return false; } // get the number of hops int? hops = 1; object hopsValue = GetValue(context, operands[3], target); if (hopsValue != null) { hops = Cast(hopsValue, BuiltInType.Int32) as int?; if (hops == null) { hops = 1; } } // get whether to include type definition subtypes. bool? includeTypeDefinitionSubtypes = true; object includeValue = GetValue(context, operands[4], target); if (includeValue != null) { includeTypeDefinitionSubtypes = Cast(includeValue, BuiltInType.Boolean) as bool?; if (includeTypeDefinitionSubtypes == null) { includeTypeDefinitionSubtypes = true; } } // get whether to include reference type subtypes. bool? includeReferenceTypeSubtypes = true; includeValue = GetValue(context, operands[5], target); if (includeValue != null) { includeReferenceTypeSubtypes = Cast(includeValue, BuiltInType.Boolean) as bool?; if (includeReferenceTypeSubtypes == null) { includeReferenceTypeSubtypes = true; } } NodeId targetTypeId = null; // check if elements are chained. ElementOperand chainedOperand = operands[1] as ElementOperand; if (chainedOperand != null) { if (chainedOperand.Index < 0 || chainedOperand.Index >= Elements.Count) { return false; } ContentFilterElement chainedElement = Elements[(int)chainedOperand.Index]; // get the target type from the first operand of the chained element. if (chainedElement.FilterOperator == FilterOperator.RelatedTo) { FilterOperand nestedType = ExtensionObject.ToEncodeable(chainedElement.FilterOperands[0]) as FilterOperand; targetTypeId = GetValue(context, nestedType, target) as NodeId; if (targetTypeId == null) { return false; } // find the nodes that meet the criteria in the first link of the chain. IList<NodeId> nodeIds = advancedTarget.GetRelatedNodes( context, intermediateNodeId, sourceTypeId, targetTypeId, referenceTypeId, hops.Value, includeTypeDefinitionSubtypes.Value, includeReferenceTypeSubtypes.Value); if (nodeIds == null || nodeIds.Count == 0) { return false; } // recursively follow the chain. for (int ii = 0; ii < nodeIds.Count; ii++) { // one match is all that is required. if (RelatedTo(context, target, chainedElement, nodeIds[ii])) { return true; } } // no matches. return false; } } // get the type of the target. if (targetTypeId == null) { targetTypeId = GetValue(context, operands[1], target) as NodeId; if (targetTypeId == null) { return false; } } // check the target. try { bool relatedTo = advancedTarget.IsRelatedTo( context, intermediateNodeId, sourceTypeId, targetTypeId, referenceTypeId, hops.Value, includeTypeDefinitionSubtypes.Value, includeReferenceTypeSubtypes.Value); return relatedTo; } catch { return false; } }
/// <summary> /// Creates an operand that references a component/property of a type. /// </summary> /// <param name="context">The context.</param> /// <param name="nodeId">The node identifier.</param> /// <param name="relativePath">The relative path.</param> public AttributeOperand( FilterContext context, ExpandedNodeId nodeId, RelativePath relativePath) { m_nodeId = ExpandedNodeId.ToNodeId(nodeId, context.NamespaceUris); m_browsePath = relativePath; m_attributeId = Attributes.Value; m_indexRange = null; m_alias = null; }
/// <summary> /// Evaluates element at the specified index. /// </summary> private object Evaluate(FilterContext context, IFilterTarget target, int index) { // get the element to evaluate. ContentFilterElement element = Elements[index]; switch (element.FilterOperator) { case FilterOperator.And: { return And(context, target, element); } case FilterOperator.Or: { return Or(context, target, element); } case FilterOperator.Not: { return Not(context, target, element); } case FilterOperator.Equals: { return Equals(context, target, element); } case FilterOperator.GreaterThan: { return GreaterThan(context, target, element); } case FilterOperator.GreaterThanOrEqual: { return GreaterThanOrEqual(context, target, element); } case FilterOperator.LessThan: { return LessThan(context, target, element); } case FilterOperator.LessThanOrEqual: { return LessThanOrEqual(context, target, element); } case FilterOperator.Between: { return Between(context, target, element); } case FilterOperator.InList: { return InList(context, target, element); } case FilterOperator.Like: { return Like(context, target, element); } case FilterOperator.IsNull: { return IsNull(context, target, element); } case FilterOperator.Cast: { return Cast(context, target, element); } case FilterOperator.OfType: { return OfType(context, target, element); } case FilterOperator.InView: { return InView(context, target, element); } case FilterOperator.RelatedTo: { return RelatedTo(context, target, element); } } throw new ServiceResultException(StatusCodes.BadUnexpectedError, "FilterOperator is not recognized."); }
/// <summary> /// Creates an operand that references a component/property of a type. /// </summary> /// <param name="context">The context.</param> /// <param name="typeDefinitionId">The type definition identifier.</param> /// <param name="browsePath">The browse path.</param> /// <param name="attributeId">The attribute identifier.</param> /// <param name="indexRange">The index range.</param> public AttributeOperand( FilterContext context, ExpandedNodeId typeDefinitionId, string browsePath, uint attributeId, string indexRange) { m_nodeId = ExpandedNodeId.ToNodeId(typeDefinitionId, context.NamespaceUris); m_browsePath = RelativePath.Parse(browsePath, context.TypeTree); m_attributeId = attributeId; m_indexRange = indexRange; m_alias = null; }