/* 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<StorageLinkSystem> _systems = new List<StorageLinkSystem>(); private readonly List<StorageLinkPool> _pools = new List<StorageLinkPool>(); private readonly List<StorageLinkAdapter> _adapters = new List<StorageLinkAdapter>(); private readonly List<StorageLinkVolume> _volumes = new List<StorageLinkVolume>(); private readonly List<StorageLinkRepository> _srs = new List<StorageLinkRepository>(); private StorageLinkServer _server; public StorageLinkServer Server { get { lock (_syncObject) { return _server; } } private set { lock (_syncObject) { _server = value; } } } /// <summary> /// Occurs when the cache changes or any property of any item in the cache changes. /// </summary> public event EventHandler Changed; public ReadOnlyCollection<StorageLinkSystem> StorageSystems { get { lock (_syncObject) { return new ReadOnlyCollection<StorageLinkSystem>(new List<StorageLinkSystem>(_systems)); } } } public ReadOnlyCollection<StorageLinkPool> StoragePools { get { lock (_syncObject) { return new ReadOnlyCollection<StorageLinkPool>(new List<StorageLinkPool>(_pools)); } } } public ReadOnlyCollection<StorageLinkAdapter> StorageAdapters { get { lock (_syncObject) { return new ReadOnlyCollection<StorageLinkAdapter>(new List<StorageLinkAdapter>(_adapters)); } } } public ReadOnlyCollection<StorageLinkVolume> StorageVolumes { get { lock (_syncObject) { return new ReadOnlyCollection<StorageLinkVolume>(new List<StorageLinkVolume>(_volumes)); } } } public ReadOnlyCollection<StorageLinkRepository> StorageRespositories { get { lock (_syncObject) { return new ReadOnlyCollection<StorageLinkRepository>(new List<StorageLinkRepository>(_srs)); } } } public IEnumerable<IXenObject> XenSearchableObjects(IEnumerable<IXenConnection> 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<StorageLinkRepository> 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<StorageLinkPool> pools, List<StorageLinkVolume> 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<StorageLinkSystem> systems, List<StorageLinkPool> pools, List<StorageLinkAdapter> adapters, List<StorageLinkVolume> volumes, List<StorageLinkRepository> 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<T>(List<T> to, List<T> from) where T : StorageLinkObject<T> { return UpdateItems<T>(to, from, t => true); } private static bool UpdateItems<T>(List<T> to, List<T> from, Predicate<T> match) where T : StorageLinkObject<T> { 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<T> 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<T>(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; } } }