// // Copyright (c) ZeroC, Inc. All rights reserved. // using System; using System.Collections.Generic; namespace Ice { public interface PropertiesAdminUpdateCallback { void updated(Dictionary changes); } public interface NativePropertiesAdmin { [Obsolete("This method is deprecated. Use addUpdateCallback(System.Action> callback) instead.")] void addUpdateCallback(PropertiesAdminUpdateCallback callback); [Obsolete("This method is deprecated. Use removeUpdateCallback(System.Action> callback) instead.")] void removeUpdateCallback(PropertiesAdminUpdateCallback callback); void addUpdateCallback(System.Action> callback); void removeUpdateCallback(System.Action> callback); } } namespace IceInternal { sealed class PropertiesAdminI : Ice.PropertiesAdminDisp_, Ice.NativePropertiesAdmin { internal PropertiesAdminI(Instance instance) { _properties = instance.initializationData().properties; _logger = instance.initializationData().logger; } public override string getProperty(string name, Ice.Current current) { return _properties.getProperty(name); } public override Dictionary getPropertiesForPrefix(string name, Ice.Current current) { return _properties.getPropertiesForPrefix(name); } public override void setProperties(Dictionary props, Ice.Current current) { lock(this) { Dictionary old = _properties.getPropertiesForPrefix(""); int traceLevel = _properties.getPropertyAsInt("Ice.Trace.Admin.Properties"); // // Compute the difference between the new property set and the existing property set: // // 1) Any properties in the new set that were not defined in the existing set. // // 2) Any properties that appear in both sets but with different values. // // 3) Any properties not present in the new set but present in the existing set. // In other words, the property has been removed. // Dictionary added = new Dictionary(); Dictionary changed = new Dictionary(); Dictionary removed = new Dictionary(); foreach(KeyValuePair e in props) { string key = e.Key; string value = e.Value; if(!old.ContainsKey(key)) { if(value.Length > 0) { // // This property is new. // added.Add(key, value); } } else { string v; if(!old.TryGetValue(key, out v) || !value.Equals(v)) { if(value.Length == 0) { // // This property was removed. // removed.Add(key, value); } else { // // This property has changed. // changed.Add(key, value); } } old.Remove(key); } } if(traceLevel > 0 && (added.Count > 0 || changed.Count > 0 || removed.Count > 0)) { System.Text.StringBuilder message = new System.Text.StringBuilder("Summary of property changes"); if(added.Count > 0) { message.Append("\nNew properties:"); foreach(KeyValuePair e in added) { message.Append("\n "); message.Append(e.Key); if(traceLevel > 1) { message.Append(" = "); message.Append(e.Value); } } } if(changed.Count > 0) { message.Append("\nChanged properties:"); foreach(KeyValuePair e in changed) { message.Append("\n "); message.Append(e.Key); if(traceLevel > 1) { message.Append(" = "); message.Append(e.Value); message.Append(" (old value = "); message.Append(_properties.getProperty(e.Key)); message.Append(")"); } } } if(removed.Count > 0) { message.Append("\nRemoved properties:"); foreach(KeyValuePair e in removed) { message.Append("\n "); message.Append(e.Key); } } _logger.trace(_traceCategory, message.ToString()); } // // Update the property set. // foreach(KeyValuePair e in added) { _properties.setProperty(e.Key, e.Value); } foreach(KeyValuePair e in changed) { _properties.setProperty(e.Key, e.Value); } foreach(KeyValuePair e in removed) { _properties.setProperty(e.Key, ""); } if(_deprecatedUpdateCallbacks.Count > 0 || _updateCallbacks.Count > 0) { Dictionary changes = new Dictionary(added); foreach(KeyValuePair e in changed) { changes.Add(e.Key, e.Value); } foreach(KeyValuePair e in removed) { changes.Add(e.Key, e.Value); } // Copy callbacks to allow callbacks to update callbacks foreach(var callback in new List(_deprecatedUpdateCallbacks)) { try { callback.updated(changes); } catch(Exception ex) { if(_properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1) { _logger.warning("properties admin update callback raised unexpected exception:\n" + ex); } } } // Copy callbacks to allow callbacks to update callbacks foreach(var callback in new List>>(_updateCallbacks)) { try { callback(changes); } catch(Exception ex) { if(_properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1) { _logger.warning("properties admin update callback raised unexpected exception:\n" + ex); } } } } } } public void addUpdateCallback(Ice.PropertiesAdminUpdateCallback cb) { lock(this) { _deprecatedUpdateCallbacks.Add(cb); } } public void removeUpdateCallback(Ice.PropertiesAdminUpdateCallback cb) { lock(this) { _deprecatedUpdateCallbacks.Remove(cb); } } public void addUpdateCallback(System.Action> cb) { lock(this) { _updateCallbacks.Add(cb); } } public void removeUpdateCallback(System.Action> cb) { lock(this) { _updateCallbacks.Remove(cb); } } private readonly Ice.Properties _properties; private readonly Ice.Logger _logger; private List _deprecatedUpdateCallbacks = new List(); private List>> _updateCallbacks = new List>>(); private static readonly string _traceCategory = "Admin.Properties"; } }