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; } } }