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(); + } + } + }