diff --git a/src/share/classes/com/sun/java/util/jar/pack/PropMap.java b/src/share/classes/com/sun/java/util/jar/pack/PropMap.java index e1a385546c96e91ecee0a2bbe655704b12d3a8e5..6199c77b51d8fee079d369b465963ba7f784512f 100644 --- a/src/share/classes/com/sun/java/util/jar/pack/PropMap.java +++ b/src/share/classes/com/sun/java/util/jar/pack/PropMap.java @@ -25,8 +25,6 @@ package com.sun.java.util.jar.pack; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeEvent; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; @@ -42,40 +40,39 @@ import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.jar.Pack200; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + /** * Control block for publishing Pack200 options to the other classes. */ final class PropMap implements SortedMap { private final TreeMap theMap = new TreeMap<>();; - private final List listenerList = new ArrayList<>(1); - void addListener(PropertyChangeListener listener) { + // type is erased, elements are of type java.beans.PropertyChangeListener + private final List listenerList = new ArrayList<>(1); + + void addListener(Object listener) { + assert Beans.isPropertyChangeListener(listener); listenerList.add(listener); } - void removeListener(PropertyChangeListener listener) { + void removeListener(Object listener) { + assert Beans.isPropertyChangeListener(listener); listenerList.remove(listener); } - void addListeners(ArrayList listeners) { - listenerList.addAll(listeners); - } - - void removeListeners(ArrayList listeners) { - listenerList.removeAll(listeners); - } - // Override: public String put(String key, String value) { String oldValue = theMap.put(key, value); if (value != oldValue && !listenerList.isEmpty()) { + assert Beans.isBeansPresent(); // Post the property change event. - PropertyChangeEvent event = - new PropertyChangeEvent(this, key, - oldValue, value); - for (PropertyChangeListener listener : listenerList) { - listener.propertyChange(event); + Object event = Beans.newPropertyChangeEvent(this, key, oldValue, value); + for (Object listener : listenerList) { + Beans.invokePropertyChange(listener, event); } } return oldValue; @@ -339,4 +336,113 @@ final class PropMap implements SortedMap { public String lastKey() { return theMap.lastKey(); } + + /** + * 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 from Packer and + * Unpacker. + */ + 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 {@code true} if the given object is a PropertyChangeListener + */ + static boolean isPropertyChangeListener(Object obj) { + if (propertyChangeListenerClass == null) { + return false; + } else { + return propertyChangeListenerClass.isInstance(obj); + } + } + + /** + * 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); + } + } + } } diff --git a/src/share/classes/java/util/logging/LogManager.java b/src/share/classes/java/util/logging/LogManager.java index ef8158a13660ed3f7ed7049121177e70305a2425..e3a8bf278853c0c1198dca726e5cfb0074ab50e0 100644 --- a/src/share/classes/java/util/logging/LogManager.java +++ b/src/share/classes/java/util/logging/LogManager.java @@ -31,10 +31,10 @@ import java.util.*; 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 @@ public class LogManager { // 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 @@ public class LogManager { // 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 @@ public class LogManager { 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); + } + } + } }