src/java.logging/share/classes/java/util/logging/LogManager.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 167,176 ****
--- 167,179 ----
// This gets set to false in readConfiguration
private boolean initializedGlobalHandlers = true;
// True if JVM death is imminent and the exit hook has been called.
private boolean deathImminent;
+ private final Map<Object, Runnable> listeners =
+ Collections.synchronizedMap(new IdentityHashMap<>());
+
static {
manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
@Override
public LogManager run() {
LogManager mgr = null;
*** 1166,1176 ****
* be re-read from the same file that was used at startup.
* <P>
* Any log level definitions in the new configuration file will be
* applied using Logger.setLevel(), if the target Logger exists.
* <p>
! * A PropertyChangeEvent will be fired after the properties are read.
*
* @exception SecurityException if a security manager exists and if
* the caller does not have LoggingPermission("control").
* @exception IOException if there are IO problems reading the configuration.
*/
--- 1169,1180 ----
* be re-read from the same file that was used at startup.
* <P>
* Any log level definitions in the new configuration file will be
* applied using Logger.setLevel(), if the target Logger exists.
* <p>
! * Any {@linkplain #addConfigurationListener registered configuration
! * listener} will be invoked after the properties are read.
*
* @exception SecurityException if a security manager exists and if
* the caller does not have LoggingPermission("control").
* @exception IOException if there are IO problems reading the configuration.
*/
*** 1300,1310 ****
}
/**
* Reinitialize the logging properties and reread the logging configuration
* from the given stream, which should be in java.util.Properties format.
! * A PropertyChangeEvent will be fired after the properties are read.
* <p>
* Any log level definitions in the new configuration file will be
* applied using Logger.setLevel(), if the target Logger exists.
*
* @param ins stream to read properties from
--- 1304,1315 ----
}
/**
* Reinitialize the logging properties and reread the logging configuration
* from the given stream, which should be in java.util.Properties format.
! * Any {@linkplain #addConfigurationListener registered configuration
! * listener} will be invoked after the properties are read.
* <p>
* Any log level definitions in the new configuration file will be
* applied using Logger.setLevel(), if the target Logger exists.
*
* @param ins stream to read properties from
*** 1333,1348 ****
--- 1338,1357 ----
}
// Set levels on any pre-existing loggers, based on the new properties.
setLevelsOnExistingLoggers();
+ try {
+ invokeConfigurationListeners();
+ } finally {
// Note that we need to reinitialize global handles when
// they are first referenced.
synchronized (this) {
initializedGlobalHandlers = false;
}
}
+ }
/**
* Get the value of a logging property.
* The method returns null if the property is not found.
* @param name property name
*** 1618,1623 ****
--- 1627,1696 ----
if (loggingMXBean == null) {
loggingMXBean = new Logging();
}
return loggingMXBean;
}
+
+ /**
+ * Adds a configuration listener to be invoked each time the logging
+ * configuration is read.
+ * If the listener is already registered the method does nothing.
+ * <p>
+ * The listener is invoked with privileges that are restricted by the
+ * calling context of this method.
+ * The order in which the listeners are invoked is unspecified.
+ * <p>
+ * It is recommended that listeners do not throw errors or exceptions.
+ * If a listener terminates with an uncaught error or exception then it
+ * will be propagated to the caller of {@link #readConfiguration()}
+ * (or {@link #readConfiguration(java.io.InputStream)}) and prevent other
+ * listeners from being notified.
+ *
+ * @param listener A configuration listener that will be invoked after the
+ * configuration changed.
+ * @return This LogManager.
+ * @throws SecurityException if a security manager exists and if the
+ * caller does not have LoggingPermission("control").
+ * @throws NullPointerException if the listener is null.
+ *
+ * @since 1.9
+ */
+ public LogManager addConfigurationListener(Runnable listener) {
+ final Runnable r = Objects.requireNonNull(listener);
+ checkPermission();
+ final SecurityManager sm = System.getSecurityManager();
+ final AccessControlContext acc =
+ sm == null ? null : AccessController.getContext();
+ final PrivilegedAction<Void> pa =
+ acc == null ? null : () -> { r.run() ; return null; };
+ final Runnable pr =
+ acc == null ? r : () -> AccessController.doPrivileged(pa, acc);
+ // Will do nothing if already registered.
+ listeners.putIfAbsent(r, pr);
+ return this;
+ }
+
+ /**
+ * Removes a previously registered configuration listener.
+ *
+ * Returns silently if the listener is not found.
+ *
+ * @param listener the configuration listener to remove.
+ * @throws NullPointerException if the listener is null.
+ * @throws SecurityException if a security manager exists and if the
+ * caller does not have LoggingPermission("control").
+ *
+ * @since 1.9
+ */
+ public void removeConfigurationListener(Runnable listener) {
+ final Runnable key = Objects.requireNonNull(listener);
+ checkPermission();
+ listeners.remove(key);
+ }
+
+ private void invokeConfigurationListeners() {
+ for (Runnable c : listeners.values().toArray(new Runnable[0])) {
+ c.run();
+ }
+ }
+
}