--- old/src/share/classes/java/util/logging/LogManager.java Tue Dec 11 18:13:50 2012 +++ new/src/share/classes/java/util/logging/LogManager.java Tue Dec 11 18:13:49 2012 @@ -31,10 +31,10 @@ import java.security.*; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeEvent; -import java.net.URL; -import sun.security.action.GetPropertyAction; /** * There is a single global LogManager object that is used to @@ -150,7 +150,7 @@ // The map of the registered listeners. The map value is the registration // count to allow for cases where the same listener is registered many times. - private final Map listenerMap = new HashMap<>(); + private final Map listenerMap = new HashMap<>(); // Table of named Loggers that maps names to Loggers. private Hashtable namedLoggers = new Hashtable<>(); @@ -971,22 +971,24 @@ // Notify any interested parties that our properties have changed. // We first take a copy of the listener map so that we aren't holding any // locks when calling the listeners. - Map listeners = null; + Map listeners = null; synchronized (listenerMap) { if (!listenerMap.isEmpty()) listeners = new HashMap<>(listenerMap); } if (listeners != null) { - PropertyChangeEvent ev = new PropertyChangeEvent(LogManager.class, null, null, null); - for (Map.Entry entry : listeners.entrySet()) { - PropertyChangeListener listener = entry.getKey(); + assert Beans.isBeansPresent(); + Object ev = Beans.newPropertyChangeEvent(LogManager.class, null, null, null); + for (Map.Entry entry : listeners.entrySet()) { + Object listener = entry.getKey(); int count = entry.getValue().intValue(); for (int i = 0; i < count; i++) { - listener.propertyChange(ev); + Beans.invokePropertyChange(listener, ev); } } } + // Note that we need to reinitialize global handles when // they are first referenced. synchronized (this) { @@ -1269,4 +1271,100 @@ return loggingMXBean; } + /** + * A class that provides access to the java.beans.PropertyChangeListener + * and java.beans.PropertyChangeEvent without creating a static dependency + * on java.beans. This class can be removed once the addPropertyChangeListener + * and removePropertyChangeListener methods are removed. + */ + private static class Beans { + private static final Class propertyChangeListenerClass = + getClass("java.beans.PropertyChangeListener"); + + private static final Class propertyChangeEventClass = + getClass("java.beans.PropertyChangeEvent"); + + private static final Method propertyChangeMethod = + getMethod(propertyChangeListenerClass, + "propertyChange", + propertyChangeEventClass); + + private static final Constructor propertyEventCtor = + getConstructor(propertyChangeEventClass, + Object.class, + String.class, + Object.class, + Object.class); + + private static Class getClass(String name) { + try { + return Class.forName(name, true, Beans.class.getClassLoader()); + } catch (ClassNotFoundException e) { + return null; + } + } + private static Constructor getConstructor(Class c, Class... types) { + try { + return (c == null) ? null : c.getDeclaredConstructor(types); + } catch (NoSuchMethodException x) { + throw new AssertionError(x); + } + } + + private static Method getMethod(Class c, String name, Class... types) { + try { + return (c == null) ? null : c.getMethod(name, types); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** + * Returns {@code true} if java.beans is present. + */ + static boolean isBeansPresent() { + return propertyChangeListenerClass != null && + propertyChangeEventClass != null; + } + + /** + * Returns a new PropertyChangeEvent with the given source, property + * name, old and new values. + */ + static Object newPropertyChangeEvent(Object source, String prop, + Object oldValue, Object newValue) + { + try { + return propertyEventCtor.newInstance(source, prop, oldValue, newValue); + } catch (InstantiationException | IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof Error) + throw (Error)cause; + if (cause instanceof RuntimeException) + throw (RuntimeException)cause; + throw new AssertionError(x); + } + } + + /** + * Invokes the given PropertyChangeListern's propertyChange method + * with the given event. + */ + static void invokePropertyChange(Object listener, Object ev) { + try { + propertyChangeMethod.invoke(listener, ev); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof Error) + throw (Error)cause; + if (cause instanceof RuntimeException) + throw (RuntimeException)cause; + throw new AssertionError(x); + } + } + } }