using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
namespace MediaBrowser.Common.Implementations.Configuration
{
///
/// Class BaseConfigurationManager
///
public abstract class BaseConfigurationManager : IConfigurationManager
{
///
/// Gets the type of the configuration.
///
/// The type of the configuration.
protected abstract Type ConfigurationType { get; }
///
/// Occurs when [configuration updated].
///
public event EventHandler ConfigurationUpdated;
///
/// Occurs when [configuration updating].
///
public event EventHandler NamedConfigurationUpdating;
///
/// Occurs when [named configuration updated].
///
public event EventHandler NamedConfigurationUpdated;
///
/// Gets the logger.
///
/// The logger.
protected ILogger Logger { get; private set; }
///
/// Gets the XML serializer.
///
/// The XML serializer.
protected IXmlSerializer XmlSerializer { get; private set; }
///
/// Gets or sets the application paths.
///
/// The application paths.
public IApplicationPaths CommonApplicationPaths { get; private set; }
///
/// The _configuration loaded
///
private bool _configurationLoaded;
///
/// The _configuration sync lock
///
private object _configurationSyncLock = new object();
///
/// The _configuration
///
private BaseApplicationConfiguration _configuration;
///
/// Gets the system configuration
///
/// The configuration.
public BaseApplicationConfiguration CommonConfiguration
{
get
{
// Lazy load
LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => (BaseApplicationConfiguration)ConfigurationHelper.GetXmlConfiguration(ConfigurationType, CommonApplicationPaths.SystemConfigurationFilePath, XmlSerializer));
return _configuration;
}
protected set
{
_configuration = value;
_configurationLoaded = value != null;
}
}
private ConfigurationStore[] _configurationStores = {};
private IConfigurationFactory[] _configurationFactories = {};
///
/// Initializes a new instance of the class.
///
/// The application paths.
/// The log manager.
/// The XML serializer.
protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILogManager logManager, IXmlSerializer xmlSerializer)
{
CommonApplicationPaths = applicationPaths;
XmlSerializer = xmlSerializer;
Logger = logManager.GetLogger(GetType().Name);
UpdateCachePath();
}
public void AddParts(IEnumerable factories)
{
_configurationFactories = factories.ToArray();
_configurationStores = _configurationFactories
.SelectMany(i => i.GetConfigurations())
.ToArray();
}
///
/// Saves the configuration.
///
public void SaveConfiguration()
{
var path = CommonApplicationPaths.SystemConfigurationFilePath;
Directory.CreateDirectory(Path.GetDirectoryName(path));
lock (_configurationSyncLock)
{
XmlSerializer.SerializeToFile(CommonConfiguration, path);
}
OnConfigurationUpdated();
}
///
/// Called when [configuration updated].
///
protected virtual void OnConfigurationUpdated()
{
UpdateCachePath();
EventHelper.QueueEventIfNotNull(ConfigurationUpdated, this, EventArgs.Empty, Logger);
}
///
/// Replaces the configuration.
///
/// The new configuration.
/// newConfiguration
public virtual void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration)
{
if (newConfiguration == null)
{
throw new ArgumentNullException("newConfiguration");
}
ValidateCachePath(newConfiguration);
CommonConfiguration = newConfiguration;
SaveConfiguration();
}
///
/// Updates the items by name path.
///
private void UpdateCachePath()
{
((BaseApplicationPaths)CommonApplicationPaths).CachePath = string.IsNullOrEmpty(CommonConfiguration.CachePath) ?
null :
CommonConfiguration.CachePath;
}
///
/// Replaces the cache path.
///
/// The new configuration.
///
private void ValidateCachePath(BaseApplicationConfiguration newConfig)
{
var newPath = newConfig.CachePath;
if (!string.IsNullOrWhiteSpace(newPath)
&& !string.Equals(CommonConfiguration.CachePath ?? string.Empty, newPath))
{
// Validate
if (!Directory.Exists(newPath))
{
throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
}
}
}
private readonly ConcurrentDictionary _configurations = new ConcurrentDictionary();
private string GetConfigurationFile(string key)
{
return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLower() + ".xml");
}
public object GetConfiguration(string key)
{
return _configurations.GetOrAdd(key, k =>
{
var file = GetConfigurationFile(key);
var configurationType = _configurationStores
.First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase))
.ConfigurationType;
lock (_configurationSyncLock)
{
return ConfigurationHelper.GetXmlConfiguration(configurationType, file, XmlSerializer);
}
});
}
public void SaveConfiguration(string key, object configuration)
{
var configurationType = GetConfigurationType(key);
if (configuration.GetType() != configurationType)
{
throw new ArgumentException("Expected configuration type is " + configurationType.Name);
}
EventHelper.FireEventIfNotNull(NamedConfigurationUpdating, this, new ConfigurationUpdateEventArgs
{
Key = key,
NewConfiguration = configuration
}, Logger);
_configurations.AddOrUpdate(key, configuration, (k, v) => configuration);
var path = GetConfigurationFile(key);
Directory.CreateDirectory(Path.GetDirectoryName(path));
lock (_configurationSyncLock)
{
XmlSerializer.SerializeToFile(configuration, path);
}
EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs
{
Key = key,
NewConfiguration = configuration
}, Logger);
}
public Type GetConfigurationType(string key)
{
return _configurationStores
.First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase))
.ConfigurationType;
}
}
}