+ public void accept(Map<String, Object> configuration) {
+ synchronized (levels) {
+ updatingConfiguration = true;
+
+ Map<String, Level> backup = new TreeMap<>(levels);
+
+ boolean fullReset = configuration.containsKey(DEFAULT_LEVEL_PROPERTY);
+ try {
+ properties: for (String property : configuration.keySet()) {
+ if (!property.startsWith(LEVEL_PROPERTY_PREFIX))
+ continue properties;
+ String levelStr = configuration.get(property).toString();
+ Level level = Level.valueOf(levelStr);
+ levels.put(property.substring(LEVEL_PROPERTY_PREFIX.length()), level);
+ }
+
+ if (fullReset) {
+ Iterator<Map.Entry<String, Level>> it = levels.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, Level> entry = it.next();
+ String name = entry.getKey();
+ if (!configuration.containsKey(LEVEL_PROPERTY_PREFIX + name)) {
+ it.remove();
+ }
+ }
+ Level newDefaultLevel = Level.valueOf(configuration.get(DEFAULT_LEVEL_PROPERTY).toString());
+ levels.put(DEFAULT_LEVEL_NAME, newDefaultLevel);
+ // TODO notify everyone?
+ }
+ assert levels.containsKey(DEFAULT_LEVEL_NAME);
+
+ // recompute all levels
+ for (String name : loggers.keySet()) {
+ ThinLogger logger = loggers.get(name);
+ logger.setLevel(computeApplicableLevel(name));
+ }
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ levels.clear();
+ levels.putAll(backup);
+ }
+ updatingConfiguration = false;
+ levels.notifyAll();
+ }
+
+ }
+
+ Flow.Publisher<Map<String, Serializable>> getLogEntryPublisher() {
+ return publisher;
+ }
+
+ Map<String, Level> getLevels() {
+ return Collections.unmodifiableNavigableMap(levels);
+ }
+
+ /*
+ * INTERNAL CLASSES
+ */
+
+ private class ThinLogger implements System.Logger {