using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Reflection; using System.Xml; using DelftTools.Utils.Reflection; using DeltaShell.Core.Properties; using log4net; namespace DeltaShell.Core { /// /// Used to load plugin configurations from a specified directory. /// public class PluginConfigurationLoader { private static readonly ILog log = LogManager.GetLogger("PluginLoader"); private readonly string directory; private readonly IList disabledPlugins = new List(); private readonly IDictionary loadedAssemblyConfigFiles = new Dictionary(); private IEnumerable assemblies; public PluginConfigurationLoader(string directory) { this.directory = directory; } public void FillPluginConfigurationsFromPath(IList pluginConfigs, IList pluginAssemblies) where TPluginConfigurationSectionHandler : IConfigurationSectionHandler, new() where TPluginConfig : class { if (assemblies == null) { assemblies = LoadAssembliesWithConfigInDirectory(directory); } foreach (var assembly in assemblies) { var config = GetPluginConfig(loadedAssemblyConfigFiles[Path.GetFileNameWithoutExtension(assembly.Location)]); if (config == null) { continue; } pluginConfigs.Add(config); pluginAssemblies.Add(assembly); } } public static TPluginConfig GetPluginConfig(string appConfigFilePath) where TPluginConfigurationSectionHandler : IConfigurationSectionHandler, new() where TPluginConfig : class { try { if (!File.Exists(appConfigFilePath)) { log.WarnFormat(Resources.PluginConfigurationLoader_GetPluginConfig_plugin_configuration_file___0___not_found__skipped_, appConfigFilePath); return default(TPluginConfig); } // find XML element with a name equal to configuration class name (e.g. applicationPlugin, guiPlugin) var nodeName = typeof(TPluginConfig).Name; var doc = new XmlDocument(); doc.Load(new XmlTextReader(appConfigFilePath)); var nodes = doc.GetElementsByTagName(nodeName); foreach (XmlNode node in nodes) { if (node.LocalName == nodeName) { var handler = new TPluginConfigurationSectionHandler(); return (TPluginConfig) handler.Create(null, null, node); } } } catch (Exception exception) { log.ErrorFormat(Resources.PluginConfigurationLoader_GetPluginConfig_plugin_could_not_be_loaded____0_____1_, appConfigFilePath, exception.Message); return default(TPluginConfig); } return default(TPluginConfig); } private IEnumerable LoadAssembliesWithConfigInDirectory(string path) { if (!Directory.Exists(path)) { throw new DirectoryNotFoundException(string.Format(Resources.PluginConfigurationLoader_LoadAssembliesWithConfigInDirectory_Can_t_find_directory_to_load_assemblies_from___0___fix_your_configuration_file, path)); } foreach (var directoryPath in Directory.GetDirectories(path).Concat(new[] { path })) { foreach (string filename in Directory.GetFiles(directoryPath).Where(name => name.EndsWith(".dll.config"))) { loadedAssemblyConfigFiles[Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(filename))] = filename; } foreach (var assembly in AssemblyUtils.LoadAllAssembliesFromDirectory(Path.GetFullPath(directoryPath))) { if (CanContainAPlugin(assembly)) { yield return assembly; } } } } /// /// Determines whether the assembly should be taken into account on the search for T implementations /// /// Assembly to inspect /// private bool CanContainAPlugin(Assembly assembly) { if (TypeUtils.IsDynamic(assembly)) { return false; } var fileName = assembly.Location; if (string.IsNullOrEmpty(fileName)) { return false; //no 'location' gac or something we don't want } string pluginDllName = fileName; if (disabledPlugins != null && disabledPlugins.Contains(pluginDllName)) { log.DebugFormat(Resources.PluginConfigurationLoader_CanContainAPlugin_Skipping_the_loading_of__0_, pluginDllName); return false; } if (!loadedAssemblyConfigFiles.ContainsKey(Path.GetFileNameWithoutExtension(pluginDllName))) { return false; } return true; } } }