Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
11/12/09 17:45:45 (15 years ago)
Author:
gkronber
Message:

Worked on plugin infrastructure refactoring. (Fully functional revision). #799

Location:
branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/ApplicationDescription.cs

    r2481 r2488  
    2929  /// </summary>
    3030  [Serializable]
    31   public class ApplicationDescription {
     31  public class ApplicationDescription : IApplicationDescription {
    3232    private string name;
    3333
     
    6767    }
    6868
    69     private string pluginAssembly;
     69    private string declaringAssemblyName;
    7070    /// <summary>
    7171    /// Gets or sets the name of the assembly that contains the IApplication type.
    7272    /// </summary>
    73     public string PluginAssembly {
    74       get { return pluginAssembly; }
    75       set { pluginAssembly = value; }
     73    public string DeclaringAssemblyName {
     74      get { return declaringAssemblyName; }
     75      set { declaringAssemblyName = value; }
    7676    }
    7777
    78     private string pluginType;
     78    private string declaringTypeName;
    7979    /// <summary>
    8080    /// Gets or sets the name of the type that implements the interface IApplication.
    8181    /// </summary>
    82     public string PluginType {
    83       get { return pluginType; }
    84       set { pluginType = value; }
     82    public string DeclaringTypeName {
     83      get { return declaringTypeName; }
     84      set { declaringTypeName = value; }
    8585    }
    8686  }
  • branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/ApplicationManager.cs

    r2481 r2488  
    2727using System.Security.Permissions;
    2828using System.Security;
     29using System.Linq;
    2930
    3031namespace HeuristicLab.PluginInfrastructure.Manager {
    3132
    32   public class ApplicationManager {
     33  public class ApplicationManager : MarshalByRefObject, IApplicationManager {
     34    private List<IPluginDescription> plugins;
    3335    /// <summary>
    34     /// Event handler for actions in the application manager.
     36    /// Gets all plugins.
    3537    /// </summary>
    36     public event PluginManagerActionEventHandler Action;
    37 
    38     // singleton pattern
    39     public ApplicationManager() {
    40       applications = new List<ApplicationDescription>();
     38    public IEnumerable<IPluginDescription> Plugins {
     39      get { return plugins; }
    4140    }
    4241
    43     private ApplicationManager singleton = new ApplicationManager();
    44     public ApplicationManager Manager {
    45       get { return singleton; }
     42    private List<IApplicationDescription> applications;
     43    /// <summary>
     44    /// Gets all installed applications.
     45    /// </summary>
     46    public IEnumerable<IApplicationDescription> Applications {
     47      get { return applications; }
     48    }
     49
     50    public ApplicationManager() : base() { }
     51
     52    internal void PrepareApplicationDomain(IEnumerable<IApplicationDescription> apps, IEnumerable<IPluginDescription> plugins) {
     53      this.plugins = new List<IPluginDescription>(plugins);
     54      this.applications = new List<IApplicationDescription>(apps);
     55      PluginInfrastructure.ApplicationManager.RegisterApplicationManager(this);
     56      LoadPlugins(plugins);
     57    }
     58
     59    private void LoadPlugins(IEnumerable<IPluginDescription> plugins) {
     60      // load all loadable plugins (all dependencies available) into the execution context
     61      foreach (var desc in PluginDescriptionIterator.IterateInDependencyOrder(plugins.Where(x => x.PluginState != PluginState.Disabled))) {
     62        foreach (var plugin in GetInstances<IPlugin>(desc)) {
     63          plugin.OnLoad();
     64        }
     65        desc.Load();
     66      }
     67    }
     68
     69    internal void Run(IApplicationDescription appInfo) {
     70      IApplication runnablePlugin = (IApplication)Activator.CreateInstance(appInfo.DeclaringAssemblyName, appInfo.DeclaringTypeName).Unwrap();
     71      try {
     72        runnablePlugin.Run();
     73      }
     74      catch (Exception e) {
     75        throw new Exception(String.Format(
     76          "Unexpected exception caught: \"{0}\"\r\n" +
     77          "Type: {1}\r\n" +
     78          "Plugin {2}:\r\n{3}",
     79          e.Message,
     80          e.GetType().FullName,
     81          appInfo.Name,
     82          e.ToString()));
     83      }
     84    }
     85
     86    /// <summary>
     87    /// Creates an instance of all types that are subtypes or the same type of the specified type and declared in <paramref name="plugin"/>
     88    /// </summary>
     89    /// <typeparam name="T">Most general type.</typeparam>
     90    /// <returns>Enumerable of the created instances.</returns>
     91    public IEnumerable<T> GetInstances<T>(IPluginDescription plugin) where T : class {
     92      return from t in GetTypes(typeof(T), plugin)
     93             where !t.IsAbstract && !t.IsInterface && !t.HasElementType
     94             select (T)Activator.CreateInstance(t);
     95    }
     96    /// <summary>
     97    /// Creates an instance of all types that are subtypes or the same type of the specified type
     98    /// </summary>
     99    /// <typeparam name="T">Most general type.</typeparam>
     100    /// <returns>Enumerable of the created instances.</returns>
     101    public IEnumerable<T> GetInstances<T>() where T : class {
     102      return from i in GetInstances(typeof(T))
     103             select (T)i;
     104    }
     105
     106    /// <summary>
     107    /// Creates an instance of all types that are subtypes or the same type of the specified type
     108    /// </summary>
     109    /// <typeparam name="type">Most general type.</typeparam>
     110    /// <returns>Enumerable of the created instances.</returns>
     111    public IEnumerable<object> GetInstances(Type type) {
     112      return from t in GetTypes(type)
     113             where !t.IsAbstract && !t.IsInterface && !t.HasElementType
     114             select Activator.CreateInstance(t);
     115    }
     116
     117    /// <summary>
     118    /// Finds all types that are subtypes or equal to the specified type.
     119    /// </summary>
     120    /// <param name="type">Most general type for which to find matching types.</param>
     121    /// <returns>Enumerable of the discovered types.</returns>
     122    public IEnumerable<Type> GetTypes(Type type) {
     123      return from asm in AppDomain.CurrentDomain.GetAssemblies()
     124             from t in GetTypes(type, asm)
     125             select t;
     126    }
     127
     128    /// <summary>
     129    /// Finds all types that are subtypes or equal to the specified type if they are part of the given
     130    /// <paramref name="plugin"/>.
     131    /// </summary>
     132    /// <param name="type">Most general type for which to find matching types.</param>
     133    /// <param name="plugin">The plugin the subtypes must be part of.</param>
     134    /// <returns>Enumerable of the discovered types.</returns>
     135    public IEnumerable<Type> GetTypes(Type type, IPluginDescription pluginDescription) {
     136      return from asm in AppDomain.CurrentDomain.GetAssemblies()
     137             where pluginDescription.Assemblies.Contains(asm.Location)
     138             from t in GetTypes(type, asm)
     139             select t;
     140    }
     141
     142    /// <summary>
     143    /// Gets types that are assignable (same of subtype) to the specified type only from the given assembly.
     144    /// </summary>
     145    /// <param name="type">Most general type we want to find.</param>
     146    /// <param name="assembly">Assembly that should be searched for types.</param>
     147    /// <returns>Enumerable of the discovered types.</returns>
     148    private IEnumerable<Type> GetTypes(Type type, Assembly assembly) {
     149      return from t in assembly.GetTypes()
     150             where type.IsAssignableFrom(t)
     151             select t;
    46152    }
    47153
    48154
    49     private void NotifyListeners(string action, string text) {
    50       if (Action != null) {
    51         Action(this, new PluginManagerActionEventArgs(text, action));
    52       }
     155    // infinite lease time
     156    /// <summary>
     157    /// Initializes the life time service with infinite lease time.
     158    /// </summary>
     159    /// <returns><c>null</c>.</returns>
     160    public override object InitializeLifetimeService() {
     161      return null;
    53162    }
    54163  }
    55164}
     165
  • branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/HeuristicLab.PluginInfrastructure.Manager.csproj

    r2481 r2488  
    4949  <ItemGroup>
    5050    <Compile Include="ApplicationDescription.cs" />
    51     <Compile Include="PluginDescriptionIterator.cs" />
     51    <Compile Include="ApplicationManager.cs">
     52      <SubType>Code</SubType>
     53    </Compile>
    5254    <Compile Include="Loader.cs" />
    53     <Compile Include="PluginState.cs" />
    5455    <Compile Include="PluginDescription.cs" />
    5556    <Compile Include="PluginManager.cs" />
    5657    <Compile Include="PluginManagerActionEventArgs.cs" />
    5758    <Compile Include="Properties\AssemblyInfo.cs" />
    58     <Compile Include="Runner.cs" />
    5959  </ItemGroup>
    6060  <ItemGroup>
  • branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/Loader.cs

    r2481 r2488  
    5555      this.plugins = new List<PluginDescription>();
    5656      this.pluginDependencies = new Dictionary<PluginDescription, List<string>>();
     57
     58      AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ReflectionOnlyAssemblyResolveEventHandler;
     59    }
     60
     61    private Assembly ReflectionOnlyAssemblyResolveEventHandler(object sender, ResolveEventArgs args) {
     62      //try {
     63      return Assembly.ReflectionOnlyLoad(args.Name);
     64      //}
     65      //catch (FileLoadException ex) {
     66      //  return null;
     67      //}
    5768    }
    5869
     
    7081    /// </summary>
    7182    internal void Init() {
    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       //};
    8083      pluginDependencies.Clear();
    8184
     
    9194      CheckPluginDependencies(pluginDescriptions);
    9295
     96      // mark all plugins as enabled that were not disabled in CheckPluginFiles or CheckPluginDependencies
     97      foreach (var desc in pluginDescriptions)
     98        if (desc.PluginState != PluginState.Disabled)
     99          desc.Enable();
     100
    93101      // test full loading (in contrast to reflection only loading) of plugins
    94102      // disables plugins that are not loaded correctly
     
    100108
    101109    private void DiscoverApplications() {
    102       DiscoveryService service = new DiscoveryService();
    103       IApplication[] apps = service.GetInstances<IApplication>();
    104110      applications = new List<ApplicationDescription>();
    105111
    106       foreach (IApplication application in apps) {
     112      foreach (IApplication application in GetApplications()) {
    107113        ApplicationDescription info = new ApplicationDescription();
    108114        info.Name = application.Name;
     
    110116        info.Description = application.Description;
    111117        info.AutoRestart = application.RestartOnErrors;
    112         info.PluginAssembly = application.GetType().Assembly.GetName().Name;
    113         info.PluginType = application.GetType().Namespace + "." + application.GetType().Name;
     118        info.DeclaringAssemblyName = application.GetType().Assembly.GetName().Name;
     119        info.DeclaringTypeName = application.GetType().Namespace + "." + application.GetType().Name;
    114120
    115121        applications.Add(info);
    116122      }
     123    }
     124
     125    private IEnumerable<IApplication> GetApplications() {
     126      return from asm in AppDomain.CurrentDomain.GetAssemblies()
     127             from t in asm.GetTypes()
     128             where typeof(IApplication).IsAssignableFrom(t) &&
     129               !t.IsAbstract && !t.IsInterface && !t.HasElementType
     130             select (IApplication)Activator.CreateInstance(t);
    117131    }
    118132
     
    198212      // iterate through all custom attributes and search for attributed that we are interested in
    199213      foreach (CustomAttributeData attributeData in attributes) {
    200         if (IsAttributeDataForType(attributeData, typeof(PluginDescriptionAttribute))) {
     214        if (IsAttributeDataForType(attributeData, typeof(PluginAttribute))) {
    201215          pluginName = (string)attributeData.ConstructorArguments[0].Value;
    202216        } else if (IsAttributeDataForType(attributeData, typeof(PluginDependencyAttribute))) {
     
    222236        info.AddAssemblies(pluginAssemblies);
    223237        info.AddFiles(pluginFiles);
    224         info.PluginState = PluginState.Undefined;
    225238
    226239        this.pluginDependencies[info] = pluginDependencies;
     
    246259          } else {
    247260            // no plugin description that matches the dependency name is available => plugin is disabled
    248             desc.PluginState = PluginState.Disabled;
     261            desc.Disable();
    249262            break; // stop processing more dependencies
    250263          }
     
    257270        if (IsAnyDependencyDisabled(pluginDescription)) {
    258271          // PluginDescription.Message = "Disabled: missing plugin dependency.";
    259           pluginDescription.PluginState = PluginState.Disabled;
     272          pluginDescription.Disable();
    260273        }
    261274      }
     
    273286    private void LoadPlugins(IEnumerable<PluginDescription> pluginDescriptions) {
    274287      // load all loadable plugins (all dependencies available) into the execution context
    275       foreach (PluginDescription desc in PluginDescriptionIterator.IterateInDependencyOrder(pluginDescriptions.Where(x => x.PluginState != PluginState.Disabled))) {
     288      foreach (var desc in PluginDescriptionIterator.IterateInDependencyOrder(pluginDescriptions
     289                                                                                .Cast<IPluginDescription>()
     290                                                                                .Where(x => x.PluginState != PluginState.Disabled))) {
    276291        List<Type> types = new List<Type>();
    277292        foreach (string assembly in desc.Assemblies) {
     
    288303            IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);
    289304            plugin.OnLoad();
     305            desc.Load();
    290306            PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.PluginLoaded));
    291307          }
     
    335351        if (!CheckPluginFiles(desc)) {
    336352          //plugin.Message = "Disabled: missing plugin file.";
    337           desc.PluginState = PluginState.Disabled;
     353          desc.Disable();
    338354        }
    339355      }
  • branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/PluginDescription.cs

    r2481 r2488  
    3030  /// </summary>
    3131  [Serializable]
    32   public class PluginDescription {
     32  public class PluginDescription : IPluginDescription {
    3333    private string name;
    3434    /// <summary>
     
    6262    public PluginState PluginState {
    6363      get { return pluginState; }
    64       set { pluginState = value; }
     64    }
     65
     66    private int nTimesLoaded;
     67    public void Disable() {
     68      if (pluginState != PluginState.Undefined)
     69        throw new InvalidOperationException("Can't disabled a plugin in state " + pluginState);
     70      pluginState = PluginState.Disabled;
     71    }
     72
     73    public void Enable() {
     74      if (pluginState != PluginState.Undefined)
     75        throw new InvalidOperationException("Can't enabled a plugin in state " + pluginState);
     76      pluginState = PluginState.Enabled;
     77    }
     78
     79    public void Load() {
     80      if (!(pluginState == PluginState.Enabled || pluginState == PluginState.Loaded))
     81        throw new InvalidOperationException("Can't loaded a plugin in state " + pluginState);
     82      pluginState = PluginState.Loaded;
     83      nTimesLoaded++;
     84    }
     85
     86    public void Unload() {
     87      if (pluginState != PluginState.Loaded)
     88        throw new InvalidOperationException("Can't unload a plugin in state " + pluginState);
     89      nTimesLoaded--;
     90      if (nTimesLoaded == 0) pluginState = PluginState.Enabled;
    6591    }
    6692
     
    78104    }
    79105
    80     private List<PluginDescription> dependencies = new List<PluginDescription>();
     106    private List<IPluginDescription> dependencies = new List<IPluginDescription>();
    81107    /// <summary>
    82108    /// Gets all dependencies of the plugin.
    83109    /// </summary>
    84     public IEnumerable<PluginDescription> Dependencies {
     110    public IEnumerable<IPluginDescription> Dependencies {
    85111      get { return dependencies; }
    86112    }
     
    104130    }
    105131
     132    public PluginDescription() {
     133      nTimesLoaded = 0;
     134      pluginState = PluginState.Undefined;
     135    }
     136
     137
    106138    //private string message;
    107139    ///// <summary>
     
    121153    }
    122154
    123     // equals and hashcode have to be implemented because we want to compare PluginDescriptions from
    124     // different AppDomains and serialization destroys reference equality
    125     /// <summary>
    126     /// Checks whether the given object is equal to the current plugin.
    127     /// </summary>
    128     /// <param name="obj">The object to compare.</param>
    129     /// <returns><c>true</c> if it is equal, <c>false</c> otherwise.</returns>
    130     public override bool Equals(object obj) {
    131       if (!(obj is PluginDescription))
    132         return false;
    133       PluginDescription other = (PluginDescription)obj;
     155    //// equals and hashcode have to be implemented because we want to compare PluginDescriptions from
     156    //// different AppDomains and serialization destroys reference equality
     157    ///// <summary>
     158    ///// Checks whether the given object is equal to the current plugin.
     159    ///// </summary>
     160    ///// <param name="obj">The object to compare.</param>
     161    ///// <returns><c>true</c> if it is equal, <c>false</c> otherwise.</returns>
     162    //public override bool Equals(object obj) {
     163    //  if (!(obj is PluginDescription))
     164    //    return false;
     165    //  PluginDescription other = (PluginDescription)obj;
    134166
    135       return other.Name == this.Name && other.Version == this.Version;
    136     }
    137     /// <summary>
    138     /// Gets the hash code of the current plugin.
    139     /// </summary>
    140     /// <returns>The hash code of the plugin.</returns>
    141     public override int GetHashCode() {
    142       if (version != null) {
    143         return name.GetHashCode() + version.GetHashCode();
    144       } else return name.GetHashCode();
    145     }
     167    //  return other.Name == this.Name && other.Version == this.Version;
     168    //}
     169    ///// <summary>
     170    ///// Gets the hash code of the current plugin.
     171    ///// </summary>
     172    ///// <returns>The hash code of the plugin.</returns>
     173    //public override int GetHashCode() {
     174    //  if (version != null) {
     175    //    return name.GetHashCode() + version.GetHashCode();
     176    //  } else return name.GetHashCode();
     177    //}
    146178  }
    147179}
  • branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/PluginManager.cs

    r2481 r2488  
    2727using System.Security.Permissions;
    2828using System.Security;
     29using System.Linq;
    2930
    3031namespace HeuristicLab.PluginInfrastructure.Manager {
     
    8182
    8283    private List<PluginDescription> plugins;
    83     public IEnumerable<PluginDescription> Plugins {
    84       get { return plugins; }
    85     }
     84    //public IEnumerable<PluginDescription> Plugins {
     85    //  get { return plugins; }
     86    //}
    8687
    8788    private List<ApplicationDescription> applications;
     
    109110      plugins = new List<PluginDescription>(remoteLoader.Plugins);
    110111      applications = new List<ApplicationDescription>(remoteLoader.Applications);
    111       throw new NotImplementedException();
     112
     113      // discard the AppDomain that was used for plugin discovery
     114      UnloadAppDomain(pluginDomain);
     115    }
     116
     117    private void UnloadAppDomain(AppDomain appDomain) {
     118      AppDomain.Unload(appDomain);
     119
     120      // set all loaded plugins back to enabled
     121      foreach (var pluginDescription in plugins)
     122        pluginDescription.Unload();
    112123    }
    113124
     
    130141    public void Run(ApplicationDescription appInfo) {
    131142      // create a separate AppDomain for the application
    132       // activate a PluginRunner instance in the application
     143      // initialize the static ApplicationManager in the AppDomain
    133144      // and remotely tell it to start the application
    134145
     
    139150        setup.PrivateBinPath = pluginDir;
    140151        applicationDomain = AppDomain.CreateDomain(appInfo.Name, null, setup);
    141         Runner remoteRunner = (Runner)applicationDomain.CreateInstanceAndUnwrap(typeof(Runner).Assembly.GetName().Name, typeof(Runner).FullName);
    142         remoteRunner.PluginAction += delegate(object sender, PluginManagerActionEventArgs args) { if (Action != null) Action(this, args); };
    143         remoteRunner.LoadPlugins(Plugins);
     152        ApplicationManager applicationManager =
     153          (ApplicationManager)applicationDomain.CreateInstanceAndUnwrap("HeuristicLab.PluginInfraStructure.Manager", "HeuristicLab.PluginInfrastructure.Manager.ApplicationManager");
     154        //applicationManager.PluginAction += delegate(object sender, PluginManagerActionEventArgs args) { if (Action != null) Action(this, args); };
     155        applicationManager.PrepareApplicationDomain(
     156          new List<IApplicationDescription>(applications.Cast<IApplicationDescription>()),
     157          new List<IPluginDescription>(plugins.Cast<IPluginDescription>()));
    144158        NotifyListeners(PluginManagerAction.Initialized, "All plugins");
    145         remoteRunner.Run(appInfo);
     159        applicationManager.Run(appInfo);
    146160      }
    147161      finally {
  • branches/PluginInfrastructure Refactoring/HeuristicLab.PluginInfrastructure.Manager/Runner.cs

    r2481 r2488  
    4444    }
    4545
    46     public void LoadPlugins(IEnumerable<PluginDescription> pluginDescriptions) {
     46    public void LoadPlugins(IEnumerable<IPluginDescription> pluginDescriptions) {
    4747      //FileIOPermission fileperm = new FileIOPermission(FileIOPermissionAccess.AllAccess, @"C:\Program Files\HeuristicLab 3.0\plugins\");
    4848      //fileperm.Assert();
    4949
    5050      // load all loadable plugins (all dependencies available) into the execution context
    51       foreach (PluginDescription desc in PluginDescriptionIterator.IterateInDependencyOrder(pluginDescriptions.Where(x => x.PluginState != PluginState.Disabled))) {
     51      foreach (var desc in PluginDescriptionIterator.IterateInDependencyOrder(pluginDescriptions.Where(x => x.PluginState != PluginState.Disabled))) {
    5252        List<Type> types = new List<Type>();
    5353        foreach (string assembly in desc.Assemblies) {
     
    6464            IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);
    6565            plugin.OnLoad();
     66            desc.Load();
    6667            PluginAction(this, new PluginManagerActionEventArgs(plugin.Name, PluginManagerAction.PluginLoaded));
    6768          }
     
    8889
    8990    public void Run(ApplicationDescription appInfo) {
    90       IApplication runnablePlugin = (IApplication)Activator.CreateInstance(appInfo.PluginAssembly, appInfo.PluginType).Unwrap();
     91      IApplication runnablePlugin = (IApplication)Activator.CreateInstance(appInfo.DeclaringAssemblyName, appInfo.DeclaringTypeName).Unwrap();
    9192      try {
    9293        runnablePlugin.Run();
Note: See TracChangeset for help on using the changeset viewer.