Imports System.Data.OleDb
Imports System.Threading
Imports System.Xml.XPath
Imports System.Xml
Public Class TemplateFields
Implements IEnumerable(Of TemplateField)
Private _fields As List(Of TemplateField)
Friend Sub New()
_fields = New List(Of TemplateField)
End Sub
Friend Sub Add(ByVal field As TemplateField)
_fields.Add(field)
End Sub
Friend Sub add(ByVal field As FieldCondition, ByVal attribute As String)
_fields.Add(New TemplateField(field, attribute))
End Sub
Friend Sub add(ByVal field As FieldCondition, ByVal attribute As String, ByVal hasCondition As Boolean)
_fields.Add(New TemplateField(field, attribute, hasCondition))
End Sub
Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of TemplateField) Implements System.Collections.Generic.IEnumerable(Of TemplateField).GetEnumerator
Return _fields.GetEnumerator
End Function
Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return _fields.GetEnumerator
End Function
End Class
Public Class TemplateField
Private _field As ValueFieldCondition
Private _attribute As String
Private _has_condition As Boolean
Friend Sub New(ByVal field As ValueFieldCondition, ByVal attribute As String)
Me.New(field, attribute, False)
End Sub
Friend Sub New(ByVal field As ValueFieldCondition, ByVal attribute As String, ByVal hasCondition As Boolean)
_field = field
_attribute = attribute
_has_condition = hasCondition
End Sub
Public ReadOnly Property Field() As ValueFieldCondition
Get
Return _field
End Get
End Property
Public ReadOnly Property Attribute() As String
Get
Return _attribute
End Get
End Property
Public ReadOnly Property HasCondition() As Boolean
Get
Return _has_condition
End Get
End Property
''' <summary>
''' Value as it is given in the XML schema, not evaluated.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property OriginalValue() As String
Get
Return _field.Value
End Get
End Property
''' <summary>
''' Value evaluated from expression given in the schema.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property Value() As String
Get
Return _field.SecondValue
End Get
End Property
End Class
''' <summary>
''' Class makes it possible to create custom validations against external data sources (oledb connection).
''' </summary>
''' <remarks>Rule object is created from template file.</remarks>
Public Class CustomQueryTemplate
Private _name As String
Private _messages As Collection
Private _template_fields As TemplateFields
Private _parent As QueryChecker
Public Sub New(ByVal queryName As String, ByVal parent As QueryChecker)
_parent = parent
_template_fields = New TemplateFields
_name = queryName
Me.GetMessages(parent.Template)
Dim iterator As XPathNodeIterator
Dim fieldNavigator As XPathNavigator
' Set Table name of the Query Checker
iterator = parent.Template.CreateNavigator.Select("Templates/Template[@Name='" & queryName & "']/Source/From")
For Each fieldNavigator In iterator
_parent.TableName = fieldNavigator.InnerXml
Next
' Add relevant fields
iterator = parent.Template.CreateNavigator.Select("Templates/Template[@Name='" & queryName & "']/Source/WhereFields/*[not(@Attribute)]")
For Each fieldNavigator In iterator
_parent.AddField(fieldNavigator)
Next
End Sub
Public ReadOnly Property Fields() As TemplateFields
Get
Return _template_fields
End Get
End Property
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
''' <summary>
''' Initates new Query Template from Xml definition
''' </summary>
''' <param name="definition">Template definition.</param>
''' <param name="parent">Query validation rule that uses the template.</param>
''' <remarks></remarks>
Public Sub New(ByVal definition As IXPathNavigable, ByVal parent As QueryChecker)
_parent = parent
_template_fields = New TemplateFields
' This should be single a node with several attributes.
Dim navigator As XPathNavigator = definition.CreateNavigator
_name = navigator.LocalName
Me.GetMessages(parent.Template)
Dim iterator As XPathNodeIterator = parent.Template.CreateNavigator.Select("Templates/Template[@Name='" & _name & "']/Source")
Select Case iterator.Count ' Number of templates for specified template & name
Case 1 ' There is only one, so we are happy to proceed.
iterator.MoveNext() ' Get to the first record
Dim templateNavigator As XPathNavigator
templateNavigator = iterator.Current() ' get navigator (we are at Source level of the template)
Dim fromNavigator As XPathNavigator = templateNavigator.CreateNavigator()
fromNavigator.MoveToChild("From", "")
parent.TableName = fromNavigator.InnerXml ' Get table or join clause name
Dim fieldsIterator As XPathNodeIterator = templateNavigator.Select("WhereFields/*")
Dim fieldNavigator As XPathNavigator
Dim attributeName As String ' this is an attribute name
Dim field As FieldCondition
For Each fieldNavigator In fieldsIterator
attributeName = fieldNavigator.GetAttribute("Attribute", "")
If String.IsNullOrEmpty(attributeName) Then
parent.AddField(fieldNavigator)
Else
Dim templateAttribute As XPathNavigator = navigator.CreateNavigator
If templateAttribute.MoveToAttribute(attributeName, "") Then
' Parameter value provided in the node.
' ie: <Contact Surname="Smith" />
field = New ValueFieldCondition(fieldNavigator, parent, navigator.GetAttribute(attributeName, ""))
' there is an attribute with a name from template in our schema. now we are ready to add the field.
parent.AddField(field)
_template_fields.Add(New TemplateField(field, attributeName, True))
Else ' Check wehter there is a node with parameter definition
'
' If condition is not provided in the template then parameter value
' should be provided in the separate node
' ie: <Contact><Parameter Name="Surname" Value="Smith" Condition="=" /></Contact>
'
Dim paramIterator As XPathNodeIterator = navigator.Select("Parameter[@Name='" & attributeName & "']")
Dim paramNavigator As XPathNavigator
If paramIterator.Count = 1 Then
For Each paramNavigator In paramIterator
Dim paramValue As String = paramNavigator.GetAttribute("Value", "")
Dim paramCondition As EnumOperator = Condition.GetOperatorType(paramNavigator.GetAttribute("Condition", ""), paramValue)
field = New ValueFieldCondition(fieldNavigator, parent, paramValue, paramCondition)
parent.AddField(field)
_template_fields.Add(field, attributeName)
Next
End If
' ok there is no attribute with this name. That just means that we don't add these field to the rule.
End If
End If
Next
Case 0
Throw New XmlException("Template: " & _name & " not found for the template:" & Me._parent.Template.Name)
Case Else
Throw New XmlException("Several templates with the same name: " & _name & " for the template:" & _parent.Template.Name)
End Select
End Sub
Friend Sub AddField(ByVal queryName As String, ByVal attributeName As String, ByVal value As String, ByVal cond As EnumOperator)
Dim iterator As XPathNodeIterator = _parent.Template.CreateNavigator.Select("Templates/Template[@Name='" & queryName & "']/Source/WhereFields/ValueField[@Attribute='" & attributeName & "']")
If iterator.Count = 1 Then
iterator.MoveNext()
Dim fieldNavigator As XPathNavigator = iterator.Current
Dim field As ValueFieldCondition = New ValueFieldCondition(fieldNavigator, _parent, value, cond)
Dim cc As String = fieldNavigator.GetAttribute("Condition", "")
Dim hasCondition As Boolean = Not String.IsNullOrEmpty(cc)
' there is an attribute with a name from template in our schema. now we are ready to add the field.
_parent.AddField(field)
_template_fields.Add(field, attributeName, hasCondition)
Else
Throw New XmlException("There must be one node where template name: " & Me.Template.Name & " and Attribute: " & attributeName)
End If
End Sub
Friend Function GetNode() As System.Xml.XmlNode
Dim customXml As XmlElement = _parent.Document.CreateElement(_name)
Dim field As TemplateField
For Each field In Me._template_fields
If field.HasCondition Then
' Condition is set in the template
' so value can be provided in-line in the same node
XmlNodeAppendAttribute(customXml, field.Attribute, field.Value)
Else ' Condition is not set in the tempalte
' so child node should be created
Dim parameterXml As XmlElement = _parent.Document.CreateElement("Parameter")
XmlNodeAppendAttribute(parameterXml, "Name", field.Attribute)
If Not String.IsNullOrEmpty(field.OriginalValue) Then
XmlNodeAppendAttribute(parameterXml, "Value", field.OriginalValue)
End If
XmlNodeAppendAttribute(parameterXml, "Condition", Condition.GetOperatorType(field.Field.Condition))
customXml.AppendChild(parameterXml)
End If
Next
Return customXml
End Function
Private Sub GetMessages(ByVal template As IXPathNavigable)
Dim navigator As XPathNavigator = template.CreateNavigator
Dim iterator As XPathNodeIterator
If _messages Is Nothing Then _messages = New Collection
iterator = navigator.Select("Templates/Template[@Name='" & _name & "']/Messages/*")
While iterator.MoveNext
navigator = iterator.Current
If _messages.Count > 0 AndAlso _messages.Contains(navigator.LocalName) Then
_messages.Remove(navigator.LocalName)
End If
_messages.Add(navigator.InnerXml, navigator.LocalName)
End While
End Sub
Public ReadOnly Property DataRuleMessage() As String
Get
Dim message As String
Select Case _parent.Cardinality
Case CardinalityType.Exists
message = CStr(Me._messages("Exists"))
Case CardinalityType.Condition
message = CStr(Me._messages("Cardinality"))
Case CardinalityType.NotExists
message = CStr(Me._messages("NotExists"))
Case Else
message = "Wrong type of query rule."
End Select
message &= "("
Dim field As TemplateField
Dim first_field As Boolean = True
For Each field In Me._template_fields
If first_field Then
first_field = False
message &= field.Attribute & "=" & field.Value
Else
message &= ", " & field.Attribute & "=" & field.Value
End If
Next
message &= ")"
Return message
End Get
End Property
Friend ReadOnly Property Template() As Template
Get
Return Me._parent.Template
End Get
End Property
End Class