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" Public Const DEFAULT_SERVICE_PORT = 9000 Private ReadOnly _logger As Logger Private ReadOnly _channelFactory As ChannelFactory(Of IEDMIServiceChannel) Private ReadOnly _IPAddressServer As String 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 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 ''' ''' 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 If pImportOptions Is Nothing Then pImportOptions = New NewFileOptions() End If 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 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 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 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 ''' ''' ''' ''' ''' ''' Public Function SetVariableValue(pObjectId As Long, pAttributeName As String, pAttributeType As AttributeType, pValue As Object, Optional pOptions As SetVariableValueOptions = Nothing) As Boolean Try If pOptions Is Nothing Then pOptions = New SetVariableValueOptions() End If Dim oLanguage = NotNull(pOptions.Language, GetUserLanguage()) Dim oUsername = NotNull(pOptions.Username, Environment.UserName) Dim oType = pValue.GetType.Name If oType = GetType(DataTable).Name Then Dim oDTMyNewValues As DataTable = pValue Dim oOldAttributeResult As Object Dim oTypeOldResult As Object If pOptions.CheckDeleted = True Then oOldAttributeResult = GetVariableValue(pAttributeName, pAttributeType) oTypeOldResult = oOldAttributeResult.GetType.Name If oTypeOldResult = GetType(DataTable).Name Then Dim oOldValues As DataTable = oOldAttributeResult If oOldValues.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 oOldValueRow As DataRow In oOldValues.Rows Dim oExists As Boolean = False For Each oNewValueRow As DataRow In oDTMyNewValues.Rows Dim oInfo = $"Checking oldValue[{oOldValueRow.Item(0)}] vs NewValue [{oNewValueRow.Item(1)}]" If oNewValueRow.Item(1).ToString.ToUpper = oOldValueRow.Item(0).ToString.ToUpper Then oExists = True Exit For End If Next If oExists = False Then Dim oInfo = $"Value [{oOldValueRow.Item(0)}] no longer existing in Vector-Attribute [{pAttributeName}] - will be deleted!" _logger.Debug(oInfo) SetVariableValue(pObjectId, My.Application.Globix.CURRENT_PROFILE_LOG_INDEX, AttributeType.Varchar, oInfo) DeleteTermObjectFromMetadata(pObjectId, pAttributeName, oOldValueRow.Item(0)) End If Next End If Else If oDTMyNewValues.Rows.Count > 1 Then Dim oExists As Boolean = False For Each oNewValueRow As DataRow In oDTMyNewValues.Rows Dim oInfo1 = $"Checking oldValue[{oOldAttributeResult}] vs NewValue [{oNewValueRow.Item(1)}]" If oNewValueRow.Item(1).ToString.ToUpper = oOldAttributeResult.ToString.ToUpper Then oExists = True Exit For End If Next If oExists = False Then Dim oInfo = $"Value [{oOldAttributeResult}] no longer existing in Vector-Attribute [{pAttributeName}] - will be deleted!" _logger.Debug(oInfo) SetVariableValue(pObjectId, My.Application.Globix.CURRENT_PROFILE_LOG_INDEX, AttributeType.Varchar, oInfo) DeleteTermObjectFromMetadata(pObjectId, pAttributeName, oOldAttributeResult) End If Else Dim oInfo = $"Value [{oOldAttributeResult}] of Attribute [{pAttributeName}] obviously was updated during runtime - will be deleted!" _logger.Debug(oInfo) SetVariableValue(pObjectId, My.Application.Globix.CURRENT_PROFILE_LOG_INDEX, AttributeType.Varchar, oInfo) DeleteTermObjectFromMetadata(pObjectId, pAttributeName, oOldAttributeResult) End If End If End If For Each oNewValueRow As DataRow In oDTMyNewValues.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 FromIDB As Boolean = False 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 Object If pOptions Is Nothing Then pOptions = New GetVariableValueOptions() End If Dim oLanguage = NotNull(pOptions.Language, GetUserLanguage()) Dim oUsername = NotNull(pOptions.Username, Environment.UserName) Try Dim oSingleAttribute As Boolean Select Case pAttributeType Case AttributeType.VectorInteger oSingleAttribute = False Case AttributeType.VectorString oSingleAttribute = False Case Else oSingleAttribute = True End Select Dim oAttributeValue As Object = Nothing If Not IsNothing(My.Tables.DTIDB_DOC_DATA) Then If oSingleAttribute = True And My.Tables.DTIDB_DOC_DATA.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 = My.Tables.DTIDB_DOC_DATA.Rows(0).Item(pAttributeName) Catch ex As Exception _logger.Debug($"Error getting Attribute from IDB_DT_DOC_DATA: {ex.Message}") End Try End If End If 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}','{oLanguage}',CONVERT(BIT,'0'))" Dim oDatatable As TableResult = _channel.ReturnDatatable_MSSQL_IDB(oFNSQL) If oDatatable.OK = False Then _logger.Warn(oDatatable.ErrorMessage) Return Nothing End If If oDatatable.Table.Rows.Count = 1 Then oAttributeValue = oDatatable.Table.Rows.Item(0).Item(0) End If Return oAttributeValue 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 CreateObjectId(pKindType As String, pWho As String, pBusinessEntity As String) As Long ' Try ' Dim oResponse = _channel.NewObjectId(New NewObjectIdRequest With { ' .KindType = pKindType, ' .BusinessEntity = pBusinessEntity, ' .Who = pWho ' }) ' Return oResponse.ObjectId ' Catch ex As Exception ' _logger.Error(ex) ' Throw ex ' End Try 'End Function 'Public Function CreateFileStoreObject(pObjectId As Long, pStoreType As String, pDate As String, pExtension As String, pKeepExtension As String) As String ' Try ' ' Remove dot in Extension ' If pExtension.StartsWith(".") Then ' pExtension = pExtension.Substring(1) ' End If ' Dim oArgs As New NewFileObjectRequest With { ' .ObjectId = pObjectId, ' .StoreType = pStoreType, ' .DateImported = pDate, ' .Extension = pExtension, ' .KeepExtension = pKeepExtension ' } ' Dim oResponse = _channel.NewFileObject(oArgs) ' Return oResponse.FileObjectPath ' Catch ex As Exception ' _logger.Error(ex) ' Throw ex ' End Try 'End Function 'Public Async Function ImportFileObjectAsync(pContent As Byte(), pWho As String, pObjectId As Long, pObjectStoreType As String, pFileObjectPath As String) As Task(Of Boolean) ' Try ' Dim oData As New ImportFileIntoFileObjectRequest() With { ' .Contents = pContent, ' .Who = pWho, ' .FilePath = pFileObjectPath, ' .ObjectId = pObjectId, ' .ObjectStoreType = pObjectStoreType ' } ' Dim oResponse = Await _channel.ImportFileIntoFileObjectAsync(oData) ' Return oResponse.Result ' Catch ex As Exception ' _logger.Error(ex) ' Return False ' End Try 'End Function 'Public Async Function GetFileByObjectIdAsync(ObjectId As Long) As Task(Of StreamedFile) ' Try ' Dim oData As New DocumentStreamRequest() With {.ObjectId = ObjectId} ' Dim oResponse As DocumentStreamResponse = Await _channel.GetFileByObjectIdAsync(oData) ' Dim oMemoryStream As New MemoryStream() ' oResponse.FileContents.CopyTo(oMemoryStream) ' oMemoryStream.Position = 0 ' Return New StreamedFile() With { ' .Stream = oMemoryStream, ' .FileName = oResponse.FileName ' } ' Catch ex As Exception ' _logger.Error(ex) ' Throw ex ' End Try 'End Function 'Public Async Function ListFilesForUserAsync() As Task(Of FileList) ' Try ' Dim oResponse As DocumentListResponse = Await _channel.ListFilesForUserAsync(New ListFilesForUserRequest()) ' Return New FileList() With { ' .Datatable = oResponse.Datatable ' } ' Catch ex As Exception ' _logger.Error(ex) ' Throw ex ' 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