Imports System.IO
Imports System.Xml.Serialization
Imports DigitalData.Modules.Logging
Public Class ConfigManager(Of T)
Private Const USER_CONFIG_NAME As String = "UserConfig.xml"
Private Const COMPUTER_CONFIG_NAME As String = "ComputerConfig.xml"
Private ReadOnly _LogConfig As LogConfig
Private ReadOnly _Logger As Logger
Private ReadOnly _File As Filesystem.File
Private ReadOnly _UserPath As String
Private ReadOnly _ComputerPath As String
Private _CurrentDataPath As String
'''
''' The blueprint class from which the default config is created
'''
Private ReadOnly _Blueprint As T
Private ReadOnly _Serializer As XmlSerializer
Public ReadOnly Property Config As T
'''
''' Creates a new instance of the ConfigManager
'''
'''
''' Public Class Config
''' Public Property StringEntry As String = "TEST"
''' Public Property BoolEntry As Boolean = True
''' Public Property IntEntry As Integer = 123
''' End Class
'''
''' Dim oConfigManager = New ConfigManager(Of Config)(_LogConfig, Application.UserAppDataPath, Application.CommonAppDataPath)
'''
''' LogConfig instance
''' The first path to check for a config file, eg. AppData
''' The second path to check for a config file, eg. ProgramData
Public Sub New(LogConfig As LogConfig, UserConfigPath As String, ComputerConfigPath As String)
_LogConfig = LogConfig
_Logger = LogConfig.GetLogger()
_File = New Filesystem.File(_LogConfig)
_UserPath = Path.Combine(UserConfigPath, USER_CONFIG_NAME)
_ComputerPath = Path.Combine(ComputerConfigPath, COMPUTER_CONFIG_NAME)
_Blueprint = Activator.CreateInstance(Of T)
_Serializer = New XmlSerializer(_Blueprint.GetType)
If Not Directory.Exists(UserConfigPath) Then
_Logger.Debug("UserConfigPath {0} did not exist and was created", UserConfigPath)
Directory.CreateDirectory(UserConfigPath)
End If
If Not _File.TestPathIsDirectory(UserConfigPath) Then
_Logger.Warn("UserConfigPath {0} is not a directory", UserConfigPath)
Throw New ArgumentException($"Path {UserConfigPath} is not a directory!")
End If
If Not Directory.Exists(ComputerConfigPath) Then
_Logger.Debug("ComputerConfigPath {0} did not exist and was created", ComputerConfigPath)
Directory.CreateDirectory(ComputerConfigPath)
End If
If Not _File.TestPathIsDirectory(ComputerConfigPath) Then
_Logger.Warn("ComputerConfigPath {0} is not a directory", ComputerConfigPath)
Throw New ArgumentException($"Path {ComputerConfigPath} is not a directory!")
End If
_Config = LoadConfig()
End Sub
'''
''' Save the current config object to `UserConfigPath`
'''
Public Sub Save()
WriteToFile(_Config, _UserPath)
End Sub
'''
''' First check if a user config exists and if it does, load it.
''' If not, check if a systemwide config exists and and if it does, load it.
''' Otherwise, create a user config using the default values from the supplied config class `T`
'''
'''
Private Function LoadConfig() As T
Dim oConfig As T
If IO.File.Exists(_UserPath) Then
_Logger.Debug("Loading config from UserPath: {0}", _UserPath)
_CurrentDataPath = _UserPath
oConfig = ReadFromFile(_UserPath)
ElseIf IO.File.Exists(_ComputerPath) Then
_Logger.Debug("Loading config from ComputerPath: {0}", _ComputerPath)
_CurrentDataPath = _ComputerPath
oConfig = ReadFromFile(_ComputerPath)
Else
_Logger.Debug("Creating default config in UserPath: {0}", _UserPath)
_CurrentDataPath = _UserPath
oConfig = Activator.CreateInstance(_Blueprint.GetType)
WriteToFile(_Config, _UserPath)
End If
Return oConfig
End Function
'''
''' Serialize a config object to byte array
'''
'''
'''
Private Function Serialize(Data As T) As Byte()
Try
_Logger.Debug("Serializing config object")
Using oStream = New MemoryStream()
_Serializer.Serialize(oStream, Data)
Return oStream.ToArray()
End Using
Catch ex As Exception
_Logger.Error(ex)
Throw ex
End Try
End Function
'''
''' Write an object to disk as xml
'''
''' The object to write
''' The file name to write to
Private Sub WriteToFile(Data As T, Path As String)
Try
_Logger.Debug("Saving config to: {0}", Path)
Dim oBytes = Serialize(Data)
Using oFileStream = New FileStream(Path, FileMode.Create, FileAccess.Write)
oFileStream.Write(oBytes, 0, oBytes.Length)
oFileStream.Flush()
End Using
Catch ex As Exception
_Logger.Error(ex)
Throw ex
End Try
End Sub
'''
''' Reads an xml from disk and deserializes to object
'''
'''
Private Function ReadFromFile(Path As String) As T
Try
_Logger.Debug("Loading config from: {0}", Path)
Dim oConfig As T
Using oReader As New StreamReader(Path)
oConfig = _Serializer.Deserialize(oReader)
End Using
' If oConfig is Nothing, a config file was created but nothing was written to it.
' In this case we need to create oConfig from defaults so we have at least some config object
If oConfig Is Nothing Then
_Logger.Debug("Config file is valid but empty. Loading default values")
oConfig = Activator.CreateInstance(_Blueprint.GetType)
End If
Return oConfig
Catch ex As Exception
_Logger.Error(ex)
Throw ex
End Try
End Function
End Class