- Timestamp:
- 11/17/09 14:03:40 (15 years ago)
- Location:
- branches/PluginInfrastructure Refactoring
- Files:
-
- 1 added
- 1 deleted
- 6 edited
- 6 moved
Legend:
- Unmodified
- Added
- Removed
-
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/HeuristicLab.PluginInfrastructure.Manager.csproj
r2497 r2503 50 50 <Compile Include="ApplicationDescription.cs" /> 51 51 <Compile Include="DefaultApplicationManager.cs" /> 52 <Compile Include="Loader.cs" />53 52 <Compile Include="PluginDescription.cs" /> 54 53 <Compile Include="PluginInfrastructureEventArgs.cs" /> 55 54 <Compile Include="PluginManager.cs" /> 55 <Compile Include="PluginValidator.cs" /> 56 56 <Compile Include="Properties\AssemblyInfo.cs" /> 57 57 </ItemGroup> -
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure/ApplicationManager.cs
r2495 r2503 31 31 namespace HeuristicLab.PluginInfrastructure { 32 32 33 /// <summary> 34 /// The ApplicationManager has a reference to the application manager singleton. 35 /// The application manager provides 36 /// </summary> 33 37 public static class ApplicationManager { 34 38 private static IApplicationManager appManager; 39 /// <summary> 40 /// Gets the application manager singleton. 41 /// </summary> 35 42 public static IApplicationManager Manager { 36 43 get { return appManager; } 37 44 } 38 45 39 public static void RegisterApplicationManager(IApplicationManager manager) { 46 /// <summary> 47 /// Registers a new application manager. 48 /// </summary> 49 /// <param name="manager"></param> 50 internal static void RegisterApplicationManager(IApplicationManager manager) { 40 51 if (appManager != null) throw new InvalidOperationException("The application manager has already been set."); 41 52 appManager = manager; -
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure/BaseClasses/PluginBase.cs
r2488 r2503 56 56 } 57 57 58 ///// <inheritdoc />59 //public Version Version {60 // get {61 // var pluginAttribute = PluginDescriptionAttribute;62 // // if the version is not set in the attribute then the version of the assembly is used as default63 // if (string.IsNullOrEmpty(pluginAttribute.Version)) {64 // return this.GetType().Assembly.GetName().Version;65 // } else {66 // return new Version(pluginAttribute.Version);67 // }68 // }69 //}70 71 ///// <inheritdoc />72 //public string Description {73 // get {74 // var pluginAttribute = PluginDescriptionAttribute;75 // // if the description is not explicitly set in the attribute then the name of the plugin is used as default76 // if (string.IsNullOrEmpty(pluginAttribute.Description)) {77 // return pluginAttribute.Name;78 // } else {79 // return pluginAttribute.Description;80 // }81 // }82 //}83 58 84 59 /// <inheritdoc/> … … 94 69 /// <inhertitdoc> 95 70 public virtual void OnLoad() { } 71 /// <inhertitdoc> 72 public virtual void OnUnload() { } 96 73 #endregion 97 74 -
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure/DefaultApplicationManager.cs
r2502 r2503 32 32 namespace HeuristicLab.PluginInfrastructure.Manager { 33 33 34 public class DefaultApplicationManager : MarshalByRefObject, IApplicationManager {34 public sealed class DefaultApplicationManager : MarshalByRefObject, IApplicationManager { 35 35 internal event EventHandler<PluginInfrastructureEventArgs> PluginLoaded; 36 internal event EventHandler<PluginInfrastructureEventArgs> PluginUnloaded; 37 36 38 // cache for the AssemblyResolveEvent 37 39 // which must be handled when assemblies are loaded dynamically after the application start 38 40 private Dictionary<string, Assembly> loadedAssemblies; 39 41 42 private List<IPlugin> loadedPlugins; 43 40 44 private List<IPluginDescription> plugins; 41 45 /// <summary> … … 55 59 } 56 60 57 publicDefaultApplicationManager()61 internal DefaultApplicationManager() 58 62 : base() { 59 63 loadedAssemblies = new Dictionary<string, Assembly>(); 64 loadedPlugins = new List<IPlugin>(); 60 65 // needed for the special case when assemblies are loaded dynamically via LoadAssemblies() 61 66 AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { … … 83 88 foreach (var plugin in GetInstances<IPlugin>(asm)) { 84 89 plugin.OnLoad(); 90 loadedPlugins.Add(plugin); 85 91 } 86 92 } 87 FirePluginLoaded(desc);93 OnPluginLoaded(new PluginInfrastructureEventArgs("Plugin loaded", desc)); 88 94 desc.Load(); 89 95 } … … 105 111 e.ToString())); 106 112 } 113 finally { 114 // unload plugins in reverse order 115 foreach (var plugin in loadedPlugins.Reverse<IPlugin>()) { 116 plugin.OnUnload(); 117 } 118 foreach (var desc in PluginDescriptionIterator.IterateInDependencyOrder(plugins.Where(x => x.PluginState != PluginState.Disabled))) { 119 desc.Unload(); 120 OnPluginUnloaded(new PluginInfrastructureEventArgs("Plugin unloaded", desc)); 121 } 122 } 107 123 } 108 124 … … 203 219 } 204 220 205 private void FirePluginLoaded(IPluginDescription plugin) { 206 if (PluginLoaded != null) PluginLoaded(this, new PluginInfrastructureEventArgs("Plugin loaded", plugin)); 221 private void OnPluginLoaded(PluginInfrastructureEventArgs e) { 222 if (PluginLoaded != null) PluginLoaded(this, e); 223 } 224 225 private void OnPluginUnloaded(PluginInfrastructureEventArgs e) { 226 if (PluginUnloaded != null) PluginUnloaded(this, e); 207 227 } 208 228 -
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure/HeuristicLab.PluginInfrastructure.csproj
r2488 r2503 86 86 </ItemGroup> 87 87 <ItemGroup> 88 <Compile Include="ApplicationDescription.cs" /> 88 89 <Compile Include="Attributes\ApplicationAttribute.cs" /> 89 90 <Compile Include="Attributes\AssemblyBuildDateAttribute.cs" /> … … 93 94 <Compile Include="BaseClasses\ApplicationBase.cs" /> 94 95 <Compile Include="BaseClasses\PluginBase.cs" /> 96 <Compile Include="DefaultApplicationManager.cs" /> 95 97 <Compile Include="Interfaces\IApplicationManager.cs" /> 96 98 <Compile Include="Interfaces\IApplicationDescription.cs" /> … … 102 104 <Compile Include="Interfaces\IPluginDescription.cs" /> 103 105 <Compile Include="InvalidPluginException.cs" /> 106 <Compile Include="PluginDescription.cs" /> 104 107 <Compile Include="PluginDescriptionIterator.cs" /> 105 108 <Compile Include="ApplicationManager.cs" /> 109 <Compile Include="PluginInfrastructureEventArgs.cs" /> 110 <Compile Include="PluginManager.cs" /> 106 111 <Compile Include="PluginState.cs" /> 112 <Compile Include="PluginValidator.cs" /> 107 113 <Compile Include="Properties\AssemblyInfo.cs" /> 108 114 <EmbeddedResource Include="Properties\Resources.resx"> … … 129 135 </Compile> 130 136 </ItemGroup> 137 <ItemGroup> 138 <Folder Include="Manager\" /> 139 </ItemGroup> 131 140 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> 132 141 <!-- To modify your build process, add your task inside one of the targets below and uncomment it. -
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure/Interfaces/IPlugin.cs
r2481 r2503 51 51 /// </summary> 52 52 void OnLoad(); 53 54 /// <summary> 55 /// Called by the framework whenever the plugin is unloaded. 56 /// Plugins are unloaded when an application exits. 57 /// </summary> 58 void OnUnload(); 53 59 } 54 60 } -
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure/PluginInfrastructureEventArgs.cs
r2502 r2503 24 24 using System.Text; 25 25 26 namespace HeuristicLab.PluginInfrastructure {26 namespace HeuristicLab.PluginInfrastructure.Manager { 27 27 // to be replaced by GenericEventArgs 28 28 [Serializable] -
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure/PluginManager.cs
r2502 r2503 35 35 /// Class to manage different plugins. 36 36 /// </summary> 37 public class PluginManager : MarshalByRefObject {37 public sealed class PluginManager : MarshalByRefObject { 38 38 /// <summary> 39 39 /// Event handler for actions in the plugin manager. … … 42 42 43 43 private string pluginDir; 44 45 public PluginManager(string pluginDir) {46 this.pluginDir = pluginDir;47 }48 44 49 45 private List<PluginDescription> plugins; … … 57 53 } 58 54 55 private object locker = new object(); 56 private bool initialized; 57 58 public PluginManager(string pluginDir) { 59 this.pluginDir = pluginDir; 60 plugins = new List<PluginDescription>(); 61 applications = new List<ApplicationDescription>(); 62 Reset(); 63 } 64 65 public void Reset() { 66 initialized = false; 67 if (plugins != null && plugins.Any(x => x.PluginState == PluginState.Loaded)) throw new InvalidOperationException("Reset() is not allowed while applications are active."); 68 plugins.Clear(); 69 applications.Clear(); 70 } 71 59 72 /// <summary> 60 73 /// Determines installed plugins and checks if all plugins are loadable. 61 74 /// </summary> 62 75 public void DiscoverAndCheckPlugins() { 63 FireAction("Initializing", "PluginInfrastructure");76 OnAction(new PluginInfrastructureEventArgs("Initializing", "PluginInfrastructure")); 64 77 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation; 65 78 setup.PrivateBinPath = pluginDir; … … 67 80 try { 68 81 pluginDomain = AppDomain.CreateDomain("plugin domain", null, setup); 69 Loader remoteLoader = (Loader)pluginDomain.CreateInstanceAndUnwrap("HeuristicLab.PluginInfraStructure.Manager", "HeuristicLab.PluginInfrastructure.Manager.Loader"); 70 remoteLoader.PluginDir = pluginDir; 71 // forward all events from the remoteLoader to listeners 72 remoteLoader.PluginLoaded += delegate(object sender, PluginInfrastructureEventArgs args) { FireAction(args.Action, args.Entity); }; 73 this.plugins = new List<PluginDescription>(remoteLoader.Plugins); 74 this.applications = new List<ApplicationDescription>(remoteLoader.Applications); 75 FireAction("Initialized", "PluginInfrastructure"); 82 PluginValidator remoteValidator = (PluginValidator)pluginDomain.CreateInstanceAndUnwrap("HeuristicLab.PluginInfraStructure.Manager", "HeuristicLab.PluginInfrastructure.Manager.Loader"); 83 remoteValidator.PluginDir = pluginDir; 84 // forward all events from the remoteValidator to listeners 85 remoteValidator.PluginLoaded += 86 delegate(object sender, PluginInfrastructureEventArgs e) { 87 OnAction(e); 88 }; 89 // get list of plugins and applications from the validator 90 plugins.Clear(); applications.Clear(); 91 plugins.AddRange(remoteValidator.Plugins); 92 applications.AddRange(remoteValidator.Applications); 93 OnAction(new PluginInfrastructureEventArgs("Initialized", "PluginInfrastructure")); 76 94 } 77 95 finally { 78 96 // discard the AppDomain that was used for plugin discovery 79 UnloadAppDomain(pluginDomain); 97 AppDomain.Unload(pluginDomain); 98 // unload all plugins 99 foreach (var pluginDescription in plugins) 100 pluginDescription.Unload(); 101 initialized = true; 80 102 } 81 103 } … … 83 105 84 106 /// <summary> 85 /// Createsa separate AppDomain.86 /// Loads all active plugin assemblies and starts the application in the new AppDomain via a PluginRunner instance activated in the new AppDomain107 /// Starts and application in a separate AppDomain. 108 /// Loads all enabled plugins and starts the application via a PluginRunner instance activated in the new AppDomain. 87 109 /// </summary> 88 110 /// <param name="appInfo">application to run</param> 89 111 public void Run(ApplicationDescription appInfo) { 112 if (!initialized) throw new InvalidOperationException("PluginManager is not initialized. DiscoverAndCheckPlugins() must be called before Run()"); 90 113 // create a separate AppDomain for the application 91 114 // initialize the static ApplicationManager in the AppDomain 92 115 // and remotely tell it to start the application 93 116 94 FireAction("Starting application", appInfo.Name);117 OnAction(new PluginInfrastructureEventArgs("Starting application", appInfo)); 95 118 AppDomain applicationDomain = null; 96 119 try { … … 101 124 (DefaultApplicationManager)applicationDomain.CreateInstanceAndUnwrap("HeuristicLab.PluginInfraStructure.Manager", "HeuristicLab.PluginInfrastructure.Manager.DefaultApplicationManager"); 102 125 applicationManager.PluginLoaded += applicationManager_PluginLoaded; 126 applicationManager.PluginUnloaded += applicationManager_PluginUnloaded; 103 127 applicationManager.PrepareApplicationDomain( 104 128 new List<IApplicationDescription>(applications.Cast<IApplicationDescription>()), 105 129 new List<IPluginDescription>(plugins.Cast<IPluginDescription>())); 106 FireAction("Started application", appInfo.Name);130 OnAction(new PluginInfrastructureEventArgs("Started application", appInfo)); 107 131 applicationManager.Run(appInfo); 108 132 } 109 133 finally { 110 134 // make sure domain is unloaded in all cases 111 UnloadAppDomain(applicationDomain);135 AppDomain.Unload(applicationDomain); 112 136 } 113 137 } 114 138 115 void applicationManager_PluginLoaded(object sender, PluginInfrastructureEventArgs e) { 139 private void applicationManager_PluginUnloaded(object sender, PluginInfrastructureEventArgs e) { 140 // unload the matching plugin description ( 141 PluginDescription desc = (PluginDescription)e.Entity; 142 143 // access to plugin descriptions has to be synchronized because multiple applications 144 // can be started or stopped at the same time 145 lock (locker) { 146 plugins.First(x => x.Equals(desc)).Unload(); 147 } 148 OnAction(new PluginInfrastructureEventArgs(e.Action, e.Entity)); 149 } 150 151 private void applicationManager_PluginLoaded(object sender, PluginInfrastructureEventArgs e) { 116 152 // load the matching plugin description ( 117 153 PluginDescription desc = (PluginDescription)e.Entity; 118 foreach (var myDesc in plugins) { 119 if (myDesc.Equals(desc)) myDesc.Load(); 154 // access to plugin descriptions has to be synchronized because multiple applications 155 // can be started or stopped at the same time 156 lock (locker) { 157 plugins.First(x => x.Equals(desc)).Load(); 120 158 } 121 FireAction(e.Action, e.Entity);159 OnAction(new PluginInfrastructureEventArgs(e.Action, e.Entity)); 122 160 } 123 161 124 private void UnloadAppDomain(AppDomain appDomain) { 125 AppDomain.Unload(appDomain); 126 127 // TODO: Update plugin descriptions in all active AppDomains 128 129 // unload all plugins 130 foreach (var pluginDescription in plugins) 131 pluginDescription.Unload(); 132 } 133 134 private void FireAction(string action, object entity) { 162 private void OnAction(PluginInfrastructureEventArgs e) { 135 163 if (Action != null) { 136 Action(this, new PluginInfrastructureEventArgs(action, entity));164 Action(this, e); 137 165 } 138 166 } -
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure/PluginValidator.cs
r2497 r2503 30 30 31 31 namespace HeuristicLab.PluginInfrastructure.Manager { 32 internal class Loader : MarshalByRefObject { 32 /// <summary> 33 /// Discovers all installed plugins in the plugin directory. Checks correctness of plugin meta-data and if 34 /// all plugin files are available and checks plugin dependencies. 35 /// </summary> 36 internal sealed class PluginValidator : MarshalByRefObject { 33 37 internal event EventHandler<PluginInfrastructureEventArgs> PluginLoaded; 34 38 … … 38 42 internal IEnumerable<ApplicationDescription> Applications { 39 43 get { 44 if (string.IsNullOrEmpty(PluginDir)) throw new InvalidOperationException("PluginDir is not set."); 40 45 if (applications == null) DiscoverAndCheckPlugins(); 41 46 return applications; … … 46 51 internal IEnumerable<PluginDescription> Plugins { 47 52 get { 53 if (string.IsNullOrEmpty(PluginDir)) throw new InvalidOperationException("PluginDir is not set."); 48 54 if (plugins == null) DiscoverAndCheckPlugins(); 49 55 return plugins; … … 53 59 public string PluginDir { get; set; } 54 60 55 public Loader() {61 public PluginValidator() { 56 62 this.pluginDependencies = new Dictionary<PluginDescription, List<string>>(); 57 63 … … 69 75 /// Init first clears all internal datastructures (including plugin lists) 70 76 /// 1. All assemblies in the plugins directory are loaded into the reflection only context. 71 /// 2. The loader checks if all necessary files for each plugin are available.72 /// 3. The loadedbuilds the tree of plugin descriptions (dependencies)73 /// 4. The loader checks if all dependencies for each plugin are ok.77 /// 2. The validator checks if all necessary files for each plugin are available. 78 /// 3. The validator builds the tree of plugin descriptions (dependencies) 79 /// 4. The validator checks if all dependencies for each plugin are ok. 74 80 /// 5. All plugins for which there are no dependencies missing are loaded into the execution context. 75 81 /// 6. Each loaded plugin (all assemblies) is searched for a types that implement IPlugin … … 77 83 /// 7. All types implementing IApplication are discovered 78 84 /// </summary> 79 privatevoid DiscoverAndCheckPlugins() {85 internal void DiscoverAndCheckPlugins() { 80 86 pluginDependencies.Clear(); 81 87 … … 135 141 assemblies.Add(Assembly.ReflectionOnlyLoadFrom(filename)); 136 142 } 137 catch (BadImageFormatException) { } // just ignore the case that the .dll file is not a ctually a CLR dll143 catch (BadImageFormatException) { } // just ignore the case that the .dll file is not a CLR assembly (e.g. a native dll) 138 144 } 139 145 return assemblies; … … 243 249 foreach (PluginDescription pluginDescription in pluginDescriptions.Where(x => x.PluginState != PluginState.Disabled)) { 244 250 if (IsAnyDependencyDisabled(pluginDescription)) { 245 // PluginDescription.Message = "Disabled: missing plugin dependency.";246 251 pluginDescription.Disable(); 247 252 } … … 277 282 IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType); 278 283 plugin.OnLoad(); 279 FirePluginLoaded(plugin.Name);284 OnPluginLoaded(new PluginInfrastructureEventArgs("Plugin loaded", plugin.Name)); 280 285 } 281 286 } … … 302 307 } 303 308 304 private void FirePluginLoaded(string pluginName) {309 internal void OnPluginLoaded(PluginInfrastructureEventArgs e) { 305 310 if (PluginLoaded != null) 306 PluginLoaded(this, new PluginInfrastructureEventArgs("Plugin loaded", pluginName));311 PluginLoaded(this, e); 307 312 } 308 313 -
branches/PluginInfrastructure Refactoring/HeuristicLab/HeuristicLab.csproj
r2481 r2503 127 127 </ItemGroup> 128 128 <ItemGroup> 129 <ProjectReference Include="..\HeuristicLab.PluginInfrastructure.Manager\HeuristicLab.PluginInfrastructure.Manager.csproj">130 <Project>{CA8AAD91-E8E2-41AF-96AD-2BA94BC3EF2D}</Project>131 <Name>HeuristicLab.PluginInfrastructure.Manager</Name>132 </ProjectReference>133 129 <ProjectReference Include="..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj"> 134 130 <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
Note: See TracChangeset
for help on using the changeset viewer.