From edd34b18a092a6342d79dd7c05bc2747f22f05d0 Mon Sep 17 00:00:00 2001 From: Jonathan Jenne Date: Wed, 12 Jan 2022 14:35:18 +0100 Subject: [PATCH] EDMIAPI: Improve Service an Client, Revert some changed function names --- Modules.EDMIAPI/Client.vb | 238 ++++++++++-------- .../DigitalData.Services.EDMIService.wsdl | 12 +- .../DigitalData.Services.EDMIService.xsd | 61 +++-- .../EDMIServiceReference/Reference.svcmap | 2 +- .../EDMIServiceReference/Reference.vb | 18 +- .../EDMIServiceReference/service.wsdl | 9 + Modules.EDMIAPI/DatabaseWithFallback.vb | 139 +++++++--- Service.EDMIService/EDMIService.vb | 6 +- Service.EDMIService/IEDMIService.vb | 6 +- 9 files changed, 317 insertions(+), 174 deletions(-) diff --git a/Modules.EDMIAPI/Client.vb b/Modules.EDMIAPI/Client.vb index 6042c700..a9b4351a 100644 --- a/Modules.EDMIAPI/Client.vb +++ b/Modules.EDMIAPI/Client.vb @@ -1,5 +1,6 @@ Imports System.IO Imports System.ServiceModel +Imports System.Timers Imports DigitalData.Modules.EDMI.API.Constants Imports DigitalData.Modules.EDMI.API.EDMIServiceReference Imports DigitalData.Modules.EDMI.API.Rights @@ -7,16 +8,49 @@ Imports DigitalData.Modules.Language.Utils Imports DigitalData.Modules.Logging Public Class Client + ' Constants + Private Const UPDATE_INTERVAL_IN_MINUTES As Integer = 1 Public Const INVALID_OBEJCT_ID As Long = 0 Private Const KIND_TYPE_DOC = "DOC" - Private ReadOnly _LogConfig As LogConfig - Private ReadOnly _logger As Logger - Private ReadOnly _channelFactory As ChannelFactory(Of IEDMIServiceChannel) - Private ReadOnly _IPAddressServer As String - Private ReadOnly _PortServer As Integer - Private ReadOnly _FileEx As Filesystem.File - Private _channel As IEDMIServiceChannel + ' Helper Classes + Private ReadOnly LogConfig As LogConfig + Private ReadOnly Logger As Logger + Private ReadOnly FileEx As Filesystem.File + + ' Runtime Variables + Private ReadOnly ServerAddress As String + Private ReadOnly ServerPort As Integer + + ' Channel + Private ReadOnly ChannelFactory As ChannelFactory(Of IEDMIServiceChannel) + Private Channel As IEDMIServiceChannel + + ' Update Timer + Private WithEvents UpdateTimer As New Timers.Timer + + ' Public Variables + Public CachedTables As New List(Of String) + + ''' + ''' Parse a IPAddress:Port String into its parts + ''' + ''' + 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 @@ -24,9 +58,9 @@ Public Class Client ''' LogConfig object ''' The IP address/hostname and port, separated by semicolon or colon, ex. 1.2.3.4:9000 Public Sub New(pLogConfig As LogConfig, pServiceAdress As String) - _LogConfig = pLogConfig - _logger = pLogConfig.GetLogger() - _FileEx = New Filesystem.File(pLogConfig) + LogConfig = pLogConfig + Logger = pLogConfig.GetLogger() + FileEx = New Filesystem.File(pLogConfig) Dim oServiceAddress As String = pServiceAdress Dim oAddressArray() As String @@ -37,17 +71,20 @@ Public Class Client oAddressArray = oServiceAddress.Split(":") End If + UpdateTimer.Interval = 60 * 1000 * UPDATE_INTERVAL_IN_MINUTES + UpdateTimer.Start() + Try - _IPAddressServer = oAddressArray(0) - _PortServer = oAddressArray(1) + ServerAddress = oAddressArray(0) + ServerPort = oAddressArray(1) - Dim oBinding = Channel.GetBinding() - Dim oAddress = New EndpointAddress($"net.tcp://{_IPAddressServer}:{_PortServer}/DigitalData/Services/Main") + Dim oBinding = API.Channel.GetBinding() + Dim oAddress = New EndpointAddress($"net.tcp://{ServerAddress}:{ServerPort}/DigitalData/Services/Main") Dim oFactory = New ChannelFactory(Of IEDMIServiceChannel)(oBinding, oAddress) - _channelFactory = oFactory + ChannelFactory = oFactory Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) End Try End Sub @@ -58,59 +95,38 @@ Public Class Client ''' 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) - _LogConfig = LogConfig - _logger = LogConfig.GetLogger() - _FileEx = New Filesystem.File(LogConfig) + Me.LogConfig = LogConfig + Logger = LogConfig.GetLogger() + FileEx = New Filesystem.File(LogConfig) Try - _IPAddressServer = IPAddress - Dim oBinding = Channel.GetBinding() + ServerAddress = IPAddress + Dim oBinding = API.Channel.GetBinding() Dim oAddress = New EndpointAddress($"net.tcp://{IPAddress}:{PortNumber}/DigitalData/Services/Main") Dim oFactory = New ChannelFactory(Of IEDMIServiceChannel)(oBinding, oAddress) - _channelFactory = oFactory + ChannelFactory = oFactory Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) End Try End Sub - ''' - ''' Parse a IPAddress:Port String into its parts - ''' - ''' - ''' - 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 - ''' ''' Connect to the service ''' ''' True if connection was successful, false otherwise Public Function Connect() As Boolean Try - _channel = GetChannel() + Channel = GetChannel() - _logger.Debug("Opening channel..") - _channel.Open() + Logger.Debug("Opening channel..") + Channel.Open() - _logger.Info($"Connection to AppService {_IPAddressServer} successfully established!") + Logger.Info($"Connection to AppService {ServerAddress} successfully established!") Return True Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return False End Try End Function @@ -119,17 +135,29 @@ Public Class Client ''' Aborts the channel and creates a new connection ''' Public Sub Reconnect() - _logger.Warn("Connection faulted. Trying to reconnect..") + Logger.Warn("Connection faulted. Trying to reconnect..") Try - _channel.Abort() - _channel = GetChannel() - _channel.Open() + Channel.Abort() + Channel = GetChannel() + Channel.Open() Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) End Try End Sub + Private Async Function UpdateTimer_Elapsed(sender As Object, e As ElapsedEventArgs) As Task Handles UpdateTimer.Elapsed + Try + Dim oTables As String() = Await Channel.GetCachedTablesAsync() + CachedTables = oTables. + Select(Function(table) table.ToUpper). + ToList() + Catch ex As Exception + Logger.Error(ex) + CachedTables = New List(Of String) + End Try + End Function + ''' ''' Imports a file from a filepath, creating a IDB ObjectId and Filesystem Object ''' @@ -157,7 +185,7 @@ Public Class Client Dim oFileName As String = oFileInfo.Name Dim oFileCreatedAt As Date = oFileInfo?.CreationTime Dim oFileModifiedAt As Date = oFileInfo?.LastWriteTime - Dim oFileHash As String = _FileEx.GetChecksum(oFileInfo.FullName) + Dim oFileHash As String = FileEx.GetChecksum(oFileInfo.FullName) ' Importing the file now Using oFileStream As New FileStream(pFilePath, FileMode.Open, FileAccess.Read) @@ -165,7 +193,7 @@ Public Class Client oFileStream.CopyTo(oMemoryStream) Dim oContents = oMemoryStream.ToArray() - Dim oFileImportResponse = Await _channel.NewFileAsync(New NewFileRequest With { + Dim oFileImportResponse = Await Channel.NewFileAsync(New NewFileRequest With { .BusinessEntity = pBusinessEntity, .File = New FileProperties With { .FileName = oFileInfo.Name, @@ -191,7 +219,7 @@ Public Class Client End Using End Using Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return INVALID_OBEJCT_ID End Try End Function @@ -205,32 +233,32 @@ Public Class Client pBusinessEntity As String, Optional pImportOptions As Options.ImportFileOptions = Nothing) As Task(Of ImportFileResponse) Try - Dim oImportFile As New Modules.Globix.ImportFile(_LogConfig, _channel) + Dim oImportFile As New Modules.Globix.ImportFile(LogConfig, Channel) Return Await oImportFile.RunAsync(pFilePath, pProfileId, pAttributeValues, pObjectStoreName, pObjectKind, pBusinessEntity, pImportOptions) Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return Nothing End Try End Function Public Function Zooflow_GetFileObject(pObjectId As Long, pLoadFileContents As Boolean) As FileObject Try - Dim oGetFileObject As New Modules.Zooflow.GetFileObject(_LogConfig, _channel) + Dim oGetFileObject As New Modules.Zooflow.GetFileObject(LogConfig, Channel) Dim oFileObject = oGetFileObject.Run(pObjectId, pLoadFileContents) Return oFileObject Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return Nothing End Try End Function Public Async Function GetFileObjectAsync(pObjectId As Long, pLoadFileContents As Boolean) As Task(Of FileObject) Try - Dim oGetFileObject As New Modules.Zooflow.GetFileObject(_LogConfig, Me) + Dim oGetFileObject As New Modules.Zooflow.GetFileObject(LogConfig, Me) Dim oFileObject = Await oGetFileObject.RunAsync(pObjectId, pLoadFileContents) Return oFileObject Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return Nothing End Try End Function @@ -256,13 +284,13 @@ Public Class Client } Try - Dim oResponse = _channel.TestObjectIdExists(New TestObjectIdExistsRequest With {.ObjectId = pObjectId}) + 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) + Logger.Error(ex) Return False End Try @@ -287,7 +315,7 @@ Public Class Client For Each oRow As DataRow In oTable.Rows Dim oExists As Boolean = False For Each oNewValueRow As DataRow In oValueTable.Rows - _logger.Debug($"Checking oldValue[{oCurrentValue}] vs NewValue [{oNewValueRow.Item(1)}]") + Logger.Debug($"Checking oldValue[{oCurrentValue}] vs NewValue [{oNewValueRow.Item(1)}]") If oNewValueRow.Item(1).ToString.ToUpper = oRow.Item(0).ToString.ToUpper Then oExists = True @@ -296,7 +324,7 @@ Public Class Client Next If oExists = False Then - _logger.Debug($"Value [{oRow.Item(0)}] no longer existing in Vector-Attribute [{pAttributeName}] - will be deleted!") + Logger.Debug($"Value [{oRow.Item(0)}] no longer existing in Vector-Attribute [{pAttributeName}] - will be deleted!") DeleteTermObjectFromMetadata(pObjectId, pAttributeName, oRow.Item(0)) End If @@ -308,7 +336,7 @@ Public Class Client 'now Checking whether the old row still remains in Vector? If not it will be deleted as it cannot be replaced in multivalues Dim oExists As Boolean = False For Each oNewValueRow As DataRow In oValueTable.Rows - _logger.Debug($"Checking oldValue[{oCurrentValue}] vs NewValue [{oNewValueRow.Item(1)}]") + Logger.Debug($"Checking oldValue[{oCurrentValue}] vs NewValue [{oNewValueRow.Item(1)}]") If oNewValueRow.Item(1).ToString.ToUpper = oCurrentValue.ToString.ToUpper Then oExists = True @@ -317,12 +345,12 @@ Public Class Client Next If oExists = False Then - _logger.Debug($"Value [{oCurrentValue}] no longer existing in Vector-Attribute [{pAttributeName}] - will be deleted!") + 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!") + Logger.Debug($"Value [{oCurrentValue}] of Attribute [{pAttributeName}] obviously was updated during runtime - will be deleted!") DeleteTermObjectFromMetadata(pObjectId, pAttributeName, oCurrentValue.Value) End If @@ -348,7 +376,7 @@ Public Class Client End If Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return False End Try End Function @@ -367,14 +395,14 @@ Public Class Client ' Check if ObjectId exists Try - Dim oResponse = _channel.TestObjectIdExists(New TestObjectIdExistsRequest With {.ObjectId = pObjectId}) + Dim oResponse = Channel.TestObjectIdExists(New TestObjectIdExistsRequest With {.ObjectId = pObjectId}) If oResponse.Exists = False Then Return New VariableValue() End If Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return New VariableValue() End Try @@ -407,7 +435,7 @@ Public Class Client End If Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return New VariableValue() End Try @@ -452,7 +480,7 @@ Public Class Client Return oAttributeValue Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return Nothing End Try @@ -462,7 +490,7 @@ Public Class Client Dim oAttributes As New List(Of ObjectAttribute) Try - Dim oResult As TableResult = _channel.ReturnDatatable_MSSQL_IDB($"EXEC [PRIDB_GET_VALUE_DT] {pObjectId}, '{pLanguage}'") + 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) @@ -488,7 +516,7 @@ Public Class Client Return oAttributes Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return Nothing End Try End Function @@ -503,11 +531,11 @@ Public Class Client 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) + Dim oResult = Channel.ExecuteNonQuery_MSSQL_IDB(oSql) If oResult.OK = False Then - _logger.Warn("Error while deleting Term object") - _logger.Error(oResult.ErrorMessage) + Logger.Warn("Error while deleting Term object") + Logger.Error(oResult.ErrorMessage) End If Return oResult.OK @@ -520,92 +548,92 @@ Public Class Client 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) + Dim oResult = Channel.ExecuteNonQuery_MSSQL_IDB(oDELSQL) If oResult.OK = False Then - _logger.Warn("Error while deleting Term object") - _logger.Error(oResult.ErrorMessage) + Logger.Warn("Error while deleting Term object") + Logger.Error(oResult.ErrorMessage) End If Return oResult.OK Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Return False End Try End Function Public Function GetDatatableFromIDB(pSQL As String, Optional pConnectionId As Integer = 0) As GetDatatableResponse Try - Dim oResponse = _channel.ReturnDatatable(New GetDatatableRequest() With { + Dim oResponse = Channel.ReturnDatatable(New GetDatatableRequest() With { .SqlCommand = pSQL, .NamedDatabase = DatabaseName.IDB, .ConnectionId = pConnectionId }) Return oResponse Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Throw ex End Try End Function Public Async Function GetDatatableFromIDBAsync(pSQL As String, Optional pConnectionId As Integer = 0) As Task(Of GetDatatableResponse) Try - Dim oResponse = Await _channel.ReturnDatatableAsync(New GetDatatableRequest() With { + Dim oResponse = Await Channel.ReturnDatatableAsync(New GetDatatableRequest() With { .SqlCommand = pSQL, .NamedDatabase = DatabaseName.IDB, .ConnectionId = pConnectionId }) Return oResponse Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Throw ex End Try End Function Public Function GetScalarValueFromIDB(pSQL As String, Optional pConnectionId As Integer = 0) As GetScalarValueResponse Try - Dim oResponse = _channel.ReturnScalarValue(New GetScalarValueRequest() With { + Dim oResponse = Channel.ReturnScalarValue(New GetScalarValueRequest() With { .SqlCommand = pSQL, .NamedDatabase = DatabaseName.IDB, .ConnectionId = pConnectionId }) Return oResponse Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Throw ex End Try End Function Public Async Function GetScalarValueFromIDBAsync(pSQL As String, Optional pConnectionId As Integer = 0) As Task(Of GetScalarValueResponse) Try - Dim oResponse = Await _channel.ReturnScalarValueAsync(New GetScalarValueRequest() With { + Dim oResponse = Await Channel.ReturnScalarValueAsync(New GetScalarValueRequest() With { .SqlCommand = pSQL, .NamedDatabase = DatabaseName.IDB, .ConnectionId = pConnectionId }) Return oResponse Catch ex As Exception - _logger.Error(ex) + 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) + Dim oResponse = Channel.ReturnDatatableFromCache(DatatableName, FilterExpression, SortByColumn) Return oResponse Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Throw ex End Try End Function Public Async Function GetDatatableByNameAsync(DatatableName As String, Optional FilterExpression As String = "", Optional SortByColumn As String = "") As Task(Of TableResult) Try - Dim oResponse = _channel.ReturnDatatableFromCache(DatatableName, FilterExpression, SortByColumn) + Dim oResponse = Await Channel.ReturnDatatableFromCacheAsync(DatatableName, FilterExpression, SortByColumn) Return oResponse Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Throw ex End Try End Function @@ -618,7 +646,7 @@ Public Class Client ''' Public Function GetDocumentInfo(UserId As Long, ObjectId As Long) As DocumentInfo Try - Dim oResponse As DocumentInfoResponse = _channel.GetFileInfoByObjectId(New DocumentInfoRequest With { + Dim oResponse As DocumentInfoResponse = Channel.GetFileInfoByObjectId(New DocumentInfoRequest With { .ObjectId = ObjectId, .UserId = UserId }) @@ -629,15 +657,15 @@ Public Class Client } Catch ex As FaultException(Of ObjectDoesNotExistFault) - _logger.Error(ex) + Logger.Error(ex) Throw ex Catch ex As FaultException - _logger.Error(ex) + Logger.Error(ex) Throw ex Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Throw ex End Try @@ -649,14 +677,14 @@ Public Class Client .ObjectId = ObjectId, .UserId = UserId } - Dim oResponse As DocumentInfoResponse = Await _channel.GetFileInfoByObjectIdAsync(oParams) + 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) + Logger.Error(ex) Throw ex End Try End Function @@ -669,14 +697,14 @@ Public Class Client ''' A channel object Private Function GetChannel() As IEDMIServiceChannel Try - _logger.Debug("...Creating channel..") - Dim oChannel = _channelFactory.CreateChannel() + Logger.Debug("...Creating channel..") + Dim oChannel = ChannelFactory.CreateChannel() AddHandler oChannel.Faulted, AddressOf Reconnect Return oChannel Catch ex As Exception - _logger.Error(ex) + Logger.Error(ex) Throw ex End Try End Function diff --git a/Modules.EDMIAPI/Connected Services/EDMIServiceReference/DigitalData.Services.EDMIService.wsdl b/Modules.EDMIAPI/Connected Services/EDMIServiceReference/DigitalData.Services.EDMIService.wsdl index 8c7c0df6..d6ba8df7 100644 --- a/Modules.EDMIAPI/Connected Services/EDMIServiceReference/DigitalData.Services.EDMIService.wsdl +++ b/Modules.EDMIAPI/Connected Services/EDMIServiceReference/DigitalData.Services.EDMIService.wsdl @@ -4,6 +4,7 @@ + @@ -17,7 +18,6 @@ - @@ -29,6 +29,12 @@ + + + + + + @@ -203,6 +209,10 @@ + + + + diff --git a/Modules.EDMIAPI/Connected Services/EDMIServiceReference/DigitalData.Services.EDMIService.xsd b/Modules.EDMIAPI/Connected Services/EDMIServiceReference/DigitalData.Services.EDMIService.xsd index 526cecdd..ca415ab6 100644 --- a/Modules.EDMIAPI/Connected Services/EDMIServiceReference/DigitalData.Services.EDMIService.xsd +++ b/Modules.EDMIAPI/Connected Services/EDMIServiceReference/DigitalData.Services.EDMIService.xsd @@ -1,5 +1,6 @@  + @@ -21,6 +22,18 @@ + + + + + + + + + + + + @@ -33,35 +46,35 @@ - + - + - + - + - + @@ -75,7 +88,7 @@ - + @@ -89,7 +102,7 @@ - + @@ -103,7 +116,7 @@ - + @@ -117,7 +130,7 @@ - + @@ -131,7 +144,7 @@ - + @@ -145,7 +158,7 @@ - + @@ -159,7 +172,7 @@ - + @@ -173,7 +186,7 @@ - + @@ -187,63 +200,63 @@ - + - + - + - + - + - + - + - + - + @@ -257,7 +270,7 @@ - + @@ -273,7 +286,7 @@ - + diff --git a/Modules.EDMIAPI/Connected Services/EDMIServiceReference/Reference.svcmap b/Modules.EDMIAPI/Connected Services/EDMIServiceReference/Reference.svcmap index 96647e1a..656e958c 100644 --- a/Modules.EDMIAPI/Connected Services/EDMIServiceReference/Reference.svcmap +++ b/Modules.EDMIAPI/Connected Services/EDMIServiceReference/Reference.svcmap @@ -26,6 +26,7 @@ + @@ -39,7 +40,6 @@ - diff --git a/Modules.EDMIAPI/Connected Services/EDMIServiceReference/Reference.vb b/Modules.EDMIAPI/Connected Services/EDMIServiceReference/Reference.vb index 07209323..66e70bf4 100644 --- a/Modules.EDMIAPI/Connected Services/EDMIServiceReference/Reference.vb +++ b/Modules.EDMIAPI/Connected Services/EDMIServiceReference/Reference.vb @@ -110,6 +110,7 @@ Namespace EDMIServiceReference System.Runtime.Serialization.DataContractAttribute(Name:="ScalarResult", [Namespace]:="http://schemas.datacontract.org/2004/07/DigitalData.Services.EDMIService.Messages"& _ ""), _ System.SerializableAttribute(), _ + System.Runtime.Serialization.KnownTypeAttribute(GetType(String())), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.TableResult)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.BaseResponse)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.NonQueryResult)), _ @@ -137,7 +138,6 @@ Namespace EDMIServiceReference System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.SetAttributeValueResponse)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.ImportFileRequest)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.ImportFileResponse)), _ - System.Runtime.Serialization.KnownTypeAttribute(GetType(String())), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.GetFileObjectRequest)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.GetFileObjectResponse)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.FileObject)), _ @@ -201,6 +201,7 @@ Namespace EDMIServiceReference System.Runtime.Serialization.DataContractAttribute(Name:="GetScalarValueResponse", [Namespace]:="http://schemas.datacontract.org/2004/07/DigitalData.Services.EDMIService.Methods."& _ "Database.GetScalarValue"), _ System.SerializableAttribute(), _ + System.Runtime.Serialization.KnownTypeAttribute(GetType(String())), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.TableResult)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.BaseResponse)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.ScalarResult)), _ @@ -228,7 +229,6 @@ Namespace EDMIServiceReference System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.SetAttributeValueResponse)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.ImportFileRequest)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.ImportFileResponse)), _ - System.Runtime.Serialization.KnownTypeAttribute(GetType(String())), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.GetFileObjectRequest)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.GetFileObjectResponse)), _ System.Runtime.Serialization.KnownTypeAttribute(GetType(EDMIServiceReference.FileObject)), _ @@ -1749,6 +1749,12 @@ Namespace EDMIServiceReference _ Function HeartbeatAsync() As System.Threading.Tasks.Task(Of Boolean) + _ + Function GetCachedTables() As String() + + _ + Function GetCachedTablesAsync() As System.Threading.Tasks.Task(Of String()) + + + + + + + + + + diff --git a/Modules.EDMIAPI/DatabaseWithFallback.vb b/Modules.EDMIAPI/DatabaseWithFallback.vb index 60e145cc..39258c1c 100644 --- a/Modules.EDMIAPI/DatabaseWithFallback.vb +++ b/Modules.EDMIAPI/DatabaseWithFallback.vb @@ -11,25 +11,41 @@ Public Class DatabaseWithFallback Private ReadOnly _DatabaseEDM As MSSQLServer Private ReadOnly _DatabaseIDB As MSSQLServer - Public Enum TableType - TBIDB_ATTRIBUTE - End Enum - - Public Class Table - Public TableName As String - Public SQLCommand As String - Public DatabaseType As Constants.DatabaseType + ''' + ''' Options for GetDatatable + ''' + Public Class GetDatatableOptions + Public ReadOnly FallbackSQL + Public ReadOnly FallbackType + + ''' + ''' Filter expression for the cached Datatable + ''' + Public Property FilterExpression As String = "" + ''' + ''' Columns to sort the cached Datatable by + ''' + Public Property SortByColumn As String = "" + ''' + ''' Force the fallback, skipping the service completely + ''' + Public Property ForceFallback As Boolean = False + ''' + ''' Connection Id to use, references TBDD_CONNECTION + ''' + Public Property ConnectionId As Integer = 0 + + ''' + ''' Creates a new options object for GetDatatable options + ''' + ''' SQL Command to execute as fallback + ''' Named Database to use for the fallback SQL Command + Public Sub New(pFallbackSQL As String, pFallbackType As Constants.DatabaseType) + FallbackSQL = pFallbackSQL + FallbackType = pFallbackType + End Sub End Class - Public Property Tables As New List(Of Table) From { - New Table With { - .DatabaseType = Constants.DatabaseType.IDB, - .TableName = "TBIDB_ATTRIBUTE", - .SQLCommand = "SELECT * FROM TBIDB_ATTRIBUTE" - } - } - - Public Sub New(LogConfig As LogConfig, Client As Client, DatabaseECM As MSSQLServer, DatabaseIDB As MSSQLServer) _Logger = LogConfig.GetLogger() _Client = Client @@ -37,42 +53,95 @@ Public Class DatabaseWithFallback _DatabaseIDB = DatabaseIDB End Sub - Public Function GetDatatable(pDataTableName As String, pFallbackSQL As String, pFallbackType As Constants.DatabaseType, Optional pFilterExpression As String = "", Optional pSortByColumn As String = "", Optional pForceFallback As Boolean = False) As DataTable + ''' + ''' Returns a Datatable by trying to fetch a cached version from the service, then querying the database through the service and querying the database directly as fallback. + ''' + ''' Name of the Cached Datatable + ''' Options object + Public Function GetDatatable(pDataTableName As String, pOptions As GetDatatableOptions) As DataTable + Return GetDatatable(pDataTableName, pOptions.FallbackSQL, pOptions.FallbackType, pOptions.FilterExpression, pOptions.SortByColumn, pOptions.ForceFallback, pOptions.ConnectionId) + End Function + + ''' + ''' Returns a datatable directly from the database. + ''' + ''' Options object + Public Function GetDatatable(pOptions As GetDatatableOptions) As DataTable + Dim oForceFallback = True + Return GetDatatable("FORCE_FALLBACK", pOptions.FallbackSQL, pOptions.FallbackType, pOptions.FilterExpression, pOptions.SortByColumn, oForceFallback, pOptions.ConnectionId) + End Function + + ''' + ''' Returns a Datatable by trying to fetch a cached version from the service, then querying the database through the service and querying the database directly as fallback. + ''' + ''' Name of the Cached Datatable + ''' SQL Command to execute as fallback + ''' Named Database to use for the fallback SQL Command + ''' Filter expression for the cached Datatable + ''' Columns to sort the cached Datatable by + ''' Force the fallback, skipping the service completely + ''' Connection Id to use, references TBDD_CONNECTION + Public Function GetDatatable(pDataTableName As String, pFallbackSQL As String, pFallbackType As Constants.DatabaseType, Optional pFilterExpression As String = "", Optional pSortByColumn As String = "", Optional pForceFallback As Boolean = False, Optional pConnectionId As Integer = 0) As DataTable Try Dim oResult As DataTable = Nothing + Dim oTableResult As TableResult = Nothing - If pForceFallback = False Then - Dim oTableResult As TableResult + ' If there is no client, we assume there is no service (configured) + If _Client Is Nothing Then + Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId) + End If - Try - oTableResult = _Client.GetDatatableByName(pDataTableName, pFilterExpression, pSortByColumn) - Catch ex As Exception - _Logger.Error(ex) - oTableResult = Nothing - End Try + ' If ForceFallback flag is set, we go to database immediately + If pForceFallback Then + Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId) + End If - If oTableResult Is Nothing OrElse oTableResult.OK = False Then - _Logger.Warn("Datatable [{0}] could not be fetched from AppServer Cache. Falling back to direct Database Access.", pDataTableName) - Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType) - End If + ' If the table is not cached, we go to database immediately + If Not IsTableCached(pDataTableName) Then + Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId) + End If - Return oTableResult.Table + ' If there is a proper ConnectionId, we go to database immediately + If pConnectionId > 0 Then + Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId) + End If + + Try + oTableResult = _Client.GetDatatableByName(pDataTableName, pFilterExpression, pSortByColumn) + Catch ex As Exception + _Logger.Error(ex) + oTableResult = Nothing + End Try + + If oTableResult Is Nothing OrElse oTableResult.OK = False Then + _Logger.Warn("Datatable [{0}] could not be fetched from AppServer Cache. Falling back to direct Database Access.", pDataTableName) + Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType, pConnectionId) Else - Return GetDatatableFromDatabase(pFallbackSQL, pFallbackType) + Return oTableResult.Table End If + Catch ex As Exception _Logger.Error(ex) Return Nothing + End Try End Function - Private Function GetDatatableFromDatabase(SQLCommand As String, DatabaseType As Constants.DatabaseType) + Private Function IsTableCached(pName As String) As Boolean + If _Client Is Nothing Then + Return False + End If + + Return _Client.CachedTables.Contains(pName.ToUpper) + End Function + + Private Function GetDatatableFromDatabase(SQLCommand As String, DatabaseType As Constants.DatabaseType, pConnectionId As Integer) Try Select Case DatabaseType - Case DatabaseType.ECM + Case Constants.DatabaseType.ECM Return _DatabaseEDM.GetDatatable(SQLCommand) - Case DatabaseType.IDB + Case Constants.DatabaseType.IDB Return _DatabaseIDB.GetDatatable(SQLCommand) Case Else diff --git a/Service.EDMIService/EDMIService.vb b/Service.EDMIService/EDMIService.vb index 6f21b5c6..a680e9cf 100644 --- a/Service.EDMIService/EDMIService.vb +++ b/Service.EDMIService/EDMIService.vb @@ -100,7 +100,7 @@ Public Class EDMIService End Try End Function - Public Function GetDatatableFromCache(Name As String, FilterExpression As String, SortByColumn As String) As TableResult Implements IEDMIService.GetDatatableFromCache + Public Function ReturnDatatableFromCache(Name As String, FilterExpression As String, SortByColumn As String) As TableResult Implements IEDMIService.ReturnDatatableFromCache Dim oReturnDatatableFromCache As New GetDatatableFromCache.GetDatatableFromCacheMethod(LogConfig, MSSQL_IDB, MSSQL_ECM, GlobalState) Dim oResult = oReturnDatatableFromCache.Run(New GetDatatableFromCache.GetDatatableFromCacheRequest With { .DataTable = Name, @@ -115,13 +115,13 @@ Public Class EDMIService End If End Function - Public Function GetDatatable(pData As GetDatatable.GetDatatableRequest) As GetDatatable.GetDatatableResponse Implements IEDMIService.GetDatatable + Public Function ReturnDatatable(pData As GetDatatable.GetDatatableRequest) As GetDatatable.GetDatatableResponse Implements IEDMIService.ReturnDatatable _Logger.Debug("Start of Method [ReturnDatatable]") Dim oGetDatatable As New GetDatatable.GetDatatableMethod(LogConfig, MSSQL_IDB, MSSQL_ECM, GlobalState) Return oGetDatatable.Run(pData) End Function - Public Function GetScalarValue(pData As GetScalarValue.GetScalarValueRequest) As GetScalarValue.GetScalarValueResponse Implements IEDMIService.GetScalarValue + Public Function ReturnScalarValue(pData As GetScalarValue.GetScalarValueRequest) As GetScalarValue.GetScalarValueResponse Implements IEDMIService.ReturnScalarValue _Logger.Debug("Start of Method [ReturnScalarValue]") Dim oGetScalarValue As New GetScalarValue.GetScalarValueMethod(LogConfig, MSSQL_IDB, MSSQL_ECM, GlobalState) Return oGetScalarValue.Run(pData) diff --git a/Service.EDMIService/IEDMIService.vb b/Service.EDMIService/IEDMIService.vb index b99619a4..e58c6822 100644 --- a/Service.EDMIService/IEDMIService.vb +++ b/Service.EDMIService/IEDMIService.vb @@ -21,13 +21,13 @@ Interface IEDMIService - Function GetDatatableFromCache(Name As String, FilterExpression As String, SortByColumn As String) As TableResult + Function ReturnDatatableFromCache(Name As String, FilterExpression As String, SortByColumn As String) As TableResult - Function GetDatatable(pData As GetDatatable.GetDatatableRequest) As GetDatatable.GetDatatableResponse + Function ReturnDatatable(pData As GetDatatable.GetDatatableRequest) As GetDatatable.GetDatatableResponse - Function GetScalarValue(pData As GetScalarValue.GetScalarValueRequest) As GetScalarValue.GetScalarValueResponse + Function ReturnScalarValue(pData As GetScalarValue.GetScalarValueRequest) As GetScalarValue.GetScalarValueResponse #End Region #Region "Database (Firebird)"