PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/V2.2/trunk/CAL/Desktop/Composite/Modularity/ModuleManager.cs

#
C# | 253 lines | 171 code | 32 blank | 50 comment | 37 complexity | c5c05c4d0c3effb23b914afe3225958b MD5 | raw file
  1. //===================================================================================
  2. // Microsoft patterns & practices
  3. // Composite Application Guidance for Windows Presentation Foundation and Silverlight
  4. //===================================================================================
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
  7. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
  8. // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  9. // FITNESS FOR A PARTICULAR PURPOSE.
  10. //===================================================================================
  11. // The example companies, organizations, products, domain names,
  12. // e-mail addresses, logos, people, places, and events depicted
  13. // herein are fictitious. No association with any real company,
  14. // organization, product, domain name, email address, logo, person,
  15. // places, or events is intended or should be inferred.
  16. //===================================================================================
  17. using System;
  18. using System.Collections.Generic;
  19. using System.Globalization;
  20. using System.Linq;
  21. using Microsoft.Practices.Composite.Logging;
  22. using Microsoft.Practices.Composite.Properties;
  23. namespace Microsoft.Practices.Composite.Modularity
  24. {
  25. /// <summary>
  26. /// Component responsible for coordinating the modules' type loading and module initialization process.
  27. /// </summary>
  28. public partial class ModuleManager : IModuleManager
  29. {
  30. private readonly IModuleInitializer moduleInitializer;
  31. private readonly IModuleCatalog moduleCatalog;
  32. private readonly ILoggerFacade loggerFacade;
  33. private IEnumerable<IModuleTypeLoader> typeLoaders;
  34. /// <summary>
  35. /// Initializes an instance of the <see cref="ModuleManager"/> class.
  36. /// </summary>
  37. /// <param name="moduleInitializer">Service used for initialization of modules.</param>
  38. /// <param name="moduleCatalog">Catalog that enumerates the modules to be loaded and initialized.</param>
  39. /// <param name="loggerFacade">Logger used during the load and initialization of modules.</param>
  40. public ModuleManager(IModuleInitializer moduleInitializer, IModuleCatalog moduleCatalog, ILoggerFacade loggerFacade)
  41. {
  42. if (moduleInitializer == null)
  43. {
  44. throw new ArgumentNullException("moduleInitializer");
  45. }
  46. if (moduleCatalog == null)
  47. {
  48. throw new ArgumentNullException("moduleCatalog");
  49. }
  50. if (loggerFacade == null)
  51. {
  52. throw new ArgumentNullException("loggerFacade");
  53. }
  54. this.moduleInitializer = moduleInitializer;
  55. this.moduleCatalog = moduleCatalog;
  56. this.loggerFacade = loggerFacade;
  57. }
  58. /// <summary>
  59. /// Initializes the modules marked as <see cref="InitializationMode.WhenAvailable"/> on the <see cref="ModuleCatalog"/>.
  60. /// </summary>
  61. public void Run()
  62. {
  63. this.moduleCatalog.Initialize();
  64. this.LoadModulesWhenAvailable();
  65. }
  66. /// <summary>
  67. /// Initializes the module on the <see cref="ModuleCatalog"/> with the name <paramref name="moduleName"/>.
  68. /// </summary>
  69. /// <param name="moduleName">Name of the module requested for initialization.</param>
  70. public void LoadModule(string moduleName)
  71. {
  72. IEnumerable<ModuleInfo> module = this.moduleCatalog.Modules.Where(m => m.ModuleName == moduleName);
  73. if (module == null || module.Count() != 1)
  74. {
  75. throw new ModuleNotFoundException(moduleName, string.Format(CultureInfo.CurrentCulture, Resources.ModuleNotFound, moduleName));
  76. }
  77. IEnumerable<ModuleInfo> modulesToLoad = this.moduleCatalog.CompleteListWithDependencies(module);
  78. this.LoadModuleTypes(modulesToLoad);
  79. }
  80. /// <summary>
  81. /// Checks if the module needs to be retrieved before it's initialized.
  82. /// </summary>
  83. /// <param name="moduleInfo">Module that is being checked if needs retrieval.</param>
  84. /// <returns></returns>
  85. protected virtual bool ModuleNeedsRetrieval(ModuleInfo moduleInfo)
  86. {
  87. if (moduleInfo.State == ModuleState.NotStarted)
  88. {
  89. // If we can instantiate the type, that means the module's assembly is already loaded into
  90. // the AppDomain and we don't need to retrieve it.
  91. bool isAvailable = Type.GetType(moduleInfo.ModuleType) != null;
  92. if (isAvailable)
  93. {
  94. moduleInfo.State = ModuleState.ReadyForInitialization;
  95. }
  96. return !isAvailable;
  97. }
  98. return false;
  99. }
  100. /// <summary>
  101. /// Handles any exception ocurred in the module typeloading process,
  102. /// logs the error using the <seealso cref="ILoggerFacade"/> and throws a <seealso cref="ModuleTypeLoadingException"/>.
  103. /// This method can be overriden to provide a different behavior.
  104. /// </summary>
  105. /// <param name="moduleInfo">The module metadata where the error happenened.</param>
  106. /// <param name="exception">The exception thrown that is the cause of the current error.</param>
  107. /// <exception cref="ModuleTypeLoadingException"></exception>
  108. protected virtual void HandleModuleTypeLoadingError(ModuleInfo moduleInfo, Exception exception)
  109. {
  110. ModuleTypeLoadingException moduleTypeLoadingException = exception as ModuleTypeLoadingException;
  111. if (moduleTypeLoadingException == null)
  112. {
  113. moduleTypeLoadingException = new ModuleTypeLoadingException(moduleInfo.ModuleName, exception.Message, exception);
  114. }
  115. this.loggerFacade.Log(moduleTypeLoadingException.Message, Category.Exception, Priority.High);
  116. throw moduleTypeLoadingException;
  117. }
  118. private void LoadModulesWhenAvailable()
  119. {
  120. IEnumerable<ModuleInfo> whenAvailableModules = this.moduleCatalog.Modules.Where(m => m.InitializationMode == InitializationMode.WhenAvailable);
  121. IEnumerable<ModuleInfo> modulesToLoadTypes = this.moduleCatalog.CompleteListWithDependencies(whenAvailableModules);
  122. if (modulesToLoadTypes != null)
  123. {
  124. this.LoadModuleTypes(modulesToLoadTypes);
  125. }
  126. }
  127. private void LoadModuleTypes(IEnumerable<ModuleInfo> moduleInfos)
  128. {
  129. if (moduleInfos == null)
  130. {
  131. return;
  132. }
  133. foreach (ModuleInfo moduleInfo in moduleInfos)
  134. {
  135. if (moduleInfo.State == ModuleState.NotStarted)
  136. {
  137. if (this.ModuleNeedsRetrieval(moduleInfo))
  138. {
  139. this.BeginRetrievingModule(moduleInfo);
  140. }
  141. else
  142. {
  143. moduleInfo.State = ModuleState.ReadyForInitialization;
  144. }
  145. }
  146. }
  147. this.LoadModulesThatAreReadyForLoad();
  148. }
  149. private void BeginRetrievingModule(ModuleInfo moduleInfo)
  150. {
  151. ModuleInfo moduleInfoToLoadType = moduleInfo;
  152. IModuleTypeLoader moduleTypeLoader = this.GetTypeLoaderForModule(moduleInfoToLoadType);
  153. moduleInfoToLoadType.State = ModuleState.LoadingTypes;
  154. moduleTypeLoader.BeginLoadModuleType(moduleInfo, this.OnModuleTypeLoaded);
  155. }
  156. private void OnModuleTypeLoaded(ModuleInfo typeLoadedModuleInfo, Exception error)
  157. {
  158. if (error == null)
  159. {
  160. typeLoadedModuleInfo.State = ModuleState.ReadyForInitialization;
  161. // This callback may call back on the UI thread, but we are not guaranteeing it.
  162. // If you were to add a custom retriever that retrieved in the background, you
  163. // would need to consider dispatching to the UI thread.
  164. this.LoadModulesThatAreReadyForLoad();
  165. }
  166. else
  167. {
  168. this.HandleModuleTypeLoadingError(typeLoadedModuleInfo, error);
  169. }
  170. }
  171. private void LoadModulesThatAreReadyForLoad()
  172. {
  173. bool keepLoading = true;
  174. while (keepLoading)
  175. {
  176. keepLoading = false;
  177. IEnumerable<ModuleInfo> availableModules = this.moduleCatalog.Modules.Where(m => m.State == ModuleState.ReadyForInitialization);
  178. foreach (ModuleInfo moduleInfo in availableModules)
  179. {
  180. if (this.AreDependenciesLoaded(moduleInfo))
  181. {
  182. moduleInfo.State = ModuleState.Initializing;
  183. this.InitializeModule(moduleInfo);
  184. keepLoading = true;
  185. break;
  186. }
  187. }
  188. }
  189. }
  190. private bool AreDependenciesLoaded(ModuleInfo moduleInfo)
  191. {
  192. IEnumerable<ModuleInfo> requiredModules = this.moduleCatalog.GetDependentModules(moduleInfo);
  193. if (requiredModules == null)
  194. {
  195. return true;
  196. }
  197. int notReadyRequiredModuleCount =
  198. requiredModules.Count(requiredModule => requiredModule.State != ModuleState.Initialized);
  199. return notReadyRequiredModuleCount == 0;
  200. }
  201. private IModuleTypeLoader GetTypeLoaderForModule(ModuleInfo moduleInfo)
  202. {
  203. foreach (IModuleTypeLoader typeLoader in this.ModuleTypeLoaders)
  204. {
  205. if (typeLoader.CanLoadModuleType(moduleInfo))
  206. {
  207. return typeLoader;
  208. }
  209. }
  210. throw new ModuleTypeLoaderNotFoundException(moduleInfo.ModuleName, String.Format(CultureInfo.CurrentCulture, Resources.NoRetrieverCanRetrieveModule, moduleInfo.ModuleName), null);
  211. }
  212. private void InitializeModule(ModuleInfo moduleInfo)
  213. {
  214. if (moduleInfo.State == ModuleState.Initializing)
  215. {
  216. this.moduleInitializer.Initialize(moduleInfo);
  217. moduleInfo.State = ModuleState.Initialized;
  218. }
  219. }
  220. }
  221. }