/* Copyright (c) Citrix Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Xml; using XenAPI; using XenCenterLib; using XenAdmin.Core; namespace XenAdmin.Plugins { public class PluginManager : IDisposable { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private readonly List _plugins = new List(); private static readonly string PLUGIN_FOLDER = Path.Combine(Program.AssemblyDir, "Plugins"); private const string ROOT_ELEMENT_NAME = "XenCenterPlugin"; public event Action PluginsChanged; /// /// Gets the plugins loaded from the Plugin directory. /// /// The plugins. public ReadOnlyCollection Plugins { get { return new ReadOnlyCollection(_plugins); } } /// /// Gets all features from all plugins of the specified type that match the specified predicate. /// /// The type of the features required. /// The predicate that the features must match. /// The features. public IEnumerable GetAllFeatures(Predicate match) where T: Feature { Util.ThrowIfParameterNull(match, "match"); foreach (PluginDescriptor plugin in Plugins) { foreach (Feature feature in plugin.Features) { T f = feature as T; if (f != null && match(f)) { yield return f; } } } } /// /// Gets a value indicating whether plugins functionality is enabled. This is driven by whether the Plugins folder exists. /// /// true if enabled; otherwise, false. public bool Enabled { get { return !Registry.DisablePlugins; } } /// /// Gets a value indicating the number of plugins the user has enabled (ticked on the GUI) /// public int EnabledPluginsCount { get { return (from PluginDescriptor plugin in _plugins where plugin.Enabled select plugin).Count(); } } public void OnPluginsChanged() { if (PluginsChanged != null) PluginsChanged(); } /// /// Loads the plugins from the default Plugins folder. /// public void LoadPlugins() { LoadPlugins(PLUGIN_FOLDER); } /// /// Loads the plugins from the specified folder. /// /// The folder. public void LoadPlugins(string folder) { if (Enabled) { // catch all exceptions, the most likely cause of errors is user mistakes with plugin creation. // we must not let this kill XenCenter try { //CA-71469: check whether the plugins folder exists if (!Directory.Exists(folder)) { log.InfoFormat("Plugin directory {0} was not found.", folder); return; } // Look for plugins in {Application Working Dir}\Plugins foreach (string vendor in Directory.GetDirectories(folder)) { foreach (string pluginDir in Directory.GetDirectories(vendor)) { try { string plugin = Path.GetFileName(pluginDir); string org = Path.GetFileName(vendor); ProcessPlugin(Path.Combine(pluginDir, string.Format("{0}.xcplugin.xml", plugin)), plugin, org); } catch (Exception e) { log.Error(string.Format("Failed to load plugin xml for file {0}.xcplugin.xml", Path.GetFileName(pluginDir)), e); } } } } catch (Exception ex) { log.Error("Error loading plugins.", ex); } OnPluginsChanged(); } } private void ProcessPlugin(string file, string plugin, string org) { XmlDocument pluginXml = new XmlDocument(); pluginXml.XmlResolver = new BasicXMLResolver(); using (StreamReader sr = new StreamReader(file)) { pluginXml.LoadXml(sr.ReadToEnd()); } foreach (XmlNode node in pluginXml.GetElementsByTagName(ROOT_ELEMENT_NAME)) { _plugins.Add(new PluginDescriptor(node, plugin, org)); } } private void ClearPlugins() { foreach (PluginDescriptor plugin in _plugins) { plugin.Dispose(); } _plugins.Clear(); OnPluginsChanged(); } public void ReloadPlugins() { ClearPlugins(); LoadPlugins(); } public void DisposeURLs(IXenObject xenObject) { foreach (PluginDescriptor plugin in _plugins) { plugin.DisposeURLs(xenObject); } } public void SetSelectedXenObject(IXenObject xenObject) { foreach (PluginDescriptor plugin in Plugins) { foreach (Feature feature in plugin.Features) { TabPageFeature tabPageFeature = feature as TabPageFeature; if (tabPageFeature != null) { tabPageFeature.SelectedXenObject = xenObject; } } } } protected virtual void Dispose(bool disposing) { if (disposing) { ClearPlugins(); } } #region IDisposable Members public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion } }