Changeset 2481 for branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/Loader.cs
- Timestamp:
- 11/11/09 18:25:15 (14 years ago)
- Location:
- branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager
- Files:
-
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager
- Property svn:ignore
-
old new 1 1 bin 2 2 obj 3 HeuristicLab.PluginInfrastructure.Manager.csproj.user
-
- Property svn:ignore
-
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/Loader.cs
r2475 r2481 26 26 using System.IO; 27 27 using System.Diagnostics; 28 using System.Windows.Forms; 29 30 namespace HeuristicLab.PluginInfrastructure { 28 using System.Linq; 29 30 31 namespace HeuristicLab.PluginInfrastructure.Manager { 31 32 internal class Loader : MarshalByRefObject { 32 /// <summary>33 /// Event handler for loaded plugins.34 /// </summary>35 /// <param name="pluginName">The plugin that has been loaded.</param>36 public delegate void PluginLoadedEventHandler(string pluginName);37 38 public delegate void PluginLoadFailedEventHandler(string pluginName, string args);39 40 private Dictionary<PluginInfo, List<string>> pluginDependencies = new Dictionary<PluginInfo, List<string>>();41 private List<PluginInfo> preloadedPluginInfos = new List<PluginInfo>();42 private Dictionary<IPlugin, PluginInfo> pluginInfos = new Dictionary<IPlugin, PluginInfo>();43 private Dictionary<PluginInfo, IPlugin> allPlugins = new Dictionary<PluginInfo, IPlugin>();44 private List<PluginInfo> disabledPlugins = new List<PluginInfo>();45 private string pluginDir = Application.StartupPath + "/" + HeuristicLab.PluginInfrastructure.Properties.Settings.Default.PluginDir;46 47 internal event PluginLoadFailedEventHandler MissingPluginFile;48 33 internal event PluginManagerActionEventHandler PluginAction; 49 34 50 internal ICollection<PluginInfo> ActivePlugins { 51 get { 52 List<PluginInfo> list = new List<PluginInfo>(); 53 foreach (PluginInfo info in allPlugins.Keys) { 54 if (!disabledPlugins.Exists(delegate(PluginInfo disabledInfo) { return info.Name == disabledInfo.Name; })) { 55 list.Add(info); 56 } 57 } 58 return list; 59 } 60 } 61 62 internal ICollection<PluginInfo> InstalledPlugins { 63 get { 64 return new List<PluginInfo>(allPlugins.Keys); 65 } 66 } 67 68 internal ICollection<PluginInfo> DisabledPlugins { 69 get { 70 return disabledPlugins; 71 } 72 } 73 74 private ICollection<ApplicationInfo> applications; 75 internal ICollection<ApplicationInfo> InstalledApplications { 35 private Dictionary<PluginDescription, List<string>> pluginDependencies; 36 37 private List<ApplicationDescription> applications; 38 internal IEnumerable<ApplicationDescription> Applications { 76 39 get { 77 40 return applications; … … 79 42 } 80 43 81 private IPlugin FindPlugin(PluginInfo plugin) { 82 if (allPlugins.ContainsKey(plugin)) { 83 return allPlugins[plugin]; 84 } else return null; 44 private IEnumerable<PluginDescription> plugins; 45 internal IEnumerable<PluginDescription> Plugins { 46 get { 47 return plugins; 48 } 49 } 50 51 public string PluginDir { get; set; } 52 53 public Loader() { 54 this.applications = new List<ApplicationDescription>(); 55 this.plugins = new List<PluginDescription>(); 56 this.pluginDependencies = new Dictionary<PluginDescription, List<string>>(); 85 57 } 86 58 … … 89 61 /// Init first clears all internal datastructures (including plugin lists) 90 62 /// 1. All assemblies in the plugins directory are loaded into the reflection only context. 91 /// 2. The loader checks if all dependencies for each assembly are available. 92 /// 3. All assemblies for which there are no dependencies missing are loaded into the execution context. 93 /// 4. Each loaded assembly is searched for a type that implements IPlugin, then one instance of each IPlugin type is activated 94 /// 5. The loader checks if all necessary files for each plugin are available. 95 /// 6. The loader builds an acyclic graph of PluginDescriptions (childs are dependencies of a plugin) based on the 96 /// list of assemblies of an plugin and the list of dependencies for each of those assemblies 63 /// 2. The loader checks if all necessary files for each plugin are available. 64 /// 3. The loaded builds the tree of plugin descriptions (dependencies) 65 /// 4. The loader checks if all dependencies for each plugin are ok. 66 /// 5. All plugins for which there are no dependencies missing are loaded into the execution context. 67 /// 6. Each loaded plugin (all assemblies) is searched for a types that implement IPlugin 68 /// then one instance of each IPlugin type is activated and the OnLoad hook is called. 69 /// 7. All types implementing IApplication are discovered 97 70 /// </summary> 98 /// <exception cref="FileLoadException">Thrown when the file could not be loaded.</exception>99 71 internal void Init() { 100 AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += delegate(object sender, ResolveEventArgs args) { 101 try { 102 return Assembly.ReflectionOnlyLoad(args.Name); 103 } 104 catch (FileLoadException ex) { 105 return null; 106 } 107 }; 108 allPlugins.Clear(); 109 disabledPlugins.Clear(); 110 pluginInfos.Clear(); 111 pluginsByName.Clear(); 72 //AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += delegate(object sender, ResolveEventArgs args) { 73 // try { 74 // return Assembly.ReflectionOnlyLoad(args.Name); 75 // } 76 // catch (FileLoadException ex) { 77 // return null; 78 // } 79 //}; 112 80 pluginDependencies.Clear(); 113 81 114 List<Assembly> assemblies = ReflectionOnlyLoadDlls(); 115 CheckAssemblyDependencies(assemblies); 116 CheckPluginFiles(); 117 CheckPluginDependencies(); 118 LoadPlugins(); 119 82 IEnumerable<Assembly> reflectionOnlyAssemblies = ReflectionOnlyLoadDlls(); 83 IEnumerable<PluginDescription> pluginDescriptions = GatherPluginDescriptions(reflectionOnlyAssemblies); 84 CheckPluginFiles(pluginDescriptions); 85 86 // a full list of plugin descriptions is available now we can build the dependency tree 87 BuildDependencyTree(pluginDescriptions); 88 89 // recursively check if all necessary plugins are available and not disabled 90 // disable plugins with missing or disabled dependencies 91 CheckPluginDependencies(pluginDescriptions); 92 93 // test full loading (in contrast to reflection only loading) of plugins 94 // disables plugins that are not loaded correctly 95 LoadPlugins(pluginDescriptions); 96 97 plugins = pluginDescriptions; 98 DiscoverApplications(); 99 } 100 101 private void DiscoverApplications() { 120 102 DiscoveryService service = new DiscoveryService(); 121 103 IApplication[] apps = service.GetInstances<IApplication>(); 122 applications = new List<Application Info>();104 applications = new List<ApplicationDescription>(); 123 105 124 106 foreach (IApplication application in apps) { 125 Application Info info = new ApplicationInfo();107 ApplicationDescription info = new ApplicationDescription(); 126 108 info.Name = application.Name; 127 109 info.Version = application.Version; … … 135 117 } 136 118 137 private List<Assembly> ReflectionOnlyLoadDlls() {119 private IEnumerable<Assembly> ReflectionOnlyLoadDlls() { 138 120 List<Assembly> assemblies = new List<Assembly>(); 139 // load all installed pluginsinto the reflection only context140 foreach ( String filename in Directory.GetFiles(pluginDir, "*.dll")) {121 // try to load each .dll file in the plugin directory into the reflection only context 122 foreach (string filename in Directory.GetFiles(PluginDir, "*.dll")) { 141 123 try { 142 assemblies.Add( ReflectionOnlyLoadDll(filename));124 assemblies.Add(Assembly.ReflectionOnlyLoadFrom(filename)); 143 125 } 144 126 catch (BadImageFormatException) { } // just ignore the case that the .dll file is not actually a CLR dll … … 147 129 } 148 130 149 private Assembly ReflectionOnlyLoadDll(string filename) {150 return Assembly.ReflectionOnlyLoadFrom(filename);151 }152 153 private void CheckAssemblyDependencies(List<Assembly> assemblies) {131 // find all types implementing IPlugin in the reflectionOnlyAssemblies and create a list of plugin descriptions 132 // the dependencies in the plugin descriptions are not yet set correctly because we need to create 133 // the full list of all plugin descriptions first 134 private IEnumerable<PluginDescription> GatherPluginDescriptions(IEnumerable<Assembly> assemblies) { 135 List<PluginDescription> pluginDescriptions = new List<PluginDescription>(); 154 136 foreach (Assembly assembly in assemblies) { 155 137 // GetExportedTypes throws FileNotFoundException when a referenced assembly 156 138 // of the current assembly is missing. 157 139 try { 158 Type[] exported = assembly.GetExportedTypes(); 159 160 foreach (Type t in exported) { 140 foreach (Type t in assembly.GetExportedTypes()) { 161 141 // if there is a type that implements IPlugin 162 if (! t.IsAbstract && Array.Exists<Type>(t.GetInterfaces(), delegate(Type iface) { 163 // use AssemblyQualifiedName to compare the types because we can't directly 164 // compare ReflectionOnly types and Execution types 165 return iface.AssemblyQualifiedName == typeof(IPlugin).AssemblyQualifiedName; 166 })) { 142 // use AssemblyQualifiedName to compare the types because we can't directly 143 // compare ReflectionOnly types and Execution types 144 if (!t.IsAbstract && 145 t.GetInterfaces().Any(x => x.AssemblyQualifiedName == typeof(IPlugin).AssemblyQualifiedName)) { 167 146 // fetch the attributes of the IPlugin type 168 GetPluginAttributeData(t);147 pluginDescriptions.Add(GetPluginDescription(t)); 169 148 } 170 149 } 171 150 } 172 151 catch (FileNotFoundException ex) { 173 PluginInfo info = new PluginInfo();174 AssemblyName name = assembly.GetName();175 info.Name = name.Name;176 info.Version = name.Version;177 info.Assemblies.Add(assembly.FullName);178 info.Files.Add(assembly.Location);179 info.Message = "File not found: " + ex.FileName;180 disabledPlugins.Add(info);152 //PluginDescription info = new PluginDescription(); 153 //AssemblyName name = assembly.GetName(); 154 //info.Name = name.Name; 155 //info.Version = name.Version; 156 //info.Assemblies.Add(assembly.FullName); 157 //info.Files.Add(assembly.Location); 158 //info.Message = "File not found: " + ex.FileName; 159 //disabledPlugins.Add(info); 181 160 } 182 161 catch (FileLoadException ex) { 183 PluginInfo info = new PluginInfo();184 AssemblyName name = assembly.GetName();185 info.Name = name.Name;186 info.Version = name.Version;187 info.Files.Add(assembly.Location);188 info.Assemblies.Add(assembly.FullName);189 info.Message = "Couldn't load file: " + ex.FileName;190 disabledPlugins.Add(info);162 //PluginDescription info = new PluginDescription(); 163 //AssemblyName name = assembly.GetName(); 164 //info.Name = name.Name; 165 //info.Version = name.Version; 166 //info.Files.Add(assembly.Location); 167 //info.Assemblies.Add(assembly.FullName); 168 //info.Message = "Couldn't load file: " + ex.FileName; 169 //disabledPlugins.Add(info); 191 170 } 192 171 catch (InvalidPluginException ex) { 193 PluginInfo info = new PluginInfo(); 194 AssemblyName name = assembly.GetName(); 195 info.Name = name.Name; 196 info.Version = name.Version; 197 info.Files.Add(assembly.Location); 198 info.Assemblies.Add(assembly.FullName); 199 info.Message = "Couldn't load plugin class from assembly: " + assembly.GetName().Name+". Necessary plugin attributes are missing."; 200 disabledPlugins.Add(info); 201 } 202 } 172 //PluginDescription info = new PluginDescription(); 173 //AssemblyName name = assembly.GetName(); 174 //info.Name = name.Name; 175 //info.Version = name.Version; 176 //info.Files.Add(assembly.Location); 177 //info.Assemblies.Add(assembly.FullName); 178 //info.Message = "Couldn't load plugin class from assembly: " + assembly.GetName().Name + ". Necessary plugin attributes are missing."; 179 //disabledPlugins.Add(info); 180 } 181 } 182 return pluginDescriptions; 203 183 } 204 184 … … 209 189 /// </summary> 210 190 /// <param name="t"></param> 211 private void GetPluginAttributeData(Type t) {191 private PluginDescription GetPluginDescription(Type pluginType) { 212 192 // get all attributes of that type 213 IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes( t);193 IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(pluginType); 214 194 List<string> pluginAssemblies = new List<string>(); 215 195 List<string> pluginDependencies = new List<string>(); 216 196 List<string> pluginFiles = new List<string>(); 217 string pluginName = "";218 // iterate through all custom attributes and search for named argumentsthat we are interested in197 string pluginName = null; 198 // iterate through all custom attributes and search for attributed that we are interested in 219 199 foreach (CustomAttributeData attributeData in attributes) { 220 List<CustomAttributeNamedArgument> namedArguments = new List<CustomAttributeNamedArgument>(attributeData.NamedArguments); 221 // if the current attribute contains a named argument with the name "Name" then extract the plugin name 222 CustomAttributeNamedArgument pluginNameArgument = namedArguments.Find(delegate(CustomAttributeNamedArgument arg) { 223 return arg.MemberInfo.Name == "Name"; 224 }); 225 if (pluginNameArgument.MemberInfo != null) { 226 pluginName = (string)pluginNameArgument.TypedValue.Value; 227 } 228 // if the current attribute contains a named argument with the name "Dependency" then extract the dependency 229 // and store it in the list of all dependencies 230 CustomAttributeNamedArgument dependencyNameArgument = namedArguments.Find(delegate(CustomAttributeNamedArgument arg) { 231 return arg.MemberInfo.Name == "Dependency"; 232 }); 233 if (dependencyNameArgument.MemberInfo != null) { 234 pluginDependencies.Add((string)dependencyNameArgument.TypedValue.Value); 235 } 236 // if the current attribute has a named argument "Filename" then find if the argument "Filetype" is also supplied 237 // and if the filetype is Assembly then store the name of the assembly in the list of assemblies 238 CustomAttributeNamedArgument filenameArg = namedArguments.Find(delegate(CustomAttributeNamedArgument arg) { 239 return arg.MemberInfo.Name == "Filename"; 240 }); 241 CustomAttributeNamedArgument filetypeArg = namedArguments.Find(delegate(CustomAttributeNamedArgument arg) { 242 return arg.MemberInfo.Name == "Filetype"; 243 }); 244 if (filenameArg.MemberInfo != null && filetypeArg.MemberInfo != null) { 245 pluginFiles.Add(pluginDir + "/" + (string)filenameArg.TypedValue.Value); 246 if ((PluginFileType)filetypeArg.TypedValue.Value == PluginFileType.Assembly) { 247 pluginAssemblies.Add(pluginDir + "/" + (string)filenameArg.TypedValue.Value); 200 if (IsAttributeDataForType(attributeData, typeof(PluginDescriptionAttribute))) { 201 pluginName = (string)attributeData.ConstructorArguments[0].Value; 202 } else if (IsAttributeDataForType(attributeData, typeof(PluginDependencyAttribute))) { 203 pluginDependencies.Add((string)attributeData.ConstructorArguments[0].Value); 204 } else if (IsAttributeDataForType(attributeData, typeof(PluginFileAttribute))) { 205 string pluginFileName = (string)attributeData.ConstructorArguments[0].Value; 206 PluginFileType fileType = (PluginFileType)attributeData.ConstructorArguments[1].Value; 207 pluginFiles.Add(PluginDir + "/" + pluginFileName); 208 if (fileType == PluginFileType.Assembly) { 209 pluginAssemblies.Add(PluginDir + "/" + pluginFileName); 248 210 } 249 211 } … … 251 213 252 214 // minimal sanity check of the attribute values 253 if (pluginName != "" && pluginAssemblies.Count > 0) { 254 // create a temporary PluginInfo that contains the attribute values 255 PluginInfo info = new PluginInfo(); 215 if (!string.IsNullOrEmpty(pluginName) && 216 pluginFiles.Count > 0 && 217 pluginAssemblies.Count > 0) { 218 // create a temporary PluginDescription that contains the attribute values 219 PluginDescription info = new PluginDescription(); 256 220 info.Name = pluginName; 257 info.Version = t.Assembly.GetName().Version; 258 info.Assemblies = pluginAssemblies; 259 info.Files.AddRange(pluginFiles); 221 info.Version = pluginType.Assembly.GetName().Version; 222 info.AddAssemblies(pluginAssemblies); 223 info.AddFiles(pluginFiles); 224 info.PluginState = PluginState.Undefined; 225 260 226 this.pluginDependencies[info] = pluginDependencies; 261 preloadedPluginInfos.Add(info);227 return info; 262 228 } else { 263 throw new InvalidPluginException(); 264 } 265 } 266 267 private void CheckPluginDependencies() { 268 foreach (PluginInfo pluginInfo in preloadedPluginInfos) { 269 // don't need to check plugins that are already disabled 270 if (disabledPlugins.Contains(pluginInfo)) { 271 continue; 272 } 273 visitedDependencies.Clear(); 274 if (!CheckPluginDependencies(pluginInfo.Name)) { 275 PluginInfo matchingInfo = preloadedPluginInfos.Find(delegate(PluginInfo info) { return info.Name == pluginInfo.Name; }); 276 if (matchingInfo == null) throw new InvalidProgramException(); // shouldn't happen 277 foreach (string dependency in pluginDependencies[matchingInfo]) { 278 PluginInfo dependencyInfo = new PluginInfo(); 279 dependencyInfo.Name = dependency; 280 pluginInfo.Dependencies.Add(dependencyInfo); 281 } 282 283 pluginInfo.Message = "Disabled: missing plugin dependency."; 284 disabledPlugins.Add(pluginInfo); 285 } 286 } 287 } 288 289 private List<string> visitedDependencies = new List<string>(); 290 private bool CheckPluginDependencies(string pluginName) { 291 if (!preloadedPluginInfos.Exists(delegate(PluginInfo info) { return pluginName == info.Name; }) || 292 disabledPlugins.Exists(delegate(PluginInfo info) { return pluginName == info.Name; }) || 293 visitedDependencies.Contains(pluginName)) { 294 // when the plugin is not available return false; 295 return false; 296 } else { 297 // otherwise check if all dependencies of the plugin are OK 298 // if yes then this plugin is also ok and we store it in the list of loadable plugins 299 300 PluginInfo matchingInfo = preloadedPluginInfos.Find(delegate(PluginInfo info) { return info.Name == pluginName; }); 301 if (matchingInfo == null) throw new InvalidProgramException(); // shouldn't happen 302 foreach (string dependency in pluginDependencies[matchingInfo]) { 303 visitedDependencies.Add(pluginName); 304 if (CheckPluginDependencies(dependency) == false) { 305 // if only one dependency is not available that means that the current plugin also is unloadable 306 return false; 307 } 308 visitedDependencies.Remove(pluginName); 309 } 310 // all dependencies OK 311 return true; 312 } 313 } 314 315 316 private Dictionary<string, IPlugin> pluginsByName = new Dictionary<string, IPlugin>(); 317 private void LoadPlugins() { 229 throw new InvalidPluginException("Invalid metadata in plugin " + pluginType.ToString()); 230 } 231 } 232 233 private bool IsAttributeDataForType(CustomAttributeData attributeData, Type attributeType) { 234 return attributeData.Constructor.DeclaringType.AssemblyQualifiedName == attributeType.AssemblyQualifiedName; 235 } 236 237 // builds a dependency tree of all plugin descriptions 238 // searches matching plugin descriptions based on the list of dependency names for each plugin 239 // and sets the dependencies in the plugin descriptions 240 private void BuildDependencyTree(IEnumerable<PluginDescription> pluginDescriptions) { 241 foreach (var desc in pluginDescriptions) { 242 foreach (string pluginName in pluginDependencies[desc]) { 243 var matchingDescriptions = pluginDescriptions.Where(x => x.Name == pluginName); 244 if (matchingDescriptions.Count() > 0) { 245 desc.AddDependency(matchingDescriptions.First()); 246 } else { 247 // no plugin description that matches the dependency name is available => plugin is disabled 248 desc.PluginState = PluginState.Disabled; 249 break; // stop processing more dependencies 250 } 251 } 252 } 253 } 254 255 private void CheckPluginDependencies(IEnumerable<PluginDescription> pluginDescriptions) { 256 foreach (PluginDescription pluginDescription in pluginDescriptions.Where(x => x.PluginState != PluginState.Disabled)) { 257 if (IsAnyDependencyDisabled(pluginDescription)) { 258 // PluginDescription.Message = "Disabled: missing plugin dependency."; 259 pluginDescription.PluginState = PluginState.Disabled; 260 } 261 } 262 } 263 264 265 private bool IsAnyDependencyDisabled(PluginDescription descr) { 266 if (descr.PluginState == PluginState.Disabled) return true; 267 foreach (PluginDescription dependency in descr.Dependencies) { 268 if (IsAnyDependencyDisabled(dependency)) return true; 269 } 270 return false; 271 } 272 273 private void LoadPlugins(IEnumerable<PluginDescription> pluginDescriptions) { 318 274 // load all loadable plugins (all dependencies available) into the execution context 319 foreach (PluginInfo pluginInfo in preloadedPluginInfos) { 320 if (!disabledPlugins.Contains(pluginInfo)) { 321 foreach (string assembly in pluginInfo.Assemblies) { 322 Assembly.LoadFrom(assembly); 323 } 324 } 325 } 326 327 Queue<IPlugin> pluginsToLoad = new Queue<IPlugin>(); 328 DiscoveryService service = new DiscoveryService(); 329 // now search and instantiate an IPlugin type in each loaded assembly 330 // and prepare the queue to load all plugins 331 foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { 332 // don't search for plugins in the PluginInfrastructure 333 if (assembly == this.GetType().Assembly) 334 continue; 335 Type[] availablePluginTypes = service.GetTypes(typeof(IPlugin), assembly); 336 foreach (Type pluginType in availablePluginTypes) { 275 foreach (PluginDescription desc in PluginDescriptionIterator.IterateInDependencyOrder(pluginDescriptions.Where(x => x.PluginState != PluginState.Disabled))) { 276 List<Type> types = new List<Type>(); 277 foreach (string assembly in desc.Assemblies) { 278 var asm = Assembly.LoadFrom(assembly); 279 foreach (Type t in asm.GetTypes()) { 280 if (typeof(IPlugin).IsAssignableFrom(t)) { 281 types.Add(t); 282 } 283 } 284 } 285 286 foreach (Type pluginType in types) { 337 287 if (!pluginType.IsAbstract && !pluginType.IsInterface && !pluginType.HasElementType) { 338 288 IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType); 339 pluginsToLoad.Enqueue(plugin); 340 pluginsByName.Add(plugin.Name, plugin); 341 } 342 } 343 } 344 345 // load all plugins respecting their dependencies 346 while (pluginsToLoad.Count > 0) { 347 IPlugin plugin = pluginsToLoad.Dequeue(); 348 PluginInfo pluginInfo = GetPluginInfo(plugin); 349 bool canLoad = true; 350 foreach (PluginInfo dependency in pluginInfo.Dependencies) { 351 if (!allPlugins.ContainsKey(dependency)) { 352 canLoad = false; 353 break; 354 } 355 } 356 if (canLoad) { 357 PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.InitializingPlugin)); 358 plugin.OnLoad(); 359 allPlugins.Add(pluginInfo, plugin); 360 PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.InitializedPlugin)); 361 } else { 362 pluginsToLoad.Enqueue(plugin); 363 } 364 } 365 } 366 private PluginInfo GetPluginInfo(IPlugin plugin) { 367 if (pluginInfos.ContainsKey(plugin)) { 368 return pluginInfos[plugin]; 369 } 370 // store the data of the plugin in a description file which can be used without loading the plugin assemblies 371 PluginInfo pluginInfo = new PluginInfo(); 372 pluginInfo.Name = plugin.Name; 373 pluginInfo.Version = plugin.Version; 374 375 object[] customAttributes = plugin.GetType().Assembly.GetCustomAttributes(typeof(AssemblyBuildDateAttribute), false); 376 if (customAttributes.Length > 0) { 377 pluginInfo.BuildDate = ((AssemblyBuildDateAttribute)customAttributes[0]).BuildDate; 378 } 379 380 string baseDir = AppDomain.CurrentDomain.BaseDirectory; 381 382 Array.ForEach<string>(plugin.FileNames, delegate(string file) { 383 string filename = pluginDir + "/" + file; 384 // always use \ as the directory separator 385 pluginInfo.Files.Add(filename.Replace('/', '\\')); 386 }); 387 388 PluginInfo preloadedInfo = preloadedPluginInfos.Find(delegate(PluginInfo info) { return info.Name == plugin.Name; }); 389 foreach (string assembly in preloadedInfo.Assemblies) { 390 // always use \ as directory separator (this is necessary for discovery of types in 391 // plugins see DiscoveryService.GetTypes() 392 pluginInfo.Assemblies.Add(assembly.Replace('/', '\\')); 393 } 394 foreach (string dependency in pluginDependencies[preloadedInfo]) { 395 // accumulate the dependencies of each assembly into the dependencies of the whole plugin 396 PluginInfo dependencyInfo = GetPluginInfo(pluginsByName[dependency]); 397 pluginInfo.Dependencies.Add(dependencyInfo); 398 } 399 pluginInfos[plugin] = pluginInfo; 400 return pluginInfo; 401 } 402 403 private void CheckPluginFiles() { 404 foreach (PluginInfo plugin in preloadedPluginInfos) { 405 if (!CheckPluginFiles(plugin)) { 406 plugin.Message = "Disabled: missing plugin file."; 407 disabledPlugins.Add(plugin); 408 } 409 } 410 } 411 412 private bool CheckPluginFiles(PluginInfo pluginInfo) { 413 foreach (string filename in pluginInfo.Files) { 289 plugin.OnLoad(); 290 PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.PluginLoaded)); 291 } 292 } 293 } 294 } 295 //private PluginDescription GetPluginDescription(IPlugin plugin) { 296 // if (PluginDescriptions.ContainsKey(plugin)) { 297 // return PluginDescriptions[plugin]; 298 // } 299 // // store the data of the plugin in a description file which can be used without loading the plugin assemblies 300 // PluginDescription PluginDescription = new PluginDescription(); 301 // PluginDescription.Name = plugin.Name; 302 // PluginDescription.Version = plugin.Version; 303 304 // object[] customAttributes = plugin.GetType().Assembly.GetCustomAttributes(typeof(AssemblyBuildDateAttribute), false); 305 // if (customAttributes.Length > 0) { 306 // PluginDescription.BuildDate = ((AssemblyBuildDateAttribute)customAttributes[0]).BuildDate; 307 // } 308 309 // string baseDir = AppDomain.CurrentDomain.BaseDirectory; 310 311 // Array.ForEach<string>(plugin.FileNames, delegate(string file) { 312 // string filename = pluginDir + "/" + file; 313 // // always use \ as the directory separator 314 // PluginDescription.Files.Add(filename.Replace('/', '\\')); 315 // }); 316 317 // PluginDescription preloadedInfo = preloadedPluginDescriptions.Find(delegate(PluginDescription info) { return info.Name == plugin.Name; }); 318 // foreach (string assembly in preloadedInfo.Assemblies) { 319 // // always use \ as directory separator (this is necessary for discovery of types in 320 // // plugins see DiscoveryService.GetTypes() 321 // PluginDescription.Assemblies.Add(assembly.Replace('/', '\\')); 322 // } 323 // foreach (string dependency in pluginDependencies[preloadedInfo]) { 324 // // accumulate the dependencies of each assembly into the dependencies of the whole plugin 325 // PluginDescription dependencyInfo = GetPluginDescription(pluginsByName[dependency]); 326 // PluginDescription.Dependencies.Add(dependencyInfo); 327 // } 328 // PluginDescriptions[plugin] = PluginDescription; 329 // return PluginDescription; 330 //} 331 332 // checks if all declared plugin files are actually available and disables plugins with missing files 333 private void CheckPluginFiles(IEnumerable<PluginDescription> pluginDescriptions) { 334 foreach (PluginDescription desc in pluginDescriptions) { 335 if (!CheckPluginFiles(desc)) { 336 //plugin.Message = "Disabled: missing plugin file."; 337 desc.PluginState = PluginState.Disabled; 338 } 339 } 340 } 341 342 private bool CheckPluginFiles(PluginDescription PluginDescription) { 343 foreach (string filename in PluginDescription.Files) { 414 344 if (!File.Exists(filename)) { 415 if (MissingPluginFile != null) {416 MissingPluginFile(pluginInfo.Name, filename);417 }345 //if (MissingPluginFile != null) { 346 // MissingPluginFile(PluginDescription.Name, filename); 347 //} 418 348 return false; 419 349 } … … 429 359 return null; 430 360 } 431 432 internal void OnDelete(PluginInfo pluginInfo) {433 IPlugin plugin = FindPlugin(pluginInfo);434 if (plugin != null) plugin.OnDelete();435 }436 437 internal void OnInstall(PluginInfo pluginInfo) {438 IPlugin plugin = FindPlugin(pluginInfo);439 if (plugin != null) plugin.OnInstall();440 }441 442 internal void OnPreUpdate(PluginInfo pluginInfo) {443 IPlugin plugin = FindPlugin(pluginInfo);444 if (plugin != null) plugin.OnPreUpdate();445 }446 447 internal void OnPostUpdate(PluginInfo pluginInfo) {448 IPlugin plugin = FindPlugin(pluginInfo);449 if (plugin != null) plugin.OnPostUpdate();450 }451 361 } 452 362 }
Note: See TracChangeset
for help on using the changeset viewer.