Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 2636 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
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;
30
31namespace HeuristicLab.PluginInfrastructure.Manager {
32
33  // must extend MarshalByRefObject because of event passing between Loader and PluginManager (each in it's own AppDomain)
34  /// <summary>
35  /// Class to manage different plugins.
36  /// </summary>
37  internal sealed class PluginManager : MarshalByRefObject {
38    /// <summary>
39    /// Event handler for actions in the plugin manager.
40    /// </summary>
41    internal event EventHandler<PluginInfrastructureEventArgs> Action;
42
43    private string pluginDir;
44
45    private List<PluginDescription> plugins;
46    /// <summary>
47    /// Gets all installed plugins.
48    /// </summary>
49    internal IEnumerable<PluginDescription> Plugins {
50      get { return plugins; }
51    }
52
53    private List<ApplicationDescription> applications;
54    /// <summary>
55    /// Gets all installed applications.
56    /// </summary>
57    internal IEnumerable<ApplicationDescription> Applications {
58      get { return applications; }
59    }
60
61    private object locker = new object();
62    private bool initialized;
63
64    internal PluginManager(string pluginDir) {
65      this.pluginDir = pluginDir;
66      plugins = new List<PluginDescription>();
67      applications = new List<ApplicationDescription>();
68      Reset();
69    }
70
71    internal void Reset() {
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
78    /// <summary>
79    /// Determines installed plugins and checks if all plugins are loadable.
80    /// </summary>
81    internal void DiscoverAndCheckPlugins() {
82      OnAction(new PluginInfrastructureEventArgs("Initializing", "PluginInfrastructure"));
83      AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
84      setup.PrivateBinPath = pluginDir;
85      AppDomain pluginDomain = null;
86      try {
87        pluginDomain = AppDomain.CreateDomain("plugin domain", null, setup);
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);
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"));
101      }
102      finally {
103        // discard the AppDomain that was used for plugin discovery
104        AppDomain.Unload(pluginDomain);
105        // unload all plugins
106        foreach (var pluginDescription in plugins.Where(x => x.PluginState == PluginState.Loaded))
107          pluginDescription.Unload();
108        initialized = true;
109      }
110    }
111
112
113    /// <summary>
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.
116    /// </summary>
117    /// <param name="appInfo">application to run</param>
118    internal void Run(ApplicationDescription appInfo) {
119      if (!initialized) throw new InvalidOperationException("PluginManager is not initialized. DiscoverAndCheckPlugins() must be called before Run()");
120      // create a separate AppDomain for the application
121      // initialize the static ApplicationManager in the AppDomain
122      // and remotely tell it to start the application
123
124      OnAction(new PluginInfrastructureEventArgs("Starting application", appInfo));
125      AppDomain applicationDomain = null;
126      try {
127        AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
128        setup.PrivateBinPath = pluginDir;
129        applicationDomain = AppDomain.CreateDomain(appInfo.Name, null, setup);
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);
133        applicationManager.PluginLoaded += applicationManager_PluginLoaded;
134        applicationManager.PluginUnloaded += applicationManager_PluginUnloaded;
135        applicationManager.PrepareApplicationDomain(applications, plugins);
136        OnAction(new PluginInfrastructureEventArgs("Started application", appInfo));
137        applicationManager.Run(appInfo);
138      }
139      finally {
140        // make sure domain is unloaded in all cases
141        AppDomain.Unload(applicationDomain);
142      }
143    }
144
145    private void applicationManager_PluginUnloaded(object sender, PluginInfrastructureEventArgs e) {
146      // unload the matching plugin description (
147      PluginDescription desc = (PluginDescription)e.Entity;
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();
153      }
154      OnAction(new PluginInfrastructureEventArgs(e.Action, e.Entity));
155    }
156
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));
166    }
167
168    private void OnAction(PluginInfrastructureEventArgs e) {
169      if (Action != null) {
170        Action(this, e);
171      }
172    }
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    }
182  }
183}
Note: See TracBrowser for help on using the repository browser.