From 8ce3e74e8112a94773df22827849bf274fc88198 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Sun, 24 Feb 2013 16:53:54 -0500 Subject: More DI --- MediaBrowser.Common/Kernel/BaseKernel.cs | 379 +++++++------------------------ 1 file changed, 88 insertions(+), 291 deletions(-) (limited to 'MediaBrowser.Common/Kernel/BaseKernel.cs') diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 28ccd8602..a5a9b46ec 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -2,16 +2,14 @@ using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Common.Serialization; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -24,7 +22,7 @@ namespace MediaBrowser.Common.Kernel /// The type of the T application paths type. public abstract class BaseKernel : IDisposable, IKernel where TConfigurationType : BaseApplicationConfiguration, new() - where TApplicationPathsType : BaseApplicationPaths, new() + where TApplicationPathsType : IApplicationPaths { /// /// Occurs when [has pending restart changed]. @@ -129,7 +127,7 @@ namespace MediaBrowser.Common.Kernel get { // Lazy load - LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => XmlSerializer.GetXmlConfiguration(ApplicationPaths.SystemConfigurationFilePath, Logger)); + LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationLoaded, ref _configurationSyncLock, () => GetXmlConfiguration(ApplicationPaths.SystemConfigurationFilePath)); return _configuration; } protected set @@ -161,19 +159,6 @@ namespace MediaBrowser.Common.Kernel /// The application paths. public TApplicationPathsType ApplicationPaths { get; private set; } - /// - /// The _failed assembly loads - /// - private readonly List _failedPluginAssemblies = new List(); - /// - /// Gets the plugin assemblies that failed to load. - /// - /// The failed assembly loads. - public IEnumerable FailedPluginAssemblies - { - get { return _failedPluginAssemblies; } - } - /// /// Gets the list of currently loaded plugins /// @@ -204,46 +189,6 @@ namespace MediaBrowser.Common.Kernel /// The rest services. public IEnumerable RestServices { get; private set; } - /// - /// The disposable parts - /// - private readonly List _disposableParts = new List(); - - /// - /// The _protobuf serializer initialized - /// - private bool _protobufSerializerInitialized; - /// - /// The _protobuf serializer sync lock - /// - private object _protobufSerializerSyncLock = new object(); - /// - /// Gets a dynamically compiled generated serializer that can serialize protocontracts without reflection - /// - private DynamicProtobufSerializer _protobufSerializer; - /// - /// Gets the protobuf serializer. - /// - /// The protobuf serializer. - public DynamicProtobufSerializer ProtobufSerializer - { - get - { - // Lazy load - LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => DynamicProtobufSerializer.Create(AllTypes)); - return _protobufSerializer; - } - private set - { - _protobufSerializer = value; - - if (value == null) - { - _protobufSerializerInitialized = false; - } - } - } - /// /// Gets the UDP server port number. /// This can't be configurable because then the user would have to configure their client to discover the server. @@ -301,42 +246,40 @@ namespace MediaBrowser.Common.Kernel protected IApplicationHost ApplicationHost { get; private set; } /// - /// Gets or sets the task manager. - /// - /// The task manager. - protected ITaskManager TaskManager { get; set; } - - /// - /// Gets the assemblies. + /// The _XML serializer /// - /// The assemblies. - protected Assembly[] Assemblies { get; private set; } - - /// - /// Gets all types. - /// - /// All types. - public Type[] AllTypes { get; private set; } + private readonly IXmlSerializer _xmlSerializer; /// /// Initializes a new instance of the class. /// /// The app host. + /// The app paths. + /// The XML serializer. /// The logger. /// isoManager - protected BaseKernel(IApplicationHost appHost, ILogger logger) + protected BaseKernel(IApplicationHost appHost, TApplicationPathsType appPaths, IXmlSerializer xmlSerializer, ILogger logger) { if (appHost == null) { throw new ArgumentNullException("appHost"); } - + if (appPaths == null) + { + throw new ArgumentNullException("appPaths"); + } + if (xmlSerializer == null) + { + throw new ArgumentNullException("xmlSerializer"); + } if (logger == null) { throw new ArgumentNullException("logger"); } + ApplicationPaths = appPaths; ApplicationHost = appHost; + _xmlSerializer = xmlSerializer; Logger = logger; } @@ -344,14 +287,12 @@ namespace MediaBrowser.Common.Kernel /// Initializes the Kernel /// /// Task. - public async Task Init() + public Task Init() { - ApplicationPaths = new TApplicationPathsType(); - IsFirstRun = !File.Exists(ApplicationPaths.SystemConfigurationFilePath); // Performs initializations that can be reloaded at anytime - await Reload().ConfigureAwait(false); + return Reload(); } /// @@ -377,7 +318,6 @@ namespace MediaBrowser.Common.Kernel { // Set these to null so that they can be lazy loaded again Configuration = null; - ProtobufSerializer = null; ReloadLogger(); @@ -388,14 +328,12 @@ namespace MediaBrowser.Common.Kernel await OnConfigurationLoaded().ConfigureAwait(false); - DisposeTaskManager(); - TaskManager = new TaskManager(Logger); + FindParts(); - Logger.Info("Loading Plugins"); - await ReloadComposableParts().ConfigureAwait(false); + await OnComposablePartsLoaded().ConfigureAwait(false); DisposeTcpManager(); - TcpManager = new TcpManager(ApplicationHost, this, ApplicationHost.Resolve(), Logger); + TcpManager = (TcpManager)ApplicationHost.CreateInstance(typeof(TcpManager)); } /// @@ -417,184 +355,14 @@ namespace MediaBrowser.Common.Kernel OnLoggerLoaded(); } - /// - /// Uses MEF to locate plugins - /// Subclasses can use this to locate types within plugins - /// - /// Task. - private async Task ReloadComposableParts() - { - _failedPluginAssemblies.Clear(); - - DisposeComposableParts(); - - Assemblies = GetComposablePartAssemblies().ToArray(); - - AllTypes = Assemblies.SelectMany(GetTypes).ToArray(); - - ComposeParts(AllTypes); - - await OnComposablePartsLoaded().ConfigureAwait(false); - } - - /// - /// Composes the parts. - /// - /// All types. - private void ComposeParts(IEnumerable allTypes) - { - var concreteTypes = allTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray(); - - RegisterExportedValues(); - - FindParts(concreteTypes); - } - /// /// Composes the parts with ioc container. /// - /// All types. - protected virtual void FindParts(Type[] allTypes) - { - RestServices = GetExports(allTypes); - WebSocketListeners = GetExports(allTypes); - Plugins = GetExports(allTypes); - - var tasks = GetExports(allTypes, false); - - TaskManager.AddTasks(tasks); - } - - /// - /// Gets the exports. - /// - /// - /// All types. - /// if set to true [manage liftime]. - /// IEnumerable{``0}. - protected IEnumerable GetExports(Type[] allTypes, bool manageLiftime = true) - { - var currentType = typeof(T); - - Logger.Info("Composing instances of " + currentType.Name); - - var parts = allTypes.Where(currentType.IsAssignableFrom).Select(Instantiate).Cast().ToArray(); - - if (manageLiftime) - { - _disposableParts.AddRange(parts.OfType()); - } - - return parts; - } - - /// - /// Instantiates the specified type. - /// - /// The type. - /// System.Object. - private object Instantiate(Type type) - { - return ApplicationHost.CreateInstance(type); - } - - /// - /// Composes the exported values. - /// - /// The container. - protected virtual void RegisterExportedValues() + protected virtual void FindParts() { - ApplicationHost.RegisterSingleInstance(this); - ApplicationHost.RegisterSingleInstance(TaskManager); - } - - /// - /// Gets the composable part assemblies. - /// - /// IEnumerable{Assembly}. - protected virtual IEnumerable GetComposablePartAssemblies() - { - // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that - // This will prevent the .dll file from getting locked, and allow us to replace it when needed - var pluginAssemblies = Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly) - .Select(file => - { - try - { - return Assembly.Load(File.ReadAllBytes((file))); - } - catch (Exception ex) - { - _failedPluginAssemblies.Add(file); - Logger.ErrorException("Error loading {0}", ex, file); - return null; - } - - }).Where(a => a != null); - - foreach (var pluginAssembly in pluginAssemblies) - { - yield return pluginAssembly; - } - - var runningDirectory = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); - var corePluginDirectory = Path.Combine(runningDirectory, "CorePlugins"); - - // This will prevent the .dll file from getting locked, and allow us to replace it when needed - pluginAssemblies = Directory.EnumerateFiles(corePluginDirectory, "*.dll", SearchOption.TopDirectoryOnly) - .Select(file => - { - try - { - return Assembly.Load(File.ReadAllBytes((file))); - } - catch (Exception ex) - { - _failedPluginAssemblies.Add(file); - Logger.ErrorException("Error loading {0}", ex, file); - return null; - } - - }).Where(a => a != null); - - foreach (var pluginAssembly in pluginAssemblies) - { - yield return pluginAssembly; - } - - // Include composable parts in the Model assembly - yield return typeof(SystemInfo).Assembly; - - // Include composable parts in the Common assembly - yield return Assembly.GetExecutingAssembly(); - - // Include composable parts in the subclass assembly - yield return GetType().Assembly; - } - - /// - /// Gets a list of types within an assembly - /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference - /// - /// The assembly. - /// IEnumerable{Type}. - /// assembly - private static IEnumerable GetTypes(Assembly assembly) - { - if (assembly == null) - { - throw new ArgumentNullException("assembly"); - } - - try - { - return assembly.GetTypes(); - } - catch (ReflectionTypeLoadException ex) - { - // If it fails we can still get a list of the Types it was able to resolve - return ex.Types.Where(t => t != null); - } + RestServices = ApplicationHost.GetExports(); + WebSocketListeners = ApplicationHost.GetExports(); + Plugins = ApplicationHost.GetExports(); } /// @@ -612,7 +380,7 @@ namespace MediaBrowser.Common.Kernel try { - plugin.Initialize(this, Logger); + plugin.Initialize(this, _xmlSerializer, Logger); Logger.Info("{0} {1} initialized.", plugin.Name, plugin.Version); } @@ -654,12 +422,7 @@ namespace MediaBrowser.Common.Kernel if (dispose) { DisposeTcpManager(); - DisposeTaskManager(); DisposeHttpManager(); - - DisposeComposableParts(); - - _disposableParts.Clear(); } } @@ -675,18 +438,6 @@ namespace MediaBrowser.Common.Kernel } } - /// - /// Disposes the task manager. - /// - private void DisposeTaskManager() - { - if (TaskManager != null) - { - TaskManager.Dispose(); - TaskManager = null; - } - } - /// /// Disposes the HTTP manager. /// @@ -699,17 +450,6 @@ namespace MediaBrowser.Common.Kernel } } - /// - /// Disposes all objects gathered through MEF composable parts - /// - protected virtual void DisposeComposableParts() - { - foreach (var part in _disposableParts) - { - part.Dispose(); - } - } - /// /// Gets the current application version /// @@ -761,7 +501,7 @@ namespace MediaBrowser.Common.Kernel IsNetworkDeployed = ApplicationHost.CanSelfUpdate, WebSocketPortNumber = TcpManager.WebSocketPortNumber, SupportsNativeWebSocket = TcpManager.SupportsNativeWebSocket, - FailedPluginAssemblies = FailedPluginAssemblies.ToArray() + FailedPluginAssemblies = ApplicationHost.FailedAssemblies.ToArray() }; } @@ -777,7 +517,7 @@ namespace MediaBrowser.Common.Kernel { lock (_configurationSaveLock) { - XmlSerializer.SerializeToFile(Configuration, ApplicationPaths.SystemConfigurationFilePath); + _xmlSerializer.SerializeToFile(Configuration, ApplicationPaths.SystemConfigurationFilePath); } OnConfigurationUpdated(); @@ -787,7 +527,7 @@ namespace MediaBrowser.Common.Kernel /// Gets the application paths. /// /// The application paths. - BaseApplicationPaths IKernel.ApplicationPaths + IApplicationPaths IKernel.ApplicationPaths { get { return ApplicationPaths; } } @@ -798,6 +538,63 @@ namespace MediaBrowser.Common.Kernel BaseApplicationConfiguration IKernel.Configuration { get { return Configuration; } + } + + /// + /// Reads an xml configuration file from the file system + /// It will immediately re-serialize and save if new serialization data is available due to property changes + /// + /// The type. + /// The path. + /// System.Object. + public object GetXmlConfiguration(Type type, string path) + { + Logger.Info("Loading {0} at {1}", type.Name, path); + + object configuration; + + byte[] buffer = null; + + // Use try/catch to avoid the extra file system lookup using File.Exists + try + { + buffer = File.ReadAllBytes(path); + + configuration = _xmlSerializer.DeserializeFromBytes(type, buffer); + } + catch (FileNotFoundException) + { + configuration = ApplicationHost.CreateInstance(type); + } + + // Take the object we just got and serialize it back to bytes + var newBytes = _xmlSerializer.SerializeToBytes(configuration); + + // If the file didn't exist before, or if something has changed, re-save + if (buffer == null || !buffer.SequenceEqual(newBytes)) + { + Logger.Info("Saving {0} to {1}", type.Name, path); + + // Save it after load in case we got new items + File.WriteAllBytes(path, newBytes); + } + + return configuration; + } + + + /// + /// Reads an xml configuration file from the file system + /// It will immediately save the configuration after loading it, just + /// in case there are new serializable properties + /// + /// + /// The path. + /// ``0. + private T GetXmlConfiguration(string path) + where T : class + { + return GetXmlConfiguration(typeof(T), path) as T; } } } -- cgit v1.2.3