Free cookie consent management tool by TermsFeed Policy Generator

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

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

Implemented an enumerable to iterate through all PluginFiles as suggested by swagner, replaced the Assemblies enumerable with an AssemblyName enumerable for internal usage in the plugin infrastructure and replaced Assembly.LoadFrom calls with Assembly.Load() to prevent loading from GAC as far as possible.

#850 (PluginInfrastructure should provide a way to get assemblies associated with a plug-in)

File size: 12.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 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    internal event EventHandler<PluginInfrastructureEventArgs> PluginLoaded;
49    internal event EventHandler<PluginInfrastructureEventArgs> PluginUnloaded;
50
51    // cache for the AssemblyResolveEvent
52    // which must be handled when assemblies are loaded dynamically after the application start
53    private Dictionary<string, Assembly> loadedAssemblies;
54
55    private List<IPlugin> loadedPlugins;
56
57    private List<PluginDescription> plugins;
58    /// <summary>
59    /// Gets all plugins.
60    /// </summary>
61    public IEnumerable<IPluginDescription> Plugins {
62      get { return plugins.Cast<IPluginDescription>(); }
63    }
64
65    private List<ApplicationDescription> applications;
66    /// <summary>
67    /// Gets all installed applications.
68    /// </summary>
69    public IEnumerable<IApplicationDescription> Applications {
70      get { return applications.Cast<IApplicationDescription>(); }
71    }
72
73    internal ApplicationManager()
74      : base() {
75      loadedAssemblies = new Dictionary<string, Assembly>();
76      loadedPlugins = new List<IPlugin>();
77      // needed for the special case when assemblies are loaded dynamically via LoadAssemblies()
78      AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
79        if (loadedAssemblies.ContainsKey(args.Name)) {
80          return loadedAssemblies[args.Name];
81        }
82        return null;
83      };
84    }
85
86    internal void PrepareApplicationDomain(IEnumerable<ApplicationDescription> apps, IEnumerable<PluginDescription> plugins) {
87      this.plugins = new List<PluginDescription>(plugins);
88      this.applications = new List<ApplicationDescription>(apps);
89      RegisterApplicationManager((IApplicationManager)this);
90      LoadPlugins(plugins);
91    }
92
93    /// <summary>
94    /// Registers a new application manager.
95    /// </summary>
96    /// <param name="manager"></param>
97    internal static void RegisterApplicationManager(IApplicationManager manager) {
98      if (appManager != null) throw new InvalidOperationException("The application manager has already been set.");
99      appManager = manager;
100    }
101
102    private void LoadPlugins(IEnumerable<PluginDescription> plugins) {
103      // load all loadable plugins (all dependencies available) into the execution context
104      foreach (var desc in PluginDescriptionIterator.IterateDependenciesBottomUp(plugins.Where(x => x.PluginState != PluginState.Disabled))) {
105        foreach (AssemblyName assemblyName in desc.AssemblyNames) {
106          var asm = Assembly.Load(assemblyName);
107
108          // instantiate and load all plugins in this assembly
109          foreach (var plugin in GetInstances<IPlugin>(asm)) {
110            plugin.OnLoad();
111            loadedPlugins.Add(plugin);
112          }
113        }
114        OnPluginLoaded(new PluginInfrastructureEventArgs("Plugin loaded", desc));
115        desc.Load();
116      }
117    }
118
119    internal void Run(ApplicationDescription appInfo) {
120      IApplication runnablePlugin = (IApplication)Activator.CreateInstance(appInfo.DeclaringAssemblyName, appInfo.DeclaringTypeName).Unwrap();
121      try {
122        runnablePlugin.Run();
123      }
124      finally {
125        // unload plugins in reverse order
126        foreach (var plugin in loadedPlugins.Reverse<IPlugin>()) {
127          plugin.OnUnload();
128        }
129        foreach (var desc in PluginDescriptionIterator.IterateDependenciesBottomUp(plugins.Where(x => x.PluginState != PluginState.Disabled))) {
130          desc.Unload();
131          OnPluginUnloaded(new PluginInfrastructureEventArgs("Plugin unloaded", desc));
132        }
133      }
134    }
135
136    /// <summary>
137    /// Loads assemblies dynamically from a byte array
138    /// </summary>
139    /// <param name="plugins">bytearray of all assemblies that should be loaded</param>
140    internal void LoadAssemblies(IEnumerable<byte[]> assemblies) {
141      foreach (byte[] asm in assemblies) {
142        Assembly loadedAsm = Assembly.Load(asm);
143        RegisterLoadedAssembly(loadedAsm);
144      }
145    }
146
147    // register assembly in the assembly cache for the AssemblyResolveEvent
148    private void RegisterLoadedAssembly(Assembly asm) {
149      loadedAssemblies.Add(asm.FullName, asm);
150      loadedAssemblies.Add(asm.GetName().Name, asm); // add short name
151    }
152
153    /// <summary>
154    /// Creates an instance of all types that are subtypes or the same type of the specified type and declared in <paramref name="plugin"/>
155    /// </summary>
156    /// <typeparam name="T">Most general type.</typeparam>
157    /// <returns>Enumerable of the created instances.</returns>
158    internal static IEnumerable<T> GetInstances<T>(IPluginDescription plugin) where T : class {
159      return from t in GetTypes(typeof(T), plugin, true)
160             select (T)Activator.CreateInstance(t);
161    }
162    /// <summary>
163    /// Creates an instance of all types declared in assembly <param name="asm"/> that are subtypes or the same type of the specified type and declared in <paramref name="plugin"/>
164    /// </summary>
165    /// <typeparam name="T">Most general type.</typeparam>
166    /// <param name="asm">Declaring assembly.</param>
167    /// <returns>Enumerable of the created instances.</returns>
168    private static IEnumerable<T> GetInstances<T>(Assembly asm) where T : class {
169      return from t in GetTypes(typeof(T), asm, true)
170             select (T)Activator.CreateInstance(t);
171    }
172    /// <summary>
173    /// Creates an instance of all types that are subtypes or the same type of the specified type
174    /// </summary>
175    /// <typeparam name="T">Most general type.</typeparam>
176    /// <returns>Enumerable of the created instances.</returns>
177    internal static IEnumerable<T> GetInstances<T>() where T : class {
178      return from i in GetInstances(typeof(T))
179             select (T)i;
180    }
181
182    /// <summary>
183    /// Creates an instance of all types that are subtypes or the same type of the specified type
184    /// </summary>
185    /// <typeparam name="type">Most general type.</typeparam>
186    /// <returns>Enumerable of the created instances.</returns>
187    internal static IEnumerable<object> GetInstances(Type type) {
188      return (from t in GetTypes(type, true)
189              select Activator.CreateInstance(t)).ToList();
190    }
191
192    /// <summary>
193    /// Finds all types that are subtypes or equal to the specified type.
194    /// </summary>
195    /// <param name="type">Most general type for which to find matching types.</param>
196    /// <param name="onlyInstantiable">Return only types that are instantiable (instance, abstract... are not returned)</param>
197    /// <returns>Enumerable of the discovered types.</returns>
198    internal static IEnumerable<Type> GetTypes(Type type, bool onlyInstantiable) {
199      return from asm in AppDomain.CurrentDomain.GetAssemblies()
200             from t in GetTypes(type, asm, onlyInstantiable)
201             select t;
202    }
203
204    /// <summary>
205    /// Finds all types that are subtypes or equal to the specified type if they are part of the given
206    /// <paramref name="plugin"/>.
207    /// </summary>
208    /// <param name="type">Most general type for which to find matching types.</param>
209    /// <param name="plugin">The plugin the subtypes must be part of.</param>
210    /// <param name="onlyInstantiable">Return only types that are instantiable (instance, abstract... are not returned)</param>
211    /// <returns>Enumerable of the discovered types.</returns>
212    internal static IEnumerable<Type> GetTypes(Type type, IPluginDescription pluginDescription, bool onlyInstantiable) {
213      PluginDescription pluginDesc = (PluginDescription)pluginDescription;
214      return from asm in AppDomain.CurrentDomain.GetAssemblies()
215             where pluginDesc.AssemblyNames.Any(asmName => asmName.FullName.Equals(asm.GetName().FullName))
216             from t in GetTypes(type, asm, onlyInstantiable)
217             select t;
218    }
219
220    /// <summary>
221    /// Gets types that are assignable (same of subtype) to the specified type only from the given assembly.
222    /// </summary>
223    /// <param name="type">Most general type we want to find.</param>
224    /// <param name="assembly">Assembly that should be searched for types.</param>
225    /// <param name="onlyInstantiable">Return only types that are instantiable (instance, abstract... are not returned)</param>
226    /// <returns>Enumerable of the discovered types.</returns>
227    private static IEnumerable<Type> GetTypes(Type type, Assembly assembly, bool onlyInstantiable) {
228      return from t in assembly.GetTypes()
229             where type.IsAssignableFrom(t)
230             where onlyInstantiable == false || (!t.IsAbstract && !t.IsInterface && !t.HasElementType)
231             select t;
232    }
233
234    private void OnPluginLoaded(PluginInfrastructureEventArgs e) {
235      if (PluginLoaded != null) PluginLoaded(this, e);
236    }
237
238    private void OnPluginUnloaded(PluginInfrastructureEventArgs e) {
239      if (PluginUnloaded != null) PluginUnloaded(this, e);
240    }
241
242    // infinite lease time
243    /// <summary>
244    /// Initializes the life time service with infinite lease time.
245    /// </summary>
246    /// <returns><c>null</c>.</returns>
247    public override object InitializeLifetimeService() {
248      return null;
249    }
250
251    #region IApplicationManager Members
252
253    IEnumerable<T> IApplicationManager.GetInstances<T>() {
254      return GetInstances<T>();
255    }
256
257    IEnumerable<object> IApplicationManager.GetInstances(Type type) {
258      return GetInstances(type);
259    }
260
261    IEnumerable<Type> IApplicationManager.GetTypes(Type type) {
262      return GetTypes(type, true);
263    }
264
265    IEnumerable<Type> IApplicationManager.GetTypes(Type type, bool onlyInstantiable) {
266      return GetTypes(type, onlyInstantiable);
267    }
268
269    IEnumerable<Type> IApplicationManager.GetTypes(Type type, IPluginDescription plugin) {
270      return GetTypes(type, plugin, true);
271    }
272
273    IEnumerable<Type> IApplicationManager.GetTypes(Type type, IPluginDescription plugin, bool onlyInstantiable) {
274      return GetTypes(type, plugin, onlyInstantiable);
275    }
276
277
278    /// <summary>
279    /// Finds the plugin that declares the <paramref name="type">type</paramref>.
280    /// </summary>
281    /// <param name="type">The type of interest.</param>
282    /// <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>
283    public IPluginDescription GetDeclaringPlugin(Type type) {
284      foreach (PluginDescription info in Plugins) {
285        if (info.AssemblyNames.Contains(type.Assembly.GetName())) return info;
286      }
287      return null;
288    }
289    #endregion
290  }
291}
Note: See TracBrowser for help on using the repository browser.