1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 using System;
6 using System.Collections.Generic;
7 
8 namespace Ice
9 {
10 
11 public interface PropertiesAdminUpdateCallback
12 {
updated(Dictionary<string, string> changes)13     void updated(Dictionary<string, string> changes);
14 }
15 
16 public interface NativePropertiesAdmin
17 {
18     [Obsolete("This method is deprecated. Use addUpdateCallback(System.Action<Dictionary<string, string>> callback) instead.")]
addUpdateCallback(PropertiesAdminUpdateCallback callback)19     void addUpdateCallback(PropertiesAdminUpdateCallback callback);
20 
21     [Obsolete("This method is deprecated. Use removeUpdateCallback(System.Action<Dictionary<string, string>> callback) instead.")]
removeUpdateCallback(PropertiesAdminUpdateCallback callback)22     void removeUpdateCallback(PropertiesAdminUpdateCallback callback);
23 
addUpdateCallback(System.Action<Dictionary<string, string>> callback)24     void addUpdateCallback(System.Action<Dictionary<string, string>> callback);
25 
removeUpdateCallback(System.Action<Dictionary<string, string>> callback)26     void removeUpdateCallback(System.Action<Dictionary<string, string>> callback);
27 }
28 
29 }
30 
31 namespace IceInternal
32 {
33     sealed class PropertiesAdminI : Ice.PropertiesAdminDisp_, Ice.NativePropertiesAdmin
34     {
PropertiesAdminI(Instance instance)35         internal PropertiesAdminI(Instance instance)
36         {
37             _properties = instance.initializationData().properties;
38             _logger = instance.initializationData().logger;
39         }
40 
41         public override string
getProperty(string name, Ice.Current current)42         getProperty(string name, Ice.Current current)
43         {
44             return _properties.getProperty(name);
45         }
46 
47         public override Dictionary<string, string>
getPropertiesForPrefix(string name, Ice.Current current)48         getPropertiesForPrefix(string name, Ice.Current current)
49         {
50             return _properties.getPropertiesForPrefix(name);
51         }
52 
53         public override void
setProperties(Dictionary<string, string> props, Ice.Current current)54         setProperties(Dictionary<string, string> props, Ice.Current current)
55         {
56             lock(this)
57             {
58                 Dictionary<string, string> old = _properties.getPropertiesForPrefix("");
59                 int traceLevel = _properties.getPropertyAsInt("Ice.Trace.Admin.Properties");
60 
61                 //
62                 // Compute the difference between the new property set and the existing property set:
63                 //
64                 // 1) Any properties in the new set that were not defined in the existing set.
65                 //
66                 // 2) Any properties that appear in both sets but with different values.
67                 //
68                 // 3) Any properties not present in the new set but present in the existing set.
69                 //    In other words, the property has been removed.
70                 //
71                 Dictionary<string, string> added = new Dictionary<string, string>();
72                 Dictionary<string, string> changed = new Dictionary<string, string>();
73                 Dictionary<string, string> removed = new Dictionary<string, string>();
74                 foreach(KeyValuePair<string, string> e in props)
75                 {
76                     string key = e.Key;
77                     string value = e.Value;
78                     if(!old.ContainsKey(key))
79                     {
80                         if(value.Length > 0)
81                         {
82                             //
83                             // This property is new.
84                             //
85                             added.Add(key, value);
86                         }
87                     }
88                     else
89                     {
90                         string v;
91                         if(!old.TryGetValue(key, out v) || !value.Equals(v))
92                         {
93                             if(value.Length == 0)
94                             {
95                                 //
96                                 // This property was removed.
97                                 //
98                                 removed.Add(key, value);
99                             }
100                             else
101                             {
102                                 //
103                                 // This property has changed.
104                                 //
105                                 changed.Add(key, value);
106                             }
107                         }
108 
109                         old.Remove(key);
110                     }
111                 }
112 
113                 if(traceLevel > 0 && (added.Count > 0 || changed.Count > 0 || removed.Count > 0))
114                 {
115                     System.Text.StringBuilder message = new System.Text.StringBuilder("Summary of property changes");
116 
117                     if(added.Count > 0)
118                     {
119                         message.Append("\nNew properties:");
120                         foreach(KeyValuePair<string, string> e in added)
121                         {
122                             message.Append("\n  ");
123                             message.Append(e.Key);
124                             if(traceLevel > 1)
125                             {
126                                 message.Append(" = ");
127                                 message.Append(e.Value);
128                             }
129                         }
130                     }
131 
132                     if(changed.Count > 0)
133                     {
134                         message.Append("\nChanged properties:");
135                         foreach(KeyValuePair<string, string> e in changed)
136                         {
137                             message.Append("\n  ");
138                             message.Append(e.Key);
139                             if(traceLevel > 1)
140                             {
141                                 message.Append(" = ");
142                                 message.Append(e.Value);
143                                 message.Append(" (old value = ");
144                                 message.Append(_properties.getProperty(e.Key));
145                                 message.Append(")");
146                             }
147                         }
148                     }
149 
150                     if(removed.Count > 0)
151                     {
152                         message.Append("\nRemoved properties:");
153                         foreach(KeyValuePair<string, string> e in removed)
154                         {
155                             message.Append("\n  ");
156                             message.Append(e.Key);
157                         }
158                     }
159 
160                     _logger.trace(_traceCategory, message.ToString());
161                 }
162 
163                 //
164                 // Update the property set.
165                 //
166 
167                 foreach(KeyValuePair<string, string> e in added)
168                 {
169                     _properties.setProperty(e.Key, e.Value);
170                 }
171 
172                 foreach(KeyValuePair<string, string> e in changed)
173                 {
174                     _properties.setProperty(e.Key, e.Value);
175                 }
176 
177                 foreach(KeyValuePair<string, string> e in removed)
178                 {
179                     _properties.setProperty(e.Key, "");
180                 }
181 
182                 if(_deprecatedUpdateCallbacks.Count > 0 || _updateCallbacks.Count > 0)
183                 {
184                     Dictionary<string, string> changes = new Dictionary<string, string>(added);
185                     foreach(KeyValuePair<string, string> e in changed)
186                     {
187                         changes.Add(e.Key, e.Value);
188                     }
189                     foreach(KeyValuePair<string, string> e in removed)
190                     {
191                         changes.Add(e.Key, e.Value);
192                     }
193 
194                     // Copy callbacks to allow callbacks to update callbacks
195                     foreach(var callback in new List<Ice.PropertiesAdminUpdateCallback>(_deprecatedUpdateCallbacks))
196                     {
197                         try
198                         {
199                             callback.updated(changes);
200                         }
201                         catch(Exception ex)
202                         {
203                             if(_properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1)
204                             {
205                                 _logger.warning("properties admin update callback raised unexpected exception:\n" + ex);
206                             }
207                         }
208                     }
209                     // Copy callbacks to allow callbacks to update callbacks
210                     foreach(var callback in new List<System.Action<Dictionary<string, string>>>(_updateCallbacks))
211                     {
212                         try
213                         {
214                             callback(changes);
215                         }
216                         catch(Exception ex)
217                         {
218                             if(_properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1)
219                             {
220                                 _logger.warning("properties admin update callback raised unexpected exception:\n" + ex);
221                             }
222                         }
223                     }
224                 }
225             }
226         }
227 
addUpdateCallback(Ice.PropertiesAdminUpdateCallback cb)228         public void addUpdateCallback(Ice.PropertiesAdminUpdateCallback cb)
229         {
230             lock(this)
231             {
232                 _deprecatedUpdateCallbacks.Add(cb);
233             }
234         }
235 
removeUpdateCallback(Ice.PropertiesAdminUpdateCallback cb)236         public void removeUpdateCallback(Ice.PropertiesAdminUpdateCallback cb)
237         {
238             lock(this)
239             {
240                 _deprecatedUpdateCallbacks.Remove(cb);
241             }
242         }
243 
addUpdateCallback(System.Action<Dictionary<string, string>> cb)244         public void addUpdateCallback(System.Action<Dictionary<string, string>> cb)
245         {
246             lock(this)
247             {
248                 _updateCallbacks.Add(cb);
249             }
250         }
251 
removeUpdateCallback(System.Action<Dictionary<string, string>> cb)252         public void removeUpdateCallback(System.Action<Dictionary<string, string>> cb)
253         {
254             lock(this)
255             {
256                 _updateCallbacks.Remove(cb);
257             }
258         }
259 
260         private readonly Ice.Properties _properties;
261         private readonly Ice.Logger _logger;
262         private List<Ice.PropertiesAdminUpdateCallback> _deprecatedUpdateCallbacks =
263             new List<Ice.PropertiesAdminUpdateCallback>();
264         private List<System.Action<Dictionary<string, string>>> _updateCallbacks =
265             new List<System.Action<Dictionary<string, string>>>();
266 
267         private static readonly string _traceCategory = "Admin.Properties";
268     }
269 }
270