/* 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.ComponentModel; using XenAPI; namespace XenAdmin.Network.StorageLink { public class StorageLinkCache { private readonly object _syncObject = new object(); private readonly List _systems = new List(); private readonly List _pools = new List(); private readonly List _adapters = new List(); private readonly List _volumes = new List(); private readonly List _srs = new List(); private StorageLinkServer _server; public StorageLinkServer Server { get { lock (_syncObject) { return _server; } } private set { lock (_syncObject) { _server = value; } } } /// /// Occurs when the cache changes or any property of any item in the cache changes. /// public event EventHandler Changed; public ReadOnlyCollection StorageSystems { get { lock (_syncObject) { return new ReadOnlyCollection(new List(_systems)); } } } public ReadOnlyCollection StoragePools { get { lock (_syncObject) { return new ReadOnlyCollection(new List(_pools)); } } } public ReadOnlyCollection StorageAdapters { get { lock (_syncObject) { return new ReadOnlyCollection(new List(_adapters)); } } } public ReadOnlyCollection StorageVolumes { get { lock (_syncObject) { return new ReadOnlyCollection(new List(_volumes)); } } } public ReadOnlyCollection StorageRespositories { get { lock (_syncObject) { return new ReadOnlyCollection(new List(_srs)); } } } public IEnumerable XenSearchableObjects(IEnumerable connections) { StorageLinkServer server = Server; if (server != null) { yield return server; if (StorageSystems.Count == 0) { yield break; } foreach (StorageLinkSystem system in StorageSystems) { yield return system; } foreach (StorageLinkPool pool in StoragePools) { // only return top level storage-pools if (pool.Parent == null) { yield return pool; } } foreach (StorageLinkRepository repo in StorageRespositories) { // only display it if it belongs to a managed server. StorageLink is to be changed so that it won't listen to // xapi events telling about an SR being forgotten (for xapi performance reasons.) if (repo.SR(connections) != null) { yield return repo; } } } } public void Update(string hostGroupId, List repositories) { Util.ThrowIfStringParameterNullOrEmpty(hostGroupId, "hostGroupId"); Util.ThrowIfParameterNull(repositories, "repositories"); bool changed; lock (_syncObject) { changed = UpdateItems(_srs, repositories, r => r.HostGroupId == hostGroupId); } if (changed) { OnChanged(EventArgs.Empty); } } public void Update(string storageSystemId, List pools, List volumes) { Util.ThrowIfParameterNull(pools, "pools"); Util.ThrowIfParameterNull(volumes, "volumes"); bool changed; lock (_syncObject) { changed = UpdateItems(_pools, pools, p => p.StorageLinkSystemId == storageSystemId); changed |= UpdateItems(_volumes, volumes, v => v.StorageLinkSystemId == storageSystemId); } if (changed) { OnChanged(EventArgs.Empty); } } public void Update(StorageLinkServer server, List systems, List pools, List adapters, List volumes, List srs) { Util.ThrowIfParameterNull(systems, "systems"); Util.ThrowIfParameterNull(pools, "pools"); Util.ThrowIfParameterNull(adapters, "adapters"); Util.ThrowIfParameterNull(volumes, "volumes"); Util.ThrowIfParameterNull(srs, "srs"); bool changed = false; lock (_syncObject) { if (Server == null || server == null) { changed = Server != server; Server = server; } else { PropertyChangedEventHandler handler = (s, e) => changed = true; Server.PropertyChanged += handler; Server.UpdateFrom(server); Server.PropertyChanged -= handler; } changed |= UpdateItems(_systems, systems); changed |= UpdateItems(_pools, pools); changed |= UpdateItems(_adapters, adapters); changed |= UpdateItems(_volumes, volumes); changed |= UpdateItems(_srs, srs); } if (changed) { OnChanged(EventArgs.Empty); } } private static bool UpdateItems(List to, List from) where T : StorageLinkObject { return UpdateItems(to, from, t => true); } private static bool UpdateItems(List to, List from, Predicate match) where T : StorageLinkObject { bool changed = false; foreach (T existingItem in to) { T newItem = from.Find(o => o.Equals(existingItem)); if (newItem != null) { PropertyChangedEventHandler handler = null; if (!changed) { handler = (s, e) => changed = true; existingItem.PropertyChanged += handler; } existingItem.UpdateFrom(newItem); if (handler != null) { existingItem.PropertyChanged -= handler; } } } changed |= to.RemoveAll(o => match(o) && !from.Contains(o)) > 0; List newItems = from.FindAll(s => !to.Contains(s)); changed |= newItems.Count > 0; to.AddRange(newItems); return changed; } protected virtual void OnChanged(EventArgs e) { EventHandler handler = Changed; if (handler != null) { handler(this, e); } } public T Resolve(string opaque_ref) where T : class { foreach (System.Collections.IEnumerable enumerable in new System.Collections.IEnumerable[] { StoragePools, StorageVolumes, StorageAdapters, StorageRespositories, StorageSystems }) { foreach (IStorageLinkObject x in enumerable) { if (!(x is T)) { break; } if (x.opaque_ref == opaque_ref) { return x as T; } } } return null; } } }