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
*** 29,38 ****
--- 29,39 ----
import java.io.*;
import java.util.*;
import java.security.*;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
+ import java.util.concurrent.CopyOnWriteArrayList;
import sun.misc.JavaAWTAccess;
import sun.misc.SharedSecrets;
/**
* There is a single global LogManager object that is used to
*** 167,176 ****
--- 168,180 ----
// 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 CopyOnWriteArrayList<ConfigurationListener> listeners =
+ new CopyOnWriteArrayList<>();
+
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.
*/
--- 1170,1181 ----
* 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>
! * The {@linkplain #addConfigurationListener(java.util.logging.LogManager.ConfigurationListener)
! * configuration listeners} 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
--- 1305,1316 ----
}
/**
* Reinitialize the logging properties and reread the logging configuration
* from the given stream, which should be in java.util.Properties format.
! * The {@linkplain #addConfigurationListener(java.util.logging.LogManager.ConfigurationListener)
! * configuration listeners} 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,1342 ****
--- 1339,1350 ----
}
// Set levels on any pre-existing loggers, based on the new properties.
setLevelsOnExistingLoggers();
+ invokeConfigurationListeners();
+
// Note that we need to reinitialize global handles when
// they are first referenced.
synchronized (this) {
initializedGlobalHandlers = false;
}
*** 1618,1623 ****
--- 1626,1727 ----
if (loggingMXBean == null) {
loggingMXBean = new Logging();
}
return loggingMXBean;
}
+
+ /**
+ * A configuration listener can be added to the LogManager in
+ * in order to be informed of configuration loads.
+ * When the LogManager reads (or re-reads) its configuration, it
+ * will invoke all configuration listeners that are registered with it.
+ *
+ * @since 1.9
+ */
+ public static abstract class ConfigurationListener {
+
+ private static Void checkPermission() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(controlPermission);
+ }
+ return null;
+ }
+ protected ConfigurationListener() {
+ this(checkPermission());
+ }
+ private ConfigurationListener(Void checked) {
+ }
+
+ /**
+ * This method will be called by the LogManager when its configuration
+ * has been read.
+ * @see #readConfiguration(java.io.InputStream)
+ */
+ public abstract void configurationLoaded();
+
+ @Override
+ public final boolean equals(Object other) {
+ return (other instanceof ConfigurationListener)
+ ? super.equals(other) : false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return super.hashCode();
+ }
+
+ }
+
+
+ /**
+ * Adds a configuration listener to be invoked when the logging properties
+ * are re-read and the configuration is changed.
+ * Adding multiple instances of the same listener results in
+ * the listener being invoked as many times as it was added when the
+ * configuration is changed.
+ *
+ * @param listener A configuration listener that will be invoked after the
+ * configuration changed.
+ * @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 void addConfigurationListener(ConfigurationListener listener) {
+ ConfigurationListener l = Objects.requireNonNull(listener);
+ checkPermission();
+ listeners.add(l);
+ }
+
+ /**
+ * Removes a previously registered configuration listener.
+ *
+ * If the same listener instance has been added through multiple
+ * invocations of {@code addConfigurationListener}, then an equivalent
+ * number of {@code removeConfigurationListener} invocations are
+ * required to remove all registration of that listener.
+ * <P>
+ * Returns silently if the given listener is {@code null} or is
+ * not found.
+ *
+ * @param listener the configuration listener to remove (can be null)
+ * @throws SecurityException if a security manager exists and if the
+ * caller does not have LoggingPermission("control").
+ *
+ * @since 1.9
+ */
+ public void removeConfigurationListener(ConfigurationListener listener) {
+ checkPermission();
+ if (listener != null) {
+ listeners.remove(listener);
+ }
+ }
+
+ private void invokeConfigurationListeners() {
+ for (ConfigurationListener listener : listeners) {
+ listener.configurationLoaded();
+ }
+ }
+
}