jdk/src/share/classes/java/util/logging/LogManager.java
changeset 14774 4e298ffae1c7
parent 14767 b64db1d425e5
child 16100 379f48d34516
child 15684 e5b41bd22ec9
--- a/jdk/src/share/classes/java/util/logging/LogManager.java	Wed Dec 12 11:35:18 2012 +0000
+++ b/jdk/src/share/classes/java/util/logging/LogManager.java	Wed Dec 12 13:03:05 2012 +0000
@@ -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<PropertyChangeListener,Integer> listenerMap = new HashMap<>();
+    private final Map<Object,Integer> listenerMap = new HashMap<>();
 
     // Table of named Loggers that maps names to Loggers.
     private Hashtable<String,LoggerWeakRef> 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<PropertyChangeListener,Integer> listeners = null;
+        Map<Object,Integer> 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<PropertyChangeListener,Integer> entry : listeners.entrySet()) {
-                PropertyChangeListener listener = entry.getKey();
+            assert Beans.isBeansPresent();
+            Object ev = Beans.newPropertyChangeEvent(LogManager.class, null, null, null);
+            for (Map.Entry<Object,Integer> 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 PropertyChangeListener'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);
+            }
+        }
+    }
 }