Imports System.IO
Imports System.ServiceModel
Imports DigitalData.Modules.EDMI.API.Constants
Imports DigitalData.Modules.EDMI.API.EDMIServiceReference
Imports DigitalData.Modules.EDMI.API.Rights
Imports DigitalData.Modules.Language.Utils
Imports DigitalData.Modules.Logging
Public Class Client
Private Const INVALID_OBEJCT_ID As Long = 0
Private Const KIND_TYPE_DOC = "DOC"
Private ReadOnly _logger As Logger
Private ReadOnly _channelFactory As ChannelFactory(Of IEDMIServiceChannel)
Private ReadOnly _IPAddressServer As String
Private _dummy_table_attributes As DataTable
Private _channel As IEDMIServiceChannel
Public Class StreamedFile
Public Stream As MemoryStream
Public FileName As String
End Class
Public Class FileList
Public Datatable As DataTable
End Class
Public Class DocumentInfo
Public FullPath As String
Public AccessRight As AccessRight
End Class
Public Class VariableValue
Public ReadOnly Property IsVector As Boolean = False
Public Property Value As Object
Public Property Type As Type
Public Sub New(pValue As Object)
' Check if value is a collection
If TypeOf pValue Is IEnumerable Then
IsVector = True
End If
' Try to determine the type
If IsNothing(pValue) Then
Type = Nothing
Else
Type = pValue.GetType
End If
Value = pValue
End Sub
End Class
Public Shared Function ParseServiceAddress(AddressWithOptionalPort As String) As Tuple(Of String, Integer)
Dim oSplit() As String = AddressWithOptionalPort.Split(":"c)
Dim oAppServerAddress As String = oSplit(0)
Dim oAppServerPort As Integer
If oSplit.Length = 2 Then
If Integer.TryParse(oSplit(1), oAppServerPort) Then
oAppServerPort = DEFAULT_SERVICE_PORT
End If
Else
oAppServerPort = DEFAULT_SERVICE_PORT
End If
Return New Tuple(Of String, Integer)(oAppServerAddress, oAppServerPort)
End Function
'''
''' Creates a new EDMI Client object
'''
''' LogConfig object
''' The full service url to connect to, for example: net.tcp://1.1.1.1:1111/some/path
Public Sub New(LogConfig As LogConfig, ServiceAdress As String)
_logger = LogConfig.GetLogger()
Try
Dim oBinding = Channel.GetBinding()
Dim oAddress = New EndpointAddress(ServiceAdress)
Dim oFactory = New ChannelFactory(Of IEDMIServiceChannel)(oBinding, oAddress)
_channelFactory = oFactory
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
'''
''' Creates a new EDMI Client object
'''
''' LogConfig object
''' The IP address to connect to
''' The Port number to use for the connection
Public Sub New(LogConfig As LogConfig, IPAddress As String, PortNumber As Integer)
_logger = LogConfig.GetLogger()
Try
_IPAddressServer = IPAddress
Dim oBinding = Channel.GetBinding()
Dim oAddress = New EndpointAddress($"net.tcp://{IPAddress}:{PortNumber}/DigitalData/Services/Main")
Dim oFactory = New ChannelFactory(Of IEDMIServiceChannel)(oBinding, oAddress)
_channelFactory = oFactory
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
'''
''' Connect to the service
'''
''' True if connection was successful, false otherwise
Public Function Connect() As Boolean
Try
_channel = GetChannel()
_logger.Debug("Opening channel..")
_channel.Open()
_logger.Info($"Connection to AppService {_IPAddressServer} successfully established!")
Return True
Catch ex As Exception
_logger.Error(ex)
Return False
End Try
End Function
Private Function PreloadAttributes()
End Function
'''
''' TODO: Creates a new object
'''
'''
Public Async Function NewObjectAsync() As Task
Throw New NotImplementedException()
End Function
'''
''' Import options for NewFileAsync. Contains default values for all options
'''
Public Class NewFileOptions
Public KeepExtension As Boolean = True
Public Username As String = String.Empty
Public Language As String = String.Empty
End Class
'''
''' Imports a file from a filepath, creating a IDB ObjectId and Filesystem Object
'''
''' Local filepath to a file.
''' Windows username of the user responsible for the import.
''' Date when the file was imported. Can be in the past.
''' Type of ObjectStore. Can be WORK or ARCHIVE.
''' Business entity that the new file object should belong to.
''' Other file import options
''' When local filepath was not found
''' When there was a error in the Service
''' The ObjectId of the newly generated filesystem object
Public Async Function NewFileAsync(pFilePath As String, pAddedWho As String, pAddedWhen As Date, pObjectStoreType As String, pBusinessEntity As String, Optional pImportOptions As NewFileOptions = Nothing) As Task(Of Long)
Try
' Set default options
If pImportOptions Is Nothing Then
pImportOptions = New NewFileOptions()
End If
' Check if file exists
If File.Exists(pFilePath) = False Then
Throw New FileNotFoundException("ImportFileAsync: Path does not exist")
End If
Dim oFileInfo As New FileInfo(pFilePath)
Dim oExtension As String = oFileInfo.Extension
' Creating new ObjectId
Dim oObjectIdResponse = Await _channel.NewObjectIdAsync(New NewObjectIdRequest With {
.BusinessEntity = pBusinessEntity,
.KindType = KIND_TYPE_DOC,
.Who = pAddedWho
})
If oObjectIdResponse.ObjectId = Nothing OrElse oObjectIdResponse.ObjectId = 0 Then
Throw New ApplicationException("ImportFileAsync: Could not get ObjectId")
End If
' Create new FileObject for ObjectId
Dim oFilePathResponse = Await _channel.NewFileObjectAsync(New NewFileObjectRequest With {
.DateImported = pAddedWhen,
.Extension = oExtension,
.KeepExtension = pImportOptions.KeepExtension,
.ObjectId = oObjectIdResponse.ObjectId,
.StoreType = pObjectStoreType
})
If oFilePathResponse.FileObjectPath = Nothing OrElse oFilePathResponse.FileObjectPath = "" Then
Throw New ApplicationException("ImportFileAsync: Could not get FileObject Path")
End If
' Importing the file now
Using oFileStream As New FileStream(pFilePath, FileMode.Open, FileAccess.Read)
Using oMemoryStream As New MemoryStream()
oFileStream.CopyTo(oMemoryStream)
Dim oContents = oMemoryStream.ToArray()
Dim oFileImportResponse = Await _channel.ImportFileIntoFileObjectAsync(New ImportFileIntoFileObjectRequest With {
.FilePath = oFilePathResponse.FileObjectPath,
.ObjectId = oObjectIdResponse.ObjectId,
.ObjectStoreType = pObjectStoreType,
.Who = pAddedWho,
.Contents = oContents
})
If oFileImportResponse.Result = False Then
Throw New ApplicationException("ImportFileAsync: Could not Import File Contents")
End If
End Using
End Using
Return oObjectIdResponse.ObjectId
Catch ex As Exception
_logger.Error(ex)
Return INVALID_OBEJCT_ID
End Try
End Function
Public Class SetVariableValueOptions
Public CheckDeleted As Boolean = False
Public Username As String = String.Empty
Public Language As String = String.Empty
End Class
'''
''' Sets a value to an attribute
'''
''' IDB ObjectId
''' Name of the attribute
''' The type of Attribute
'''
'''
'''
Public Function SetVariableValue(pObjectId As Long, pAttributeName As String, pAttributeType As AttributeType, pValue As Object, Optional pOptions As SetVariableValueOptions = Nothing) As Boolean
Try
' Set default options
If pOptions Is Nothing Then
pOptions = New SetVariableValueOptions()
End If
Dim oLanguage = NotNull(pOptions.Language, GetUserLanguage())
Dim oUsername = NotNull(pOptions.Username, Environment.UserName)
Try
Dim oResponse = _channel.TestObjectIdExists(New TestObjectIdExistsRequest With {.ObjectId = pObjectId})
If oResponse.Exists = False Then
Return False
End If
Catch ex As Exception
_logger.Error(ex)
Return False
End Try
' TODO: Check if Attribute exists
Dim oType = pValue.GetType.Name
If oType = GetType(DataTable).Name Then
Dim oValueTable As DataTable = pValue
Dim oCurrentValue As VariableValue
If pOptions.CheckDeleted = True Then
Dim oOptions As New GetVariableValueOptions With {
.Language = oLanguage,
.Username = oUsername
}
' Get current value
oCurrentValue = GetVariableValue(pObjectId, pAttributeName, pAttributeType, oOptions)
' If current value is datatable
If oCurrentValue.Type = GetType(DataTable) Then
' Convert value to Datatable
Dim oTable As DataTable = oCurrentValue.Value
If oTable.Rows.Count > 1 Then
'now Checking whether the old row still remains in Vector? If not it will be deleted as it cannot be replaced in multivalues
For Each oRow As DataRow In oTable.Rows
Dim oExists As Boolean = False
For Each oNewValueRow As DataRow In oValueTable.Rows
Dim oInfo = $"Checking oldValue[{oRow.Item(0)}] vs NewValue [{oNewValueRow.Item(1)}]"
If oNewValueRow.Item(1).ToString.ToUpper = oRow.Item(0).ToString.ToUpper Then
oExists = True
Exit For
End If
Next
If oExists = False Then
_logger.Debug($"Value [{oRow.Item(0)}] no longer existing in Vector-Attribute [{pAttributeName}] - will be deleted!")
DeleteTermObjectFromMetadata(pObjectId, pAttributeName, oRow.Item(0))
End If
Next
End If
Else
If oValueTable.Rows.Count > 1 Then
Dim oExists As Boolean = False
For Each oNewValueRow As DataRow In oValueTable.Rows
_logger.Debug($"Checking oldValue[{oCurrentValue}] vs NewValue [{oNewValueRow.Item(1)}]")
If oNewValueRow.Item(1).ToString.ToUpper = oCurrentValue.ToString.ToUpper Then
oExists = True
Exit For
End If
Next
If oExists = False Then
_logger.Debug($"Value [{oCurrentValue}] no longer existing in Vector-Attribute [{pAttributeName}] - will be deleted!")
DeleteTermObjectFromMetadata(pObjectId, pAttributeName, oCurrentValue.Value)
End If
Else
_logger.Debug($"Value [{oCurrentValue}] of Attribute [{pAttributeName}] obviously was updated during runtime - will be deleted!")
DeleteTermObjectFromMetadata(pObjectId, pAttributeName, oCurrentValue.Value)
End If
End If
End If
For Each oNewValueRow As DataRow In oValueTable.Rows
Dim oSuccess As Boolean = False
Dim oSQL = $"DECLARE @NEW_OBJ_MD_ID BIGINT
EXEC PRIDB_NEW_OBJ_DATA({pObjectId}, '{pAttributeName}', '{oUsername}', '{oNewValueRow.Item(1)}', '{oLanguage}', 0, @OMD_ID = @NEW_OBJ_MD_ID OUTPUT)"
Dim oResult = _channel.ExecuteNonQuery_MSSQL_IDB(oSQL)
If Not oResult.OK Then
Return False
End If
Next
Return True
Else
Dim oSql = $"DECLARE @NEW_OBJ_MD_ID BIGINT
EXEC PRIDB_NEW_OBJ_DATA({pObjectId}, '{pAttributeName}', '{oUsername}', '{pValue}', '{oLanguage}', 0, @OMD_ID = @NEW_OBJ_MD_ID OUTPUT)"
Dim oResult = _channel.ExecuteNonQuery_MSSQL_IDB(oSql)
Return oResult.OK
End If
Catch ex As Exception
_logger.Error(ex)
Return False
End Try
End Function
Public Class GetVariableValueOptions
Public Username As String = String.Empty
Public Language As String = String.Empty
End Class
Public Function GetVariableValue(pObjectId As Long, pAttributeName As String, pAttributeType As AttributeType, Optional pOptions As GetVariableValueOptions = Nothing) As VariableValue
If pOptions Is Nothing Then
pOptions = New GetVariableValueOptions()
End If
pOptions.Language = NotNull(pOptions.Language, GetUserLanguage())
pOptions.Username = NotNull(pOptions.Username, Environment.UserName)
' Check if ObjectId exists
Try
Dim oResponse = _channel.TestObjectIdExists(New TestObjectIdExistsRequest With {.ObjectId = pObjectId})
If oResponse.Exists = False Then
Return Nothing
End If
Catch ex As Exception
_logger.Error(ex)
Return Nothing
End Try
' Get Attributes and Values from Database
Dim oAttributes As DataTable = GetAttributesForObject(pObjectId, pOptions.Language)
' TODO: Check if Attribute exists & REfactor
Try
Dim oVectorAttribute As Boolean = False
Select Case pAttributeType
Case AttributeType.VectorInteger
oVectorAttribute = True
Case AttributeType.VectorString
oVectorAttribute = True
Case Else
oVectorAttribute = False
End Select
Dim oValues As New List(Of Object)
Dim oRows As List(Of DataRow) = oAttributes.AsEnumerable().
Where(Function(pRow As DataRow) pRow.Item("AttributeTitle") = pAttributeName).
ToList()
If oVectorAttribute = False Then
Dim oRow As DataRow = oRows.FirstOrDefault()
Dim oType As String = oRow.Item("AttributeType")
Dim oValue = GetValueByType(oRow, oType)
'oValues.Add(oValue)
Return New VariableValue(oValue)
Else
For Each oRow As DataRow In oRows
Dim oType As String = oRow.Item("AttributeType")
Dim oValue = GetValueByType(oRow, oType)
oValues.Add(oValue)
Next
Return New VariableValue(oValues)
End If
'If Not IsNothing(oAttributes) Then
' If oVectorAttribute = True And _dummy_table_attributes.Rows.Count = 1 And pOptions.FromIDB = False Then
' Try
' If pAttributeName = "IDBCreatedWhen" Then
' pAttributeName = "ADDED_WHEN"
' ElseIf pAttributeName = "IDBCreatedWho" Then
' pAttributeName = "ADDED_WHO"
' ElseIf pAttributeName = "IDBChangedWhen" Then
' pAttributeName = "CHANGED_WHEN"
' ElseIf pAttributeName = "IDBChangedWho" Then
' pAttributeName = "CHANGED_WHO"
' End If
' oAttributeValue = _dummy_table_attributes.Rows(0).Item(pAttributeName)
' Catch ex As Exception
' _logger.Debug($"Error getting Attribute from IDB_DT_DOC_DATA: {ex.Message}")
' End Try
' End If
'Else
' Throw New ApplicationException($"Could not get Attributes for ObjectId [{pObjectId}]")
'End If
'TODO: BRAUCHEN SIE DAS ÜBERHAUPT??????11111?!!1!1
'If Not IsNothing(oAttributeValue) Then
' Return oAttributeValue
'Else
' _logger.Debug($"oAttributeValue for Attribute [{pAttributeName}] is so far nothing..Now trying FNIDB_PM_GET_VARIABLE_VALUE ")
'End If
'Dim oFNSQL = $"SELECT * FROM [dbo].[FNIDB_PM_GET_VARIABLE_VALUE] ({pObjectId},'{pAttributeName}','{pOptions.Language}',CONVERT(BIT,'0'))"
'Dim oDatatable As TableResult = _channel.ReturnDatatable_MSSQL_IDB(oFNSQL)
'If oDatatable.OK = False Then
' Throw New ApplicationException(oDatatable.ErrorMessage)
'End If
'If oDatatable.Table.Rows.Count = 1 Then
' oAttributeValue = oDatatable.Table.Rows.Item(0).Item(0)
'End If
Catch ex As Exception
_logger.Error(ex)
Return Nothing
End Try
End Function
Private Function GetValueByType(pRow As DataRow, pTypeString As String) As Object
Try
Dim oAttributeValue As Object
Select Case pTypeString
Case Constants.AttributeTypeName.BIT
oAttributeValue = pRow.Item("ValueBigInt")
Case Constants.AttributeTypeName.BIG_INTEGER
oAttributeValue = pRow.Item("ValueBigInt")
Case Constants.AttributeTypeName.DATE
oAttributeValue = pRow.Item("ValueDate")
Case Constants.AttributeTypeName.DATETIME
oAttributeValue = pRow.Item("ValueDate")
Case Constants.AttributeTypeName.DECIMAL
oAttributeValue = pRow.Item("ValueDecimal")
Case Constants.AttributeTypeName.FLOAT
oAttributeValue = pRow.Item("ValueDecimal")
Case Constants.AttributeTypeName.VARCHAR
oAttributeValue = pRow.Item("ValueText")
Case Constants.AttributeTypeName.VECTOR_INTEGER
oAttributeValue = pRow.Item("ValueBigInt")
Case Constants.AttributeTypeName.VECTOR_STRING
oAttributeValue = pRow.Item("ValueText")
Case Else
oAttributeValue = Nothing
End Select
Return oAttributeValue
Catch ex As Exception
_logger.Error(ex)
Return Nothing
End Try
End Function
Private Function GetAttributesForObject(pObjectId As Long, pLanguage As String) As DataTable
Dim oTable As DataTable
Try
Dim oResult As TableResult = _channel.ReturnDatatable_MSSQL_IDB($"EXEC [PRIDB_GET_VALUE_DT]({pObjectId}, '{pLanguage}')")
If oResult.OK = False Then
Throw New ApplicationException(oResult.ErrorMessage)
End If
If oResult.Table Is Nothing OrElse oResult.Table.Rows.Count = 0 Then
Return Nothing
End If
oTable = oResult.Table
Return oTable
Catch ex As Exception
_logger.Error(ex)
Return Nothing
End Try
End Function
Private Function DeleteTermObjectFromMetadata(pObjectId As Long, pAttributeName As String, pTerm2Delete As String, Optional pUsername As String = "", Optional pLanguage As String = "") As Boolean
Try
Dim oLanguage = NotNull(pLanguage, GetUserLanguage())
Dim oUsername = NotNull(pUsername, Environment.UserName)
Dim oIdIsForeign As Integer = 1
Dim oDELSQL = $"EXEC PRIDB_DELETE_TERM_OBJECT_METADATA {pObjectId},'{pAttributeName}','{pTerm2Delete}','{oUsername}','{oLanguage}',{oIdIsForeign}"
Dim oResult = _channel.ExecuteNonQuery_MSSQL_IDB(oDELSQL)
Return oResult.OK
Catch ex As Exception
_logger.Error(ex)
Return False
End Try
End Function
Public Function GetDatatableFromIDB(SQL As String) As TableResult
Try
Dim oResponse = _channel.ReturnDatatable_MSSQL_IDB(SQL)
Return oResponse
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Async Function GetDatatableFromIDBAsync(SQL As String) As Task(Of TableResult)
Try
Dim oResponse = Await _channel.ReturnDatatable_MSSQL_IDBAsync(SQL)
Return oResponse
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Function GetScalarValueFromIDB(SQL As String) As ScalarResult
Try
Dim oResponse = _channel.ReturnScalar_MSSQL_IDB(SQL)
Return oResponse
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Async Function GetScalarValueFromIDBAsync(SQL As String) As Task(Of ScalarResult)
Try
Dim oResponse = Await _channel.ReturnScalar_MSSQL_IDBAsync(SQL)
Return oResponse
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Function GetDatatableByName(DatatableName As String, Optional FilterExpression As String = "", Optional SortByColumn As String = "") As TableResult
Try
Dim oResponse = _channel.ReturnDatatableFromCache(DatatableName, FilterExpression, SortByColumn)
Return oResponse
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
'''
''' Return infos about a file object
'''
'''
'''
'''
Public Function GetDocumentInfo(UserId As Long, ObjectId As Long) As DocumentInfo
Try
Dim oResponse As DocumentInfoResponse = _channel.GetFileInfoByObjectId(New DocumentInfoRequest With {
.ObjectId = ObjectId,
.UserId = UserId
})
Return New DocumentInfo With {
.AccessRight = oResponse.FileRight,
.FullPath = oResponse.FullPath
}
Catch ex As FaultException(Of ObjectDoesNotExistFault)
_logger.Error(ex)
Throw ex
Catch ex As FaultException
_logger.Error(ex)
Throw ex
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Async Function GetDocumentInfoAsync(UserId As Long, ObjectId As Long) As Task(Of DocumentInfo)
Try
Dim oParams = New DocumentInfoRequest With {
.ObjectId = ObjectId,
.UserId = UserId
}
Dim oResponse As DocumentInfoResponse = Await _channel.GetFileInfoByObjectIdAsync(oParams)
Return New DocumentInfo With {
.AccessRight = oResponse.FileRight,
.FullPath = oResponse.FullPath
}
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
'''
''' Aborts the channel and creates a new connection
'''
Public Sub Reconnect()
_logger.Warn("Connection faulted. Trying to reconnect..")
Try
_channel.Abort()
_channel = GetChannel()
_channel.Open()
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
'''
''' Creates a channel and adds a Faulted-Handler
'''
''' A channel object
Private Function GetChannel() As IEDMIServiceChannel
Try
_logger.Debug("...Creating channel..")
Dim oChannel = _channelFactory.CreateChannel()
AddHandler oChannel.Faulted, AddressOf Reconnect
Return oChannel
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function GetUserLanguage() As String
Return Threading.Thread.CurrentThread.CurrentUICulture.Name
End Function
End Class