提交 31bf615b 编写于 作者: A alanb

8004874: Reduce dependency on java.beans to only add/removePropertyChangeListener

Reviewed-by: ksrini, mchung, dholmes
上级 7690114e
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
package com.sun.java.util.jar.pack; package com.sun.java.util.jar.pack;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintStream; import java.io.PrintStream;
...@@ -42,40 +40,39 @@ import java.util.Set; ...@@ -42,40 +40,39 @@ import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.jar.Pack200; 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. * Control block for publishing Pack200 options to the other classes.
*/ */
final class PropMap implements SortedMap<String, String> { final class PropMap implements SortedMap<String, String> {
private final TreeMap<String, String> theMap = new TreeMap<>();; private final TreeMap<String, String> theMap = new TreeMap<>();;
private final List<PropertyChangeListener> listenerList = new ArrayList<>(1);
void addListener(PropertyChangeListener listener) { // type is erased, elements are of type java.beans.PropertyChangeListener
private final List<Object> listenerList = new ArrayList<>(1);
void addListener(Object listener) {
assert Beans.isPropertyChangeListener(listener);
listenerList.add(listener); listenerList.add(listener);
} }
void removeListener(PropertyChangeListener listener) { void removeListener(Object listener) {
assert Beans.isPropertyChangeListener(listener);
listenerList.remove(listener); listenerList.remove(listener);
} }
void addListeners(ArrayList<PropertyChangeListener> listeners) {
listenerList.addAll(listeners);
}
void removeListeners(ArrayList<PropertyChangeListener> listeners) {
listenerList.removeAll(listeners);
}
// Override: // Override:
public String put(String key, String value) { public String put(String key, String value) {
String oldValue = theMap.put(key, value); String oldValue = theMap.put(key, value);
if (value != oldValue && !listenerList.isEmpty()) { if (value != oldValue && !listenerList.isEmpty()) {
assert Beans.isBeansPresent();
// Post the property change event. // Post the property change event.
PropertyChangeEvent event = Object event = Beans.newPropertyChangeEvent(this, key, oldValue, value);
new PropertyChangeEvent(this, key, for (Object listener : listenerList) {
oldValue, value); Beans.invokePropertyChange(listener, event);
for (PropertyChangeListener listener : listenerList) {
listener.propertyChange(event);
} }
} }
return oldValue; return oldValue;
...@@ -339,4 +336,113 @@ final class PropMap implements SortedMap<String, String> { ...@@ -339,4 +336,113 @@ final class PropMap implements SortedMap<String, String> {
public String lastKey() { public String lastKey() {
return theMap.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);
}
}
}
} }
...@@ -31,10 +31,10 @@ import java.util.*; ...@@ -31,10 +31,10 @@ import java.util.*;
import java.security.*; import java.security.*;
import java.lang.ref.ReferenceQueue; import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference; 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.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 * There is a single global LogManager object that is used to
...@@ -150,7 +150,7 @@ public class LogManager { ...@@ -150,7 +150,7 @@ public class LogManager {
// The map of the registered listeners. The map value is the registration // 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. // 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. // Table of named Loggers that maps names to Loggers.
private Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>(); private Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
...@@ -971,22 +971,24 @@ public class LogManager { ...@@ -971,22 +971,24 @@ public class LogManager {
// Notify any interested parties that our properties have changed. // 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 // We first take a copy of the listener map so that we aren't holding any
// locks when calling the listeners. // locks when calling the listeners.
Map<PropertyChangeListener,Integer> listeners = null; Map<Object,Integer> listeners = null;
synchronized (listenerMap) { synchronized (listenerMap) {
if (!listenerMap.isEmpty()) if (!listenerMap.isEmpty())
listeners = new HashMap<>(listenerMap); listeners = new HashMap<>(listenerMap);
} }
if (listeners != null) { if (listeners != null) {
PropertyChangeEvent ev = new PropertyChangeEvent(LogManager.class, null, null, null); assert Beans.isBeansPresent();
for (Map.Entry<PropertyChangeListener,Integer> entry : listeners.entrySet()) { Object ev = Beans.newPropertyChangeEvent(LogManager.class, null, null, null);
PropertyChangeListener listener = entry.getKey(); for (Map.Entry<Object,Integer> entry : listeners.entrySet()) {
Object listener = entry.getKey();
int count = entry.getValue().intValue(); int count = entry.getValue().intValue();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
listener.propertyChange(ev); Beans.invokePropertyChange(listener, ev);
} }
} }
} }
// Note that we need to reinitialize global handles when // Note that we need to reinitialize global handles when
// they are first referenced. // they are first referenced.
synchronized (this) { synchronized (this) {
...@@ -1269,4 +1271,100 @@ public class LogManager { ...@@ -1269,4 +1271,100 @@ public class LogManager {
return loggingMXBean; 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);
}
}
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册