NativePropertiesAdmin.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Consumer;
/**
* The default implementation of the "Properties" admin facet.
*/
public class NativePropertiesAdmin implements PropertiesAdmin {
private final Properties _properties;
private final Logger _logger;
private final List<Consumer<Map<String, String>>> _updateCallbacks = new ArrayList<>();
private static final String _traceCategory = "Admin.Properties";
@Override
public synchronized String getProperty(String name, Current current) {
return _properties.getProperty(name);
}
@Override
public synchronized TreeMap<String, String> getPropertiesForPrefix(String name, Current current) {
return new TreeMap<>(_properties.getPropertiesForPrefix(name));
}
@Override
public synchronized void setProperties(Map<String, String> props, Current current) {
Map<String, String> old = _properties.getPropertiesForPrefix("");
final int traceLevel = _properties.getIcePropertyAsInt("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.
Map<String, String> added = new HashMap<>();
Map<String, String> changed = new HashMap<>();
Map<String, String> removed = new HashMap<>();
for (Map.Entry<String, String> e : props.entrySet()) {
final String key = e.getKey();
final String value = e.getValue();
if (!old.containsKey(key)) {
if (!value.isEmpty()) {
//
// This property is new.
//
added.put(key, value);
}
} else {
if (!value.equals(old.get(key))) {
if (value.isEmpty()) {
//
// This property was removed.
//
removed.put(key, value);
} else {
//
// This property has changed.
//
changed.put(key, value);
}
}
old.remove(key);
}
}
if (traceLevel > 0 && (!added.isEmpty() || !changed.isEmpty() || !removed.isEmpty())) {
StringBuilder out = new StringBuilder(128);
out.append("Summary of property changes");
if (!added.isEmpty()) {
out.append("\nNew properties:");
for (Map.Entry<String, String> e : added.entrySet()) {
out.append("\n ");
out.append(e.getKey());
if (traceLevel > 1) {
out.append(" = ");
out.append(e.getValue());
}
}
}
if (!changed.isEmpty()) {
out.append("\nChanged properties:");
for (Map.Entry<String, String> e : changed.entrySet()) {
out.append("\n ");
out.append(e.getKey());
if (traceLevel > 1) {
out.append(" = ");
out.append(e.getValue());
out.append(" (old value = ");
out.append(_properties.getProperty(e.getKey()));
out.append(')');
}
}
}
if (!removed.isEmpty()) {
out.append("\nRemoved properties:");
for (Map.Entry<String, String> e : removed.entrySet()) {
out.append("\n ");
out.append(e.getKey());
}
}
_logger.trace(_traceCategory, out.toString());
}
//
// Update the property set.
//
for (Map.Entry<String, String> e : added.entrySet()) {
_properties.setProperty(e.getKey(), e.getValue());
}
for (Map.Entry<String, String> e : changed.entrySet()) {
_properties.setProperty(e.getKey(), e.getValue());
}
for (Map.Entry<String, String> e : removed.entrySet()) {
_properties.setProperty(e.getKey(), "");
}
if (!_updateCallbacks.isEmpty()) {
Map<String, String> changes = new HashMap<>(added);
changes.putAll(changed);
changes.putAll(removed);
//
// Copy the callbacks to allow callbacks to update the callbacks.
//
for (Consumer<Map<String, String>> callback : new ArrayList<>(_updateCallbacks)) {
callback.accept(changes);
}
}
}
/**
* Adds a new update callback. The callback receives the updated properties each time the
* properties are updated.
*
* @param cb The new callback.
*/
public synchronized void addUpdateCallback(Consumer<Map<String, String>> cb) {
_updateCallbacks.add(cb);
}
/**
* Removes a previously registered update callback.
*
* @param cb The callback to remove.
*/
public synchronized void removeUpdateCallback(Consumer<Map<String, String>> cb) {
_updateCallbacks.remove(cb);
}
NativePropertiesAdmin(Instance instance) {
_properties = instance.initializationData().properties;
_logger = instance.initializationData().logger;
}
}