Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
04/01/10 12:36:29 (14 years ago)
Author:
gkronber
Message:

Implemented a LightweightApplicationManager for unit testing and extracted the DefaultApplicationManager out of class ApplicationManager. #954 (ApplicationManager.Manager should have a default instance to enable unit testing)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.PluginInfrastructure/ApplicationManager.cs

    r3092 r3247  
    3535  /// <summary>
    3636  /// The ApplicationManager has a reference to the application manager singleton.
    37   /// The application manager provides
    3837  /// </summary>
    39   public sealed class ApplicationManager : MarshalByRefObject, IApplicationManager {
    40     private static IApplicationManager appManager;
     38  public static class ApplicationManager {
     39    // the singleton instance is initialized to LightweightApplicationManager as long as no other application manager is registered
     40    private static IApplicationManager appManager = new LightweightApplicationManager();
    4141    /// <summary>
    4242    /// Gets the application manager singleton.
     
    4747
    4848    /// <summary>
    49     /// Fired when a plugin is loaded.
    50     /// </summary>
    51     internal event EventHandler<PluginInfrastructureEventArgs> PluginLoaded;
    52     /// <summary>
    53     /// Fired when a plugin is unloaded (when the application terminates).
    54     /// </summary>
    55     internal event EventHandler<PluginInfrastructureEventArgs> PluginUnloaded;
    56 
    57     // cache for the AssemblyResolveEvent
    58     // which must be handled when assemblies are loaded dynamically after the application start
    59     private Dictionary<string, Assembly> loadedAssemblies;
    60 
    61     private List<IPlugin> loadedPlugins;
    62 
    63     private List<PluginDescription> plugins;
    64     /// <summary>
    65     /// Gets all plugins.
    66     /// </summary>
    67     public IEnumerable<IPluginDescription> Plugins {
    68       get { return plugins.Cast<IPluginDescription>(); }
    69     }
    70 
    71     private List<ApplicationDescription> applications;
    72     /// <summary>
    73     /// Gets all installed applications.
    74     /// </summary>
    75     public IEnumerable<IApplicationDescription> Applications {
    76       get { return applications.Cast<IApplicationDescription>(); }
    77     }
    78 
    79     internal ApplicationManager()
    80       : base() {
    81       loadedAssemblies = new Dictionary<string, Assembly>();
    82       loadedPlugins = new List<IPlugin>();
    83       AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
    84         if (loadedAssemblies.ContainsKey(args.Name)) {
    85           return loadedAssemblies[args.Name];
    86         }
    87         return null;
    88       };
    89     }
    90 
    91     /// <summary>
    92     /// Prepares the application domain for the execution of an HL application.
    93     /// Pre-loads all <paramref name="plugins"/>.
    94     /// </summary>
    95     /// <param name="apps">Enumerable of available HL applications.</param>
    96     /// <param name="plugins">Enumerable of plugins that should be pre-loaded.</param>
    97     internal void PrepareApplicationDomain(IEnumerable<ApplicationDescription> apps, IEnumerable<PluginDescription> plugins) {
    98       this.plugins = new List<PluginDescription>(plugins);
    99       this.applications = new List<ApplicationDescription>(apps);
    100       RegisterApplicationManager((IApplicationManager)this);
    101       LoadPlugins(plugins);
    102     }
    103 
    104     /// <summary>
    10549    /// Registers a new application manager.
    10650    /// </summary>
    10751    /// <param name="manager"></param>
    10852    internal static void RegisterApplicationManager(IApplicationManager manager) {
    109       if (appManager != null) throw new InvalidOperationException("The application manager has already been set.");
    110       appManager = manager;
    111     }
    112 
    113     /// <summary>
    114     /// Loads the <paramref name="plugins"/> into this application domain.
    115     /// </summary>
    116     /// <param name="plugins">Enumerable of plugins that should be loaded.</param>
    117     private void LoadPlugins(IEnumerable<PluginDescription> plugins) {
    118       // load all loadable plugins (all dependencies available) into the execution context
    119       foreach (var desc in PluginDescriptionIterator.IterateDependenciesBottomUp(plugins.Where(x => x.PluginState != PluginState.Disabled))) {
    120         foreach (string fileName in desc.AssemblyLocations) {
    121           var asm = Assembly.LoadFrom(fileName);
    122           RegisterLoadedAssembly(asm);
    123           // instantiate and load all plugins in this assembly
    124           foreach (var plugin in GetInstances<IPlugin>(asm)) {
    125             plugin.OnLoad();
    126             loadedPlugins.Add(plugin);
    127           }
    128         }
    129         OnPluginLoaded(new PluginInfrastructureEventArgs(desc));
    130         desc.Load();
     53      if (!(appManager is LightweightApplicationManager)) throw new InvalidOperationException("The application manager has already been set.");
     54      else {
     55        appManager = manager;
    13156      }
    13257    }
    133 
    134     /// <summary>
    135     /// Runs the application declared in <paramref name="appInfo"/>.
    136     /// This is a synchronous call. When the application is terminated all plugins are unloaded.
    137     /// </summary>
    138     /// <param name="appInfo">Description of the application to run</param>
    139     internal void Run(ApplicationDescription appInfo) {
    140       IApplication runnablePlugin = (IApplication)Activator.CreateInstance(appInfo.DeclaringAssemblyName, appInfo.DeclaringTypeName).Unwrap();
    141       try {
    142         runnablePlugin.Run();
    143       }
    144       finally {
    145         // unload plugins in reverse order
    146         foreach (var plugin in loadedPlugins.Reverse<IPlugin>()) {
    147           plugin.OnUnload();
    148         }
    149         foreach (var desc in PluginDescriptionIterator.IterateDependenciesBottomUp(plugins.Where(x => x.PluginState != PluginState.Disabled))) {
    150           desc.Unload();
    151           OnPluginUnloaded(new PluginInfrastructureEventArgs(desc));
    152         }
    153       }
    154     }
    155 
    156     /// <summary>
    157     /// Loads raw assemblies dynamically from a byte array
    158     /// </summary>
    159     /// <param name="assemblies">bytearray of all raw assemblies that should be loaded</param>
    160     internal void LoadAssemblies(IEnumerable<byte[]> assemblies) {
    161       foreach (byte[] asm in assemblies) {
    162         Assembly loadedAsm = Assembly.Load(asm);
    163         RegisterLoadedAssembly(loadedAsm);
    164       }
    165     }
    166 
    167     // register assembly in the assembly cache for the AssemblyResolveEvent
    168     private void RegisterLoadedAssembly(Assembly asm) {
    169       loadedAssemblies.Add(asm.FullName, asm);
    170       loadedAssemblies.Add(asm.GetName().Name, asm); // add short name
    171     }
    172 
    173     /// <summary>
    174     /// Creates an instance of all types that are subtypes or the same type of the specified type and declared in <paramref name="plugin"/>
    175     /// </summary>
    176     /// <typeparam name="T">Most general type.</typeparam>
    177     /// <returns>Enumerable of the created instances.</returns>
    178     internal static IEnumerable<T> GetInstances<T>(IPluginDescription plugin) where T : class {
    179       return from t in GetTypes(typeof(T), plugin, true)
    180              select (T)Activator.CreateInstance(t);
    181     }
    182     /// <summary>
    183     /// Creates an instance of all types declared in assembly <paramref name="asm"/> that are subtypes or the same type of the specified <typeparamref name="type"/>.
    184     /// </summary>
    185     /// <typeparam name="T">Most general type.</typeparam>
    186     /// <param name="asm">Declaring assembly.</param>
    187     /// <returns>Enumerable of the created instances.</returns>
    188     private static IEnumerable<T> GetInstances<T>(Assembly asm) where T : class {
    189       return from t in GetTypes(typeof(T), asm, true)
    190              select (T)Activator.CreateInstance(t);
    191     }
    192     /// <summary>
    193     /// Creates an instance of all types that are subtypes or the same type of the specified type
    194     /// </summary>
    195     /// <typeparam name="T">Most general type.</typeparam>
    196     /// <returns>Enumerable of the created instances.</returns>
    197     internal static IEnumerable<T> GetInstances<T>() where T : class {
    198       return from i in GetInstances(typeof(T))
    199              select (T)i;
    200     }
    201 
    202     /// <summary>
    203     /// Creates an instance of all types that are subtypes or the same type of the specified type
    204     /// </summary>
    205     /// <param name="type">Most general type.</param>
    206     /// <returns>Enumerable of the created instances.</returns>
    207     internal static IEnumerable<object> GetInstances(Type type) {
    208       return (from t in GetTypes(type, true)
    209               select Activator.CreateInstance(t)).ToList();
    210     }
    211 
    212     /// <summary>
    213     /// Finds all types that are subtypes or equal to the specified type.
    214     /// </summary>
    215     /// <param name="type">Most general type for which to find matching types.</param>
    216     /// <param name="onlyInstantiable">Return only types that are instantiable
    217     /// (interfaces, abstract classes... are not returned)</param>
    218     /// <returns>Enumerable of the discovered types.</returns>
    219     internal static IEnumerable<Type> GetTypes(Type type, bool onlyInstantiable) {
    220       return from asm in AppDomain.CurrentDomain.GetAssemblies()
    221              from t in GetTypes(type, asm, onlyInstantiable)
    222              select t;
    223     }
    224 
    225     /// <summary>
    226     /// Finds all types that are subtypes or equal to the specified type if they are part of the given
    227     /// <paramref name="pluginDescription"/>.
    228     /// </summary>
    229     /// <param name="type">Most general type for which to find matching types.</param>
    230     /// <param name="pluginDescription">The plugin the subtypes must be part of.</param>
    231     /// <param name="onlyInstantiable">Return only types that are instantiable
    232     /// (interfaces, abstract classes... are not returned)</param>
    233     /// <returns>Enumerable of the discovered types.</returns>
    234     internal static IEnumerable<Type> GetTypes(Type type, IPluginDescription pluginDescription, bool onlyInstantiable) {
    235       PluginDescription pluginDesc = (PluginDescription)pluginDescription;
    236       return from asm in AppDomain.CurrentDomain.GetAssemblies()
    237              where !IsDynamicAssembly(asm)
    238              where pluginDesc.AssemblyLocations.Any(location => location.Equals(Path.GetFullPath(asm.Location), StringComparison.CurrentCultureIgnoreCase))
    239              from t in GetTypes(type, asm, onlyInstantiable)
    240              select t;
    241     }
    242 
    243     private static bool IsDynamicAssembly(Assembly asm) {
    244       return (asm is System.Reflection.Emit.AssemblyBuilder) || string.IsNullOrEmpty(asm.Location);
    245     }
    246 
    247     /// <summary>
    248     /// Gets types that are assignable (same of subtype) to the specified type only from the given assembly.
    249     /// </summary>
    250     /// <param name="type">Most general type we want to find.</param>
    251     /// <param name="assembly">Assembly that should be searched for types.</param>
    252     /// <param name="onlyInstantiable">Return only types that are instantiable
    253     /// (interfaces, abstract classes...  are not returned)</param>
    254     /// <returns>Enumerable of the discovered types.</returns>
    255     private static IEnumerable<Type> GetTypes(Type type, Assembly assembly, bool onlyInstantiable) {
    256       return from t in assembly.GetTypes()
    257              where type.IsAssignableFrom(t)
    258              where onlyInstantiable == false || (!t.IsAbstract && !t.IsInterface && !t.HasElementType)
    259              select t;
    260     }
    261 
    262     private void OnPluginLoaded(PluginInfrastructureEventArgs e) {
    263       if (PluginLoaded != null) PluginLoaded(this, e);
    264     }
    265 
    266     private void OnPluginUnloaded(PluginInfrastructureEventArgs e) {
    267       if (PluginUnloaded != null) PluginUnloaded(this, e);
    268     }
    269 
    270     // infinite lease time
    271     /// <summary>
    272     /// Initializes the life time service with infinite lease time.
    273     /// </summary>
    274     /// <returns><c>null</c>.</returns>
    275     public override object InitializeLifetimeService() {
    276       return null;
    277     }
    278 
    279     #region IApplicationManager Members
    280 
    281     IEnumerable<T> IApplicationManager.GetInstances<T>() {
    282       return GetInstances<T>();
    283     }
    284 
    285     IEnumerable<object> IApplicationManager.GetInstances(Type type) {
    286       return GetInstances(type);
    287     }
    288 
    289     IEnumerable<Type> IApplicationManager.GetTypes(Type type) {
    290       return GetTypes(type, true);
    291     }
    292 
    293     IEnumerable<Type> IApplicationManager.GetTypes(Type type, bool onlyInstantiable) {
    294       return GetTypes(type, onlyInstantiable);
    295     }
    296 
    297     IEnumerable<Type> IApplicationManager.GetTypes(Type type, IPluginDescription plugin) {
    298       return GetTypes(type, plugin, true);
    299     }
    300 
    301     IEnumerable<Type> IApplicationManager.GetTypes(Type type, IPluginDescription plugin, bool onlyInstantiable) {
    302       return GetTypes(type, plugin, onlyInstantiable);
    303     }
    304 
    305 
    306     /// <summary>
    307     /// Finds the plugin that declares the <paramref name="type">type</paramref>.
    308     /// </summary>
    309     /// <param name="type">The type of interest.</param>
    310     /// <returns>The description of the plugin that declares the given type or null if the type has not been declared by a known plugin.</returns>
    311     public IPluginDescription GetDeclaringPlugin(Type type) {
    312       foreach (PluginDescription info in Plugins) {
    313         if (info.AssemblyLocations.Contains(Path.GetFullPath(type.Assembly.Location))) return info;
    314       }
    315       return null;
    316     }
    317     #endregion
    31858  }
    31959}
Note: See TracChangeset for help on using the changeset viewer.