/* 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 XenAdmin.Network;
using XenAPI;
using XenAdmin.Core;
using System.Xml;
namespace XenAdmin.CustomFields
{
///
/// Provide custom fields management support for VMs. The master list of custom fields will be
/// maintained in the pool class using the same conventions as the tags implementation (see
/// XenAdmin.XenSearch.Tags). When persisting the label-value pairs in the VMs, the
/// following key/value convention will be used:
/// "XenCenter.CustomFields.foo1" value
/// "XenCenter.CustomFields.foo2" value
///
public class CustomFieldsManager
{
#region These functions deal with caching the list of custom fields
private static readonly CustomFieldsCache customFieldsCache = new CustomFieldsCache();
private const String CUSTOM_FIELD_DELIM = ".";
public const String CUSTOM_FIELD_BASE_KEY = "XenCenter.CustomFields";
public const String CUSTOM_FIELD = "CustomField:";
public static event EventHandler CustomFieldsChanged;
static CustomFieldsManager()
{
OtherConfigAndTagsWatcher.GuiConfigChanged += OtherConfigAndTagsWatcher_GuiConfigChanged;
}
private static void OtherConfigAndTagsWatcher_GuiConfigChanged(object sender, EventArgs e)
{
InvokeHelper.AssertOnEventThread();
customFieldsCache.RecalculateCustomFields();
OnCustomFieldsChanged(EventArgs.Empty);
}
private static void OnCustomFieldsChanged(EventArgs e)
{
EventHandler handler = CustomFieldsChanged;
if (handler != null)
{
handler(null, e);
}
}
#endregion
#region These functions deal with custom field definitions on the pool object
public static List GetCustomFields()
{
return customFieldsCache.GetCustomFields();
}
public static List GetCustomFields(IXenConnection connection)
{
return customFieldsCache.GetCustomFields(connection);
}
/// The CustomFieldDefinition with the given name, or null if none is found.
public static CustomFieldDefinition GetCustomFieldDefinition(string name)
{
foreach (CustomFieldDefinition d in GetCustomFields())
{
if (d.Name == name)
return d;
}
return null;
}
public static void RemoveCustomField(Session session, IXenConnection connection, CustomFieldDefinition definition)
{
List customFields = customFieldsCache.GetCustomFields(connection);
if (customFields.Remove(definition))
{
SaveCustomFields(session, connection, customFields);
// Remove from all Objects
RemoveCustomFieldsFrom(session, connection.Cache.VMs, definition);
RemoveCustomFieldsFrom(session, connection.Cache.Hosts, definition);
RemoveCustomFieldsFrom(session, connection.Cache.Pools, definition);
RemoveCustomFieldsFrom(session, connection.Cache.SRs, definition);
}
}
public static void AddCustomField(Session session, IXenConnection connection, CustomFieldDefinition customField)
{
List customFields = customFieldsCache.GetCustomFields(connection);
if (!customFields.Contains(customField))
{
customFields.Add(customField);
SaveCustomFields(session, connection, customFields);
}
}
private static String GetCustomFieldDefinitionXML(List customFieldDefinitions)
{
XmlDocument doc = new XmlDocument();
XmlNode parentNode = doc.CreateElement("CustomFieldDefinitions");
doc.AppendChild(parentNode);
foreach (CustomFieldDefinition customFieldDefinition in customFieldDefinitions)
{
parentNode.AppendChild(customFieldDefinition.ToXmlNode(doc));
}
return doc.OuterXml;
}
#endregion
#region These functions deal with the custom fields themselves
public static string GetCustomFieldKey(CustomFieldDefinition customFieldDefinition)
{
return CUSTOM_FIELD_BASE_KEY + CUSTOM_FIELD_DELIM + customFieldDefinition.Name;
}
private static void RemoveCustomFieldsFrom(Session session, IEnumerable os, CustomFieldDefinition customFieldDefinition)
{
InvokeHelper.AssertOffEventThread();
string customFieldKey = GetCustomFieldKey(customFieldDefinition);
foreach (IXenObject o in os)
{
Helpers.RemoveFromOtherConfig(session, o, customFieldKey);
}
}
private static void SaveCustomFields(Session session, IXenConnection connection, List customFields)
{
Pool pool = Helpers.GetPoolOfOne(connection);
if (pool != null)
{
String customFieldXML = GetCustomFieldDefinitionXML(customFields);
Helpers.SetGuiConfig(session, pool, CUSTOM_FIELD_BASE_KEY, customFieldXML);
}
}
public static List CustomFieldValues(IXenObject o)
{
//Program.AssertOnEventThread();
List customFields = new List();
Dictionary otherConfig = GetOtherConfigCopy(o);
if (otherConfig != null)
{
foreach (CustomFieldDefinition customFieldDefinition in customFieldsCache.GetCustomFields(o.Connection))
{
string customFieldKey = GetCustomFieldKey(customFieldDefinition);
if (!otherConfig.ContainsKey(customFieldKey) || otherConfig[customFieldKey] == String.Empty)
{
continue;
}
object value = ParseValue(customFieldDefinition.Type, otherConfig[customFieldKey]);
if (value != null)
{
customFields.Add(new CustomField(customFieldDefinition, value));
}
}
}
return customFields;
}
// The same as CustomFieldValues(), but with each custom field unwound into an array
public static List