/* 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; using System.Collections.Generic; using System.IO; using System.Xml; using XenAPI; using XenCenterLib; using XenAdmin.Network; namespace XenAdmin.ServerDBs { /// /// A class which represents the XenServer status report Xml document. For use by . /// public partial class Db { private readonly TableDictionary _tables; private static readonly Dictionary AllRelations = Relation.GetRelations(); public Db(IXenConnection connection, string url) { _tables = new TableDictionary(this); using (StreamReader stream = url.StartsWith("http") ? new StreamReader(HTTPHelper.GET(new Uri(url), connection, true)) : new StreamReader(url)) { StatusReportXmlDocReader reader = new StatusReportXmlDocReader(); XmlDocument doc = new XmlDocument(); doc.XmlResolver = new BasicXMLResolver(); doc.Load(stream); reader.PopulateDbFromXml(this, doc); } UpdateRelations(); _tables.Changed += TablesChanged; } public void Dispose() { Dispose(true); } private bool disposed; private void Dispose(bool disposing) { if(!disposed) { if(disposing) { _tables.Changed -= TablesChanged; _tables.Clear(); disposed = true; } } } private void TablesChanged(object sender, EventArgs e) { _tables.Changed -= TablesChanged; UpdateRelations(); _tables.Changed += TablesChanged; } public TableDictionary Tables { get { return _tables; } } public object GetValue(string clazz, string opaque_ref, string field) { return Tables[clazz].Rows[opaque_ref].Props[field].XapiObjectValue; } public string ObjectWithFieldValue(string clazz, string field, string value) { foreach (KeyValuePair row in Tables[clazz].Rows) { if (row.Value.Props[field].XapiObjectValue.ToString() == value) { return row.Key; } } return Helper.NullOpaqueRef; } private void ClearRelations() { foreach (Table table in Tables.Values) { foreach (Db.Row row in table.Rows.Values) { Relation[] relations; if (AllRelations.TryGetValue(table.XapiType, out relations)) { foreach (Relation relation in relations) { row.Props[relation.field] = new Prop(row, relation.field, new string[0]); } } } } } private void UpdateRelations() { // clear all existing relation ClearRelations(); foreach (PropInfo propInfo in GetAllPropsWithOpaqueRefValue()) { foreach (KeyValuePair relationsPair in AllRelations) { foreach (Relation relation in relationsPair.Value) { if (relation.manyField.ToLower() == propInfo.Prop.Name.ToLower() && propInfo.Table.Name.ToLower() == relation.manyType.ToLower()) { // string of the Proxy_ from the front. string relTypeName = relationsPair.Key.Name.Substring(6); if (Tables[relTypeName].Rows.ContainsKey(propInfo.PropValue)) { List list = new List((string[])Tables[relTypeName].Rows[propInfo.PropValue].Props[relation.field].XapiObjectValue); list.Add(propInfo.RowKey); Tables[relTypeName].Rows[propInfo.PropValue].Props[relation.field].XapiObjectValue = list.ToArray(); } } } } } } private IEnumerable GetAllPropsWithOpaqueRefValue() { foreach (Table table in Tables.Values) { foreach (KeyValuePair row in table.Rows) { foreach (Prop prop in row.Value.Props.Values) { string propOpaqueRef = prop.XapiObjectValue as string; if (propOpaqueRef != null && propOpaqueRef.StartsWith("OpaqueRef:") && propOpaqueRef != "OpaqueRef:NULL") { yield return new PropInfo(table, row.Key, row.Value, prop, propOpaqueRef); } } } } } private class PropInfo { public readonly Table Table; public readonly string RowKey; public readonly Row Row; public readonly Prop Prop; public readonly string PropValue; public PropInfo(Table table, string rowKey, Row row, Prop prop, string propValue) { Table = table; RowKey = rowKey; Row = row; Prop = prop; PropValue = propValue; } } /// /// A class which represents a table in the XenServer status report Xml document. For use by . /// public class Table { private readonly string _name; private readonly Type _xapiType; private readonly RowDictionary _rows; private readonly Db _db; public event EventHandler Changed; internal virtual void OnChanged(EventArgs e) { EventHandler handler = Changed; if (handler != null) { handler(this, e); } } /// /// Initializes a new instance of the class. /// /// The name of the table. /// The to which this is attached. public Table(string name, Db db) { Util.ThrowIfStringParameterNullOrEmpty(name, "name"); Util.ThrowIfParameterNull(db, "db"); _rows = new RowDictionary(this); _name = name.ToLower(); _db = db; TypeCache.TryGetProxyType(name, out _xapiType); _rows.Changed += delegate { OnChanged(EventArgs.Empty); }; } public RowDictionary Rows { get { return _rows; } } /// /// Gets the name of this . /// /// The name. public string Name { get { return _name; } } /// /// Gets the XAPI type that this represents. /// /// The XAPI type that this represents. public Type XapiType { get { return _xapiType; } } } /// /// Represents a row entity in the parent . /// public class Row { private readonly PropDictionary _props; private readonly Table _table; /// /// Initializes a new instance of the class. /// /// The to which this belongs. public Row(Table table) { Util.ThrowIfParameterNull(table, "table"); _table = table; _props = new PropDictionary(this); _props.Changed += delegate { _table.OnChanged(EventArgs.Empty); }; } public PropDictionary Props { get { return _props; } } /// /// Gets the which this belongs to. /// /// The table. public Table Table { get { return _table; } } public Row CopyOf() { Row r = new Row(_table); foreach (KeyValuePair p in _props) { r.Props[p.Key] = p.Value.CopyOf(this); } return r; } public void PopulateFrom(Hashtable h) { foreach (string key in h.Keys) { this.Props[key] = new Prop(this, key, h[key]); } } } /// /// A class representing a property of a within the XenServer status report XML document. /// public class Prop { private readonly Row _row; private Type _xapiType; private readonly string _name; private object _xapiValue; /// /// Initializes a new instance of the class. /// /// The row to which this belongs. /// The name of this . /// The string value of this . public Prop(Row row, string name, string stringValue) { Util.ThrowIfParameterNull(row, "row"); Util.ThrowIfStringParameterNullOrEmpty(name, "name"); Util.ThrowIfParameterNull(stringValue, "stringValue"); _row = row; _name = name; _xapiType = TypeCache.GetFieldType(_row.Table.Name, _name); _xapiValue = Parser.Parse(XapiType, stringValue); } public Prop(Row row, string name, object xapiValue) { Util.ThrowIfParameterNull(row, "row"); Util.ThrowIfStringParameterNullOrEmpty(name, "name"); _row = row; _name = name; _xapiType = TypeCache.GetFieldType(_row.Table.Name, _name); _xapiValue = xapiValue ?? Parser.Parse(XapiType, ""); } /// /// Gets the name of this . /// /// The name. public string Name { get { return _name; } } /// /// Gets the XAPI type which this represents. /// /// The XAPI type which this represents. public Type XapiType { get { return _xapiType; } } /// /// Gets or sets the XAPI value which of the XAPI type which this represents. /// /// The xapi object value. public object XapiObjectValue { get { return _xapiValue; } set { Util.ThrowIfParameterNull(value, "value"); _xapiType = value.GetType(); _xapiValue = value; _row.Table.OnChanged(EventArgs.Empty); } } public Prop CopyOf(Row r) { return new Prop(r, _name, _xapiValue); } } } }