mirror of
https://github.com/xcp-ng/xenadmin.git
synced 2024-12-22 08:26:03 +01:00
6e4c39ac96
Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
244 lines
8.3 KiB
C#
244 lines
8.3 KiB
C#
/* 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 Citrix.XenCenter;
|
|
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<PluginDescriptor> _plugins = new List<PluginDescriptor>();
|
|
private static readonly string PLUGIN_FOLDER = Path.Combine(Program.AssemblyDir, "Plugins");
|
|
|
|
private const string ROOT_ELEMENT_NAME = "XenCenterPlugin";
|
|
|
|
public event Action PluginsChanged;
|
|
|
|
/// <summary>
|
|
/// Gets the plugins loaded from the Plugin directory.
|
|
/// </summary>
|
|
/// <value>The plugins.</value>
|
|
public ReadOnlyCollection<PluginDescriptor> Plugins
|
|
{
|
|
get
|
|
{
|
|
return new ReadOnlyCollection<PluginDescriptor>(_plugins);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all features from all plugins of the specified type that match the specified predicate.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the features required.</typeparam>
|
|
/// <param name="match">The predicate that the features must match.</param>
|
|
/// <returns>The features.</returns>
|
|
public IEnumerable<T> GetAllFeatures<T>(Predicate<T> 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether plugins functionality is enabled. This is driven by whether the Plugins folder exists.
|
|
/// </summary>
|
|
/// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
|
|
public bool Enabled
|
|
{
|
|
get { return !Registry.DisablePlugins; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating the number of plugins the user has enabled (ticked on the GUI)
|
|
/// </summary>
|
|
public int EnabledPluginsCount
|
|
{
|
|
get { return (from PluginDescriptor plugin in _plugins where plugin.Enabled select plugin).Count(); }
|
|
}
|
|
|
|
public void OnPluginsChanged()
|
|
{
|
|
if (PluginsChanged != null)
|
|
PluginsChanged();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads the plugins from the default Plugins folder.
|
|
/// </summary>
|
|
public void LoadPlugins()
|
|
{
|
|
LoadPlugins(PLUGIN_FOLDER);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads the plugins from the specified folder.
|
|
/// </summary>
|
|
/// <param name="folder">The folder.</param>
|
|
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
|
|
}
|
|
}
|