Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 2716 was 2693, checked in by gkronber, 15 years ago

Fixed a bug introduced with r2690 #854

File size: 12.2 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      AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
78        if (loadedAssemblies.ContainsKey(args.Name)) {
79          return loadedAssemblies[args.Name];
80        }
81        return null;
82      };
83    }
84
85    internal void PrepareApplicationDomain(IEnumerable<ApplicationDescription> apps, IEnumerable<PluginDescription> plugins) {
86      this.plugins = new List<PluginDescription>(plugins);
87      this.applications = new List<ApplicationDescription>(apps);
88      RegisterApplicationManager((IApplicationManager)this);
89      LoadPlugins(plugins);
90    }
91
92    /// <summary>
93    /// Registers a new application manager.
94    /// </summary>
95    /// <param name="manager"></param>
96    internal static void RegisterApplicationManager(IApplicationManager manager) {
97      if (appManager != null) throw new InvalidOperationException("The application manager has already been set.");
98      appManager = manager;
99    }
100
101    private void LoadPlugins(IEnumerable<PluginDescription> plugins) {
102      // load all loadable plugins (all dependencies available) into the execution context
103      foreach (var desc in PluginDescriptionIterator.IterateDependenciesBottomUp(plugins.Where(x => x.PluginState != PluginState.Disabled))) {
104        foreach (string fileName in desc.AssemblyLocations) {
105          var asm = Assembly.LoadFrom(fileName);
106          RegisterLoadedAssembly(asm);
107          // instantiate and load all plugins in this assembly
108          foreach (var plugin in GetInstances<IPlugin>(asm)) {
109            plugin.OnLoad();
110            loadedPlugins.Add(plugin);
111          }
112        }
113        OnPluginLoaded(new PluginInfrastructureEventArgs("Plugin loaded", desc));
114        desc.Load();
115      }
116    }
117
118    internal void Run(ApplicationDescription appInfo) {
119      IApplication runnablePlugin = (IApplication)Activator.CreateInstance(appInfo.DeclaringAssemblyName, appInfo.DeclaringTypeName).Unwrap();
120      try {
121        runnablePlugin.Run();
122      }
123      finally {
124        // unload plugins in reverse order
125        foreach (var plugin in loadedPlugins.Reverse<IPlugin>()) {
126          plugin.OnUnload();
127        }
128        foreach (var desc in PluginDescriptionIterator.IterateDependenciesBottomUp(plugins.Where(x => x.PluginState != PluginState.Disabled))) {
129          desc.Unload();
130          OnPluginUnloaded(new PluginInfrastructureEventArgs("Plugin unloaded", desc));
131        }
132      }
133    }
134
135    /// <summary>
136    /// Loads assemblies dynamically from a byte array
137    /// </summary>
138    /// <param name="plugins">bytearray of all assemblies that should be loaded</param>
139    internal void LoadAssemblies(IEnumerable<byte[]> assemblies) {
140      foreach (byte[] asm in assemblies) {
141        Assembly loadedAsm = Assembly.Load(asm);
142        RegisterLoadedAssembly(loadedAsm);
143      }
144    }
145
146    // register assembly in the assembly cache for the AssemblyResolveEvent
147    private void RegisterLoadedAssembly(Assembly asm) {
148      loadedAssemblies.Add(asm.FullName, asm);
149      loadedAssemblies.Add(asm.GetName().Name, asm); // add short name
150    }
151
152    /// <summary>
153    /// Creates an instance of all types that are subtypes or the same type of the specified type and declared in <paramref name="plugin"/>
154    /// </summary>
155    /// <typeparam name="T">Most general type.</typeparam>
156    /// <returns>Enumerable of the created instances.</returns>
157    internal static IEnumerable<T> GetInstances<T>(IPluginDescription plugin) where T : class {
158      return from t in GetTypes(typeof(T), plugin, true)
159             select (T)Activator.CreateInstance(t);
160    }
161    /// <summary>
162    /// 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"/>
163    /// </summary>
164    /// <typeparam name="T">Most general type.</typeparam>
165    /// <param name="asm">Declaring assembly.</param>
166    /// <returns>Enumerable of the created instances.</returns>
167    private static IEnumerable<T> GetInstances<T>(Assembly asm) where T : class {
168      return from t in GetTypes(typeof(T), asm, true)
169             select (T)Activator.CreateInstance(t);
170    }
171    /// <summary>
172    /// Creates an instance of all types that are subtypes or the same type of the specified type
173    /// </summary>
174    /// <typeparam name="T">Most general type.</typeparam>
175    /// <returns>Enumerable of the created instances.</returns>
176    internal static IEnumerable<T> GetInstances<T>() where T : class {
177      return from i in GetInstances(typeof(T))
178             select (T)i;
179    }
180
181    /// <summary>
182    /// Creates an instance of all types that are subtypes or the same type of the specified type
183    /// </summary>
184    /// <typeparam name="type">Most general type.</typeparam>
185    /// <returns>Enumerable of the created instances.</returns>
186    internal static IEnumerable<object> GetInstances(Type type) {
187      return (from t in GetTypes(type, true)
188              select Activator.CreateInstance(t)).ToList();
189    }
190
191    /// <summary>
192    /// Finds all types that are subtypes or equal to the specified type.
193    /// </summary>
194    /// <param name="type">Most general type for which to find matching types.</param>
195    /// <param name="onlyInstantiable">Return only types that are instantiable (instance, abstract... are not returned)</param>
196    /// <returns>Enumerable of the discovered types.</returns>
197    internal static IEnumerable<Type> GetTypes(Type type, bool onlyInstantiable) {
198      return from asm in AppDomain.CurrentDomain.GetAssemblies()
199             from t in GetTypes(type, asm, onlyInstantiable)
200             select t;
201    }
202
203    /// <summary>
204    /// Finds all types that are subtypes or equal to the specified type if they are part of the given
205    /// <paramref name="plugin"/>.
206    /// </summary>
207    /// <param name="type">Most general type for which to find matching types.</param>
208    /// <param name="plugin">The plugin the subtypes must be part of.</param>
209    /// <param name="onlyInstantiable">Return only types that are instantiable (instance, abstract... are not returned)</param>
210    /// <returns>Enumerable of the discovered types.</returns>
211    internal static IEnumerable<Type> GetTypes(Type type, IPluginDescription pluginDescription, bool onlyInstantiable) {
212      PluginDescription pluginDesc = (PluginDescription)pluginDescription;
213      return from asm in AppDomain.CurrentDomain.GetAssemblies()
214             where !string.IsNullOrEmpty(asm.Location) // ignore dynamically generated assemblies
215             where pluginDesc.AssemblyLocations.Any(location => location.Equals(Path.GetFullPath(asm.Location), StringComparison.CurrentCultureIgnoreCase))
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.AssemblyLocations.Contains(Path.GetFullPath(type.Assembly.Location))) return info;
286      }
287      return null;
288    }
289    #endregion
290  }
291}
Note: See TracBrowser for help on using the repository browser.