Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.PluginInfrastructure/ApplicationManager.cs @ 3092

Last change on this file since 3092 was 3092, checked in by gkronber, 14 years ago

Fixed relevant warnings in the plugin infrastructure (didn't fix warnings about XML comments of members that will be removed soon). #915 (Remove warnings from HL 3.3 solution)

File size: 13.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Security.Policy;
25using System.Reflection;
26using System.Diagnostics;
27using System.Security.Permissions;
28using System.Security;
29using System.Linq;
30using HeuristicLab.PluginInfrastructure.Manager;
31using System.IO;
32
33namespace HeuristicLab.PluginInfrastructure {
34
35  /// <summary>
36  /// The ApplicationManager has a reference to the application manager singleton.
37  /// The application manager provides
38  /// </summary>
39  public sealed class ApplicationManager : MarshalByRefObject, IApplicationManager {
40    private static IApplicationManager appManager;
41    /// <summary>
42    /// Gets the application manager singleton.
43    /// </summary>
44    public static IApplicationManager Manager {
45      get { return appManager; }
46    }
47
48    /// <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>
105    /// Registers a new application manager.
106    /// </summary>
107    /// <param name="manager"></param>
108    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();
131      }
132    }
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
318  }
319}
Note: See TracBrowser for help on using the repository browser.