Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.PluginInfrastructure/Manager/PluginManager.cs @ 2724

Last change on this file since 2724 was 2615, checked in by gkronber, 15 years ago

Added infinite lease for PluginManager. #832 (Starting a new application or closing a running application after some time throws a RemotingException)

File size: 7.5 KB
RevLine 
[2]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;
[882]24using System.Security.Policy;
25using System.Reflection;
26using System.Diagnostics;
27using System.Security.Permissions;
28using System.Security;
[2488]29using System.Linq;
[2]30
[2481]31namespace HeuristicLab.PluginInfrastructure.Manager {
[2]32
33  // must extend MarshalByRefObject because of event passing between Loader and PluginManager (each in it's own AppDomain)
[1189]34  /// <summary>
35  /// Class to manage different plugins.
36  /// </summary>
[2504]37  internal sealed class PluginManager : MarshalByRefObject {
[1189]38    /// <summary>
39    /// Event handler for actions in the plugin manager.
40    /// </summary>
[2504]41    internal event EventHandler<PluginInfrastructureEventArgs> Action;
[2]42
43    private string pluginDir;
44
[2481]45    private List<PluginDescription> plugins;
[2513]46    /// <summary>
47    /// Gets all installed plugins.
48    /// </summary>
49    internal IEnumerable<PluginDescription> Plugins {
50      get { return plugins; }
51    }
[29]52
[2481]53    private List<ApplicationDescription> applications;
[1189]54    /// <summary>
55    /// Gets all installed applications.
56    /// </summary>
[2504]57    internal IEnumerable<ApplicationDescription> Applications {
[2481]58      get { return applications; }
[2]59    }
60
[2503]61    private object locker = new object();
62    private bool initialized;
63
[2504]64    internal PluginManager(string pluginDir) {
[2503]65      this.pluginDir = pluginDir;
66      plugins = new List<PluginDescription>();
67      applications = new List<ApplicationDescription>();
68      Reset();
69    }
70
[2504]71    internal void Reset() {
[2503]72      initialized = false;
73      if (plugins != null && plugins.Any(x => x.PluginState == PluginState.Loaded)) throw new InvalidOperationException("Reset() is not allowed while applications are active.");
74      plugins.Clear();
75      applications.Clear();
76    }
77
[1189]78    /// <summary>
[2481]79    /// Determines installed plugins and checks if all plugins are loadable.
[1189]80    /// </summary>
[2504]81    internal void DiscoverAndCheckPlugins() {
[2503]82      OnAction(new PluginInfrastructureEventArgs("Initializing", "PluginInfrastructure"));
[2]83      AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
84      setup.PrivateBinPath = pluginDir;
[2497]85      AppDomain pluginDomain = null;
86      try {
87        pluginDomain = AppDomain.CreateDomain("plugin domain", null, setup);
[2504]88        Type pluginValidatorType = typeof(PluginValidator);
89        PluginValidator remoteValidator = (PluginValidator)pluginDomain.CreateInstanceAndUnwrap(pluginValidatorType.Assembly.FullName, pluginValidatorType.FullName, true, BindingFlags.NonPublic | BindingFlags.Instance, null, null, null, null, null);
[2503]90        remoteValidator.PluginDir = pluginDir;
91        // forward all events from the remoteValidator to listeners
92        remoteValidator.PluginLoaded +=
93          delegate(object sender, PluginInfrastructureEventArgs e) {
94            OnAction(e);
95          };
96        // get list of plugins and applications from the validator
97        plugins.Clear(); applications.Clear();
98        plugins.AddRange(remoteValidator.Plugins);
99        applications.AddRange(remoteValidator.Applications);
100        OnAction(new PluginInfrastructureEventArgs("Initialized", "PluginInfrastructure"));
[2497]101      }
102      finally {
103        // discard the AppDomain that was used for plugin discovery
[2503]104        AppDomain.Unload(pluginDomain);
105        // unload all plugins
[2527]106        foreach (var pluginDescription in plugins.Where(x => x.PluginState == PluginState.Loaded))
[2503]107          pluginDescription.Unload();
108        initialized = true;
[2497]109      }
[2]110    }
111
[2481]112
[2]113    /// <summary>
[2592]114    /// Starts an application in a separate AppDomain.
115    /// Loads all enabled plugins and starts the application via an ApplicationManager instance activated in the new AppDomain.
[2]116    /// </summary>
117    /// <param name="appInfo">application to run</param>
[2504]118    internal void Run(ApplicationDescription appInfo) {
[2503]119      if (!initialized) throw new InvalidOperationException("PluginManager is not initialized. DiscoverAndCheckPlugins() must be called before Run()");
[2]120      // create a separate AppDomain for the application
[2488]121      // initialize the static ApplicationManager in the AppDomain
[2]122      // and remotely tell it to start the application
123
[2503]124      OnAction(new PluginInfrastructureEventArgs("Starting application", appInfo));
[766]125      AppDomain applicationDomain = null;
[241]126      try {
[2481]127        AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
128        setup.PrivateBinPath = pluginDir;
129        applicationDomain = AppDomain.CreateDomain(appInfo.Name, null, setup);
[2527]130        Type applicationManagerType = typeof(ApplicationManager);
131        ApplicationManager applicationManager =
132          (ApplicationManager)applicationDomain.CreateInstanceAndUnwrap(applicationManagerType.Assembly.FullName, applicationManagerType.FullName, true, BindingFlags.NonPublic | BindingFlags.Instance, null, null, null, null, null);
[2497]133        applicationManager.PluginLoaded += applicationManager_PluginLoaded;
[2503]134        applicationManager.PluginUnloaded += applicationManager_PluginUnloaded;
[2504]135        applicationManager.PrepareApplicationDomain(applications, plugins);
[2503]136        OnAction(new PluginInfrastructureEventArgs("Started application", appInfo));
[2488]137        applicationManager.Run(appInfo);
[766]138      }
139      finally {
[241]140        // make sure domain is unloaded in all cases
[2503]141        AppDomain.Unload(applicationDomain);
[241]142      }
[2]143    }
144
[2503]145    private void applicationManager_PluginUnloaded(object sender, PluginInfrastructureEventArgs e) {
146      // unload the matching plugin description (
[2497]147      PluginDescription desc = (PluginDescription)e.Entity;
[2503]148
149      // access to plugin descriptions has to be synchronized because multiple applications
150      // can be started or stopped at the same time
151      lock (locker) {
152        plugins.First(x => x.Equals(desc)).Unload();
[2497]153      }
[2503]154      OnAction(new PluginInfrastructureEventArgs(e.Action, e.Entity));
[2497]155    }
[766]156
[2503]157    private void applicationManager_PluginLoaded(object sender, PluginInfrastructureEventArgs e) {
158      // load the matching plugin description (
159      PluginDescription desc = (PluginDescription)e.Entity;
160      // access to plugin descriptions has to be synchronized because multiple applications
161      // can be started or stopped at the same time
162      lock (locker) {
163        plugins.First(x => x.Equals(desc)).Load();
164      }
165      OnAction(new PluginInfrastructureEventArgs(e.Action, e.Entity));
[2497]166    }
[882]167
[2503]168    private void OnAction(PluginInfrastructureEventArgs e) {
[766]169      if (Action != null) {
[2503]170        Action(this, e);
[2]171      }
172    }
[2615]173
174    // infinite lease time
175    /// <summary>
176    /// Initializes the life time service with infinite lease time.
177    /// </summary>
178    /// <returns><c>null</c>.</returns>
179    public override object InitializeLifetimeService() {
180      return null;
181    }
[2]182  }
183}
Note: See TracBrowser for help on using the repository browser.