Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.PluginInfrastructure/PluginManager.cs @ 766

Last change on this file since 766 was 766, checked in by gkronber, 16 years ago

fixed #362 (GridClient doesn't work since the change to use major.minor version-numbers for plugins)

File size: 7.3 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;
24
25namespace HeuristicLab.PluginInfrastructure {
26
27  // must extend MarshalByRefObject because of event passing between Loader and PluginManager (each in it's own AppDomain)
28  public class PluginManager : MarshalByRefObject {
29
30    // singleton: only one manager allowed in each AppDomain
31    private static PluginManager manager = new PluginManager();
32    public static PluginManager Manager {
33      get { return manager; }
34    }
35
36    // singleton: only one control manager allowed in each applicatoin (i.e. AppDomain)
37    private static IControlManager controlManager;
38    public static IControlManager ControlManager {
39      get { return controlManager; }
40      set { controlManager = value; }
41    }
42
43    public event PluginManagerActionEventHandler Action;
44
45    // holds a proxy for the loader in the special AppDomain for PluginManagament
46    private Loader remoteLoader;
47    private AppDomain pluginDomain;
48    private string pluginDir;
49
50    // singleton pattern
51    private PluginManager() {
52      this.pluginDir = HeuristicLab.PluginInfrastructure.Properties.Settings.Default.PluginDir;
53    }
54
55    public ICollection<PluginInfo> InstalledPlugins {
56      get { return remoteLoader.InstalledPlugins; }
57    }
58
59    public ICollection<PluginInfo> DisabledPlugins {
60      get { return remoteLoader.DisabledPlugins; }
61    }
62
63    public ICollection<PluginInfo> ActivePlugins {
64      get { return remoteLoader.ActivePlugins; }
65    }
66
67    public ICollection<ApplicationInfo> InstalledApplications {
68      get { return remoteLoader.InstalledApplications; }
69    }
70
71    private ICollection<PluginInfo> loadedPlugins;
72    public ICollection<PluginInfo> LoadedPlugins {
73      get { return loadedPlugins; }
74      internal set { loadedPlugins = value; }
75    }
76
77    /// <summary>
78    /// Creates a dedicated AppDomain for loading all plugins and checking dependencies.
79    /// </summary>
80    public void Initialize() {
81      NotifyListeners(PluginManagerAction.Initializing, "-");
82      AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
83      setup.PrivateBinPath = pluginDir;
84      pluginDomain = AppDomain.CreateDomain("plugin domain", null, setup);
85      remoteLoader = (Loader)pluginDomain.CreateInstanceAndUnwrap("HeuristicLab.PluginInfraStructure", "HeuristicLab.PluginInfrastructure.Loader");
86      remoteLoader.PluginAction += delegate(object sender, PluginManagerActionEventArgs args) { if (Action != null) Action(this, args); };
87      remoteLoader.Init();
88      NotifyListeners(PluginManagerAction.Initialized, "-");
89    }
90
91    /// <summary>
92    /// Creates a separate AppDomain.
93    /// Loads all active plugin assemblies and starts the application in the new AppDomain via a PluginRunner instance activated in the new AppDomain
94    /// </summary>
95    /// <param name="appInfo">application to run</param>
96    public void Run(ApplicationInfo appInfo) {
97      // create a separate AppDomain for the application
98      // activate a PluginRunner instance in the application
99      // and remotely tell it to start the application
100
101      NotifyListeners(PluginManagerAction.Starting, appInfo.Name);
102      AppDomain applicationDomain = null;
103      try {
104        applicationDomain = CreateAndInitAppDomain(appInfo.Name + " AppDomain");
105        Runner remoteRunner = (Runner)applicationDomain.CreateInstanceAndUnwrap(typeof(Runner).Assembly.GetName().Name, typeof(Runner).FullName);
106        remoteRunner.Run(appInfo);
107      }
108      finally {
109        // make sure domain is unloaded in all cases
110        if (applicationDomain != null) AppDomain.Unload(applicationDomain);
111      }
112    }
113
114    /// <summary>
115    /// Creates a new AppDomain with all plugins preloaded.
116    /// </summary>
117    /// <param name="friendlyName">Name of the new AppDomain</param>
118    /// <returns>the new AppDomain with all plugins preloaded.</returns>
119    public AppDomain CreateAndInitAppDomain(string friendlyName) {
120      AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
121      setup.PrivateBinPath = pluginDir;
122      AppDomain applicationDomain = AppDomain.CreateDomain(friendlyName, null, setup);
123      Runner remoteRunner = (Runner)applicationDomain.CreateInstanceAndUnwrap(typeof(Runner).Assembly.GetName().Name, typeof(Runner).FullName);
124      NotifyListeners(PluginManagerAction.Initializing, "All plugins");
125      if (remoteLoader != null) {
126        remoteRunner.LoadPlugins(remoteLoader.ActivePlugins);
127      } else if (LoadedPlugins != null && LoadedPlugins.Count > 0) {
128        remoteRunner.LoadPlugins(LoadedPlugins);
129      }
130      NotifyListeners(PluginManagerAction.Initialized, "All plugins");
131      return applicationDomain;
132    }
133
134
135    /// <summary>
136    /// Calculates a set of plugins that directly or transitively depend on the plugin given in the argument.
137    /// </summary>
138    /// <param name="pluginInfo"></param>
139    /// <returns>a list of plugins that are directly of transitively dependent.</returns>
140    public List<PluginInfo> GetDependentPlugins(PluginInfo pluginInfo) {
141      List<PluginInfo> mergedList = new List<PluginInfo>();
142      foreach (PluginInfo plugin in InstalledPlugins) {
143        if (plugin.Dependencies.Contains(pluginInfo)) {
144          if (!mergedList.Contains(plugin)) {
145            mergedList.Add(plugin);
146          }
147          // for each of the dependent plugins add the list of transitively dependent plugins
148          // make sure that only one entry for each plugin is added to the merged list
149          GetDependentPlugins(plugin).ForEach(delegate(PluginInfo dependentPlugin) {
150            if (!mergedList.Contains(dependentPlugin)) {
151              mergedList.Add(dependentPlugin);
152            }
153          });
154        }
155      }
156      return mergedList;
157    }
158
159    public void UnloadAllPlugins() {
160      AppDomain.Unload(pluginDomain);
161    }
162
163    public void LoadAllPlugins() {
164      Initialize();
165    }
166
167    public void OnDelete(PluginInfo pluginInfo) {
168      remoteLoader.OnDelete(pluginInfo);
169    }
170
171    public void OnInstall(PluginInfo pluginInfo) {
172      remoteLoader.OnInstall(pluginInfo);
173    }
174
175    public void OnPreUpdate(PluginInfo pluginInfo) {
176      remoteLoader.OnPreUpdate(pluginInfo);
177    }
178
179    public void OnPostUpdate(PluginInfo pluginInfo) {
180      remoteLoader.OnPostUpdate(pluginInfo);
181    }
182
183    private void NotifyListeners(PluginManagerAction action, string text) {
184      if (Action != null) {
185        Action(this, new PluginManagerActionEventArgs(text, action));
186      }
187    }
188  }
189}
Note: See TracBrowser for help on using the repository browser.