You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by tv...@apache.org on 2009/10/26 16:50:21 UTC
svn commit: r829838 - in /incubator/pivot/trunk:
core/src/org/apache/pivot/beans/ tools/src/org/apache/pivot/tools/wtk/
Author: tvolkert
Date: Mon Oct 26 15:50:21 2009
New Revision: 829838
URL: http://svn.apache.org/viewvc?rev=829838&view=rev
Log:
Migrated BeanMonitor functionality into BeanDictionary, updates tools project per the migration
Added:
incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionaryListener.java
- copied, changed from r829797, incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanMonitorListener.java
Removed:
incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanMonitor.java
incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanMonitorListener.java
Modified:
incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentInspectorSkin.java
incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/EventLogger.java
Modified: incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java?rev=829838&r1=829837&r2=829838&view=diff
==============================================================================
--- incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java (original)
+++ incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionary.java Mon Oct 26 15:50:21 2009
@@ -17,14 +17,23 @@
package org.apache.pivot.beans;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.pivot.collections.Dictionary;
-
+import org.apache.pivot.collections.HashMap;
+import org.apache.pivot.collections.HashSet;
+import org.apache.pivot.util.ListenerList;
+import org.apache.pivot.util.ThreadUtilities;
+import org.apache.pivot.util.Vote;
/**
* Exposes Java bean properties of an object via the {@link Dictionary}
@@ -131,14 +140,70 @@
}
}
+ private class BeanInvocationHandler implements InvocationHandler {
+ @Override
+ public Object invoke(Object proxy, Method event, Object[] arguments) throws Throwable {
+ String eventName = event.getName();
+ if (eventName.endsWith(PROPERTY_CHANGE_SUFFIX)) {
+ String propertyName = eventName.substring(0, eventName.length()
+ - PROPERTY_CHANGE_SUFFIX.length());
+
+ if (notifyingProperties.contains(propertyName)) {
+ beanDictionaryListeners.propertyChanged(BeanDictionary.this, propertyName);
+ }
+ }
+
+ Object result = null;
+ Class<?> returnType = event.getReturnType();
+ if (returnType == Vote.class) {
+ result = Vote.APPROVE;
+ } else if (returnType == Boolean.TYPE) {
+ result = false;
+ }
+
+ return result;
+ }
+ }
+
+ private static class BeanDictionaryListenerList extends ListenerList<BeanDictionaryListener>
+ implements BeanDictionaryListener {
+ @Override
+ public void beanChanged(BeanDictionary beanDictionary, Object previousBean) {
+ for (BeanDictionaryListener listener : this) {
+ listener.beanChanged(beanDictionary, previousBean);
+ }
+ }
+
+ @Override
+ public void propertyChanged(BeanDictionary beanDictionary, String propertyName) {
+ for (BeanDictionaryListener listener : this) {
+ listener.propertyChanged(beanDictionary, propertyName);
+ }
+ }
+ }
+
private Object bean;
private boolean ignoreReadOnlyProperties;
+ private HashMap<Class<?>, Object> beanListenerProxies = null;
+ private BeanInvocationHandler invocationHandler = null;
+ private HashSet<String> notifyingProperties = null;
+
+ private BeanDictionaryListenerList beanDictionaryListeners = null;
+
public static final String GET_PREFIX = "get";
public static final String IS_PREFIX = "is";
public static final String SET_PREFIX = "set";
public static final String FIELD_PREFIX = "~";
public static final String LISTENERS_SUFFIX = "Listeners";
+ public static final String PROPERTY_CHANGE_SUFFIX = "Changed";
+
+ /**
+ * Creates a new bean dictionary that is not associated with a bean.
+ */
+ public BeanDictionary() {
+ this(null);
+ }
/**
* Creates a new bean dictionary.
@@ -157,22 +222,52 @@
* The bean object to wrap.
*/
public BeanDictionary(Object bean, boolean ignoreReadOnlyProperties) {
- if (bean == null) {
- throw new IllegalArgumentException("bean is null.");
- }
-
- this.bean = bean;
this.ignoreReadOnlyProperties = ignoreReadOnlyProperties;
+ setBean(bean);
}
/**
* Returns the bean object this dictionary wraps.
+ *
+ * @return
+ * The bean object, or <tt>null</tt> if no bean has been set.
*/
public Object getBean() {
return bean;
}
/**
+ * Sets the bean object that this dictionary will wrap.
+ * <p>
+ * <b>NOTE</b>: failing to clear the bean of a bean dictionary may result in
+ * memory leaks, as the bean object may maintain references to the bean
+ * dictionary as long as it is set.
+ *
+ * @param bean
+ * The bean object, or <tt>null</tt> to clear the bean.
+ */
+ public void setBean(Object bean) {
+ Object previousBean = this.bean;
+
+ if (bean != previousBean) {
+ if (beanDictionaryListeners != null
+ && previousBean != null) {
+ unregisterBeanListeners();
+ }
+
+ this.bean = bean;
+
+ if (beanDictionaryListeners != null) {
+ if (bean != null) {
+ registerBeanListeners();
+ }
+
+ beanDictionaryListeners.beanChanged(this, previousBean);
+ }
+ }
+ }
+
+ /**
* Invokes the getter method for the given property.
*
* @param key
@@ -184,6 +279,10 @@
*/
@Override
public Object get(String key) {
+ if (bean == null) {
+ throw new IllegalStateException("bean is null.");
+ }
+
if (key == null) {
throw new IllegalArgumentException("key is null.");
}
@@ -237,6 +336,10 @@
*/
@Override
public Object put(String key, Object value) {
+ if (bean == null) {
+ throw new IllegalStateException("bean is null.");
+ }
+
if (key == null) {
throw new IllegalArgumentException("key is null.");
}
@@ -324,6 +427,10 @@
*/
@Override
public boolean containsKey(String key) {
+ if (bean == null) {
+ throw new IllegalStateException("bean is null.");
+ }
+
if (key == null) {
throw new IllegalArgumentException("key is null.");
}
@@ -344,6 +451,10 @@
*/
@Override
public boolean isEmpty() {
+ if (bean == null) {
+ throw new IllegalStateException("bean is null.");
+ }
+
return !iterator().hasNext();
}
@@ -357,10 +468,41 @@
* <tt>true</tt> if the property is read-only; <tt>false</tt>, otherwise.
*/
public boolean isReadOnly(String key) {
+ if (bean == null) {
+ throw new IllegalStateException("bean is null.");
+ }
+
return isReadOnly(bean.getClass(), key);
}
/**
+ * Tells whether or not the specified property fires change events.
+ *
+ * @param key
+ * The property name.
+ *
+ * @return
+ * <tt>true</tt> if the property fires change events; <tt>false</tt>
+ * otherwise.
+ */
+ public boolean isNotifying(String key) {
+ if (bean == null) {
+ throw new IllegalStateException("bean is null.");
+ }
+
+ if (beanDictionaryListeners == null) {
+ beanDictionaryListeners = new BeanDictionaryListenerList();
+ beanListenerProxies = new HashMap<Class<?>, Object>();
+ invocationHandler = new BeanInvocationHandler();
+ notifyingProperties = new HashSet<String>();
+
+ registerBeanListeners();
+ }
+
+ return notifyingProperties.contains(key);
+ }
+
+ /**
* Returns the type of a property.
*
* @param key
@@ -370,6 +512,10 @@
* The type of the property.
*/
public Class<?> getType(String key) {
+ if (bean == null) {
+ throw new IllegalStateException("bean is null.");
+ }
+
return getType(bean.getClass(), key);
}
@@ -381,6 +527,10 @@
*/
@Override
public Iterator<String> iterator() {
+ if (bean == null) {
+ throw new IllegalStateException("bean is null.");
+ }
+
return new PropertyIterator();
}
@@ -426,6 +576,142 @@
}
/**
+ * Registers event listeners on the bean so that the dictionary can fire
+ * property change events and report which properties can fire change
+ * events.
+ */
+ private void registerBeanListeners() {
+ Method[] methods = bean.getClass().getMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (ListenerList.class.isAssignableFrom(method.getReturnType())
+ && (method.getModifiers() & Modifier.STATIC) == 0) {
+ ParameterizedType genericType = (ParameterizedType)method.getGenericReturnType();
+ Type[] typeArguments = genericType.getActualTypeArguments();
+
+ if (typeArguments.length == 1) {
+ Class<?> listenerInterface = (Class<?>)typeArguments[0];
+
+ if (!listenerInterface.isInterface()) {
+ throw new RuntimeException(listenerInterface.getName()
+ + " is not an interface.");
+ }
+
+ Method[] interfaceMethods = listenerInterface.getMethods();
+ for (int j = 0; j < interfaceMethods.length; j++) {
+ Method interfaceMethod = interfaceMethods[j];
+ String interfaceMethodName = interfaceMethod.getName();
+
+ if (interfaceMethodName.endsWith(PROPERTY_CHANGE_SUFFIX)) {
+ String propertyName = interfaceMethodName.substring(0,
+ interfaceMethodName.length() - PROPERTY_CHANGE_SUFFIX.length());
+
+ if (containsKey(propertyName)) {
+ notifyingProperties.add(propertyName);
+ }
+ }
+ }
+
+ // Get the listener list
+ Object listenerList;
+ try {
+ listenerList = method.invoke(bean);
+ } catch (InvocationTargetException exception) {
+ throw new RuntimeException(exception);
+ } catch (IllegalAccessException exception) {
+ throw new RuntimeException(exception);
+ }
+
+ // Get the listener for this interface
+ Object listener = beanListenerProxies.get(listenerInterface);
+ if (listener == null) {
+ listener = Proxy.newProxyInstance(ThreadUtilities.getClassLoader(),
+ new Class[]{listenerInterface}, invocationHandler);
+ beanListenerProxies.put(listenerInterface, listener);
+ }
+
+ // Add the listener
+ Class<?> listenerListClass = listenerList.getClass();
+ Method addMethod;
+ try {
+ addMethod = listenerListClass.getMethod("add",
+ new Class<?>[] {Object.class});
+ } catch (NoSuchMethodException exception) {
+ throw new RuntimeException(exception);
+ }
+
+ try {
+ addMethod.invoke(listenerList, new Object[] {listener});
+ } catch (IllegalAccessException exception) {
+ throw new RuntimeException(exception);
+ } catch (InvocationTargetException exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Un-registers event listeners on the bean.
+ */
+ private void unregisterBeanListeners() {
+ Method[] methods = bean.getClass().getMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (ListenerList.class.isAssignableFrom(method.getReturnType())
+ && (method.getModifiers() & Modifier.STATIC) == 0) {
+ ParameterizedType genericType = (ParameterizedType)method.getGenericReturnType();
+ Type[] typeArguments = genericType.getActualTypeArguments();
+
+ if (typeArguments.length == 1) {
+ Class<?> listenerInterface = (Class<?>)typeArguments[0];
+
+ // Get the listener list
+ Object listenerList;
+ try {
+ listenerList = method.invoke(bean);
+ } catch (InvocationTargetException exception) {
+ throw new RuntimeException(exception);
+ } catch (IllegalAccessException exception) {
+ throw new RuntimeException(exception);
+ }
+
+ // Get the listener for this interface
+ Object listener = beanListenerProxies.get(listenerInterface);
+ if (listener == null) {
+ throw new IllegalStateException("Listener proxy is null.");
+ }
+
+ // Remove the listener
+ Class<?> listenerListClass = listenerList.getClass();
+ Method removeMethod;
+ try {
+ removeMethod = listenerListClass.getMethod("remove",
+ new Class<?>[] {Object.class});
+ } catch (NoSuchMethodException exception) {
+ throw new RuntimeException(exception);
+ }
+
+ try {
+ removeMethod.invoke(listenerList, new Object[] {listener});
+ } catch (IllegalAccessException exception) {
+ throw new RuntimeException(exception);
+ } catch (InvocationTargetException exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+ }
+ }
+
+ notifyingProperties.clear();
+ }
+
+ /**
* Tests the read-only state of a property. Note that is no such property
* exists, this method will return <tt>true</tt> (it will <u>not</u> throw
* an exception).
@@ -678,4 +964,19 @@
return coercedValue;
}
+
+ public ListenerList<BeanDictionaryListener> getBeanDictionaryListeners() {
+ if (beanDictionaryListeners == null) {
+ beanDictionaryListeners = new BeanDictionaryListenerList();
+ beanListenerProxies = new HashMap<Class<?>, Object>();
+ invocationHandler = new BeanInvocationHandler();
+ notifyingProperties = new HashSet<String>();
+
+ if (bean != null) {
+ registerBeanListeners();
+ }
+ }
+
+ return beanDictionaryListeners;
+ }
}
Copied: incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionaryListener.java (from r829797, incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanMonitorListener.java)
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionaryListener.java?p2=incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionaryListener.java&p1=incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanMonitorListener.java&r1=829797&r2=829838&rev=829838&view=diff
==============================================================================
--- incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanMonitorListener.java (original)
+++ incubator/pivot/trunk/core/src/org/apache/pivot/beans/BeanDictionaryListener.java Mon Oct 26 15:50:21 2009
@@ -19,48 +19,35 @@
import java.lang.reflect.Method;
/**
- * Bean monitor listener interface.
+ * Bean dictionary listener interface.
*/
-public interface BeanMonitorListener {
+public interface BeanDictionaryListener {
/**
- * Bean monitor listener adapter.
+ * Bean dictionary listener adapter.
*/
- public static class Adapter implements BeanMonitorListener {
+ public static class Adapter implements BeanDictionaryListener {
@Override
- public void sourceChanged(BeanMonitor beanMonitor, Object previousSource) {
+ public void beanChanged(BeanDictionary beanDictionary, Object previousBean) {
}
@Override
- public void eventFired(BeanMonitor beanMonitor, Method event, Object[] arguments) {
- }
-
- @Override
- public void propertyChanged(BeanMonitor beanMonitor, String propertyName) {
+ public void propertyChanged(BeanDictionary beanDictionary, String propertyName) {
}
}
/**
- * Called when a bean monitor's source has changed.
- *
- * @param beanMonitor
- * @param previousSource
- */
- public void sourceChanged(BeanMonitor beanMonitor, Object previousSource);
-
- /**
- * Called when an event has been fired by the bean monitor's source.
+ * Called when a bean dictionary's bean has changed.
*
- * @param beanMonitor
- * @param event
- * @param arguments
+ * @param beanDictionary
+ * @param previousBean
*/
- public void eventFired(BeanMonitor beanMonitor, Method event, Object[] arguments);
+ public void beanChanged(BeanDictionary beanDictionary, Object previousBean);
/**
- * Called when a property of the bean monitor's source has changed.
+ * Called when a property of the bean dictionary's bean has changed.
*
- * @param beanMonitor
+ * @param beanDictionary
* @param propertyName
*/
- public void propertyChanged(BeanMonitor beanMonitor, String propertyName);
+ public void propertyChanged(BeanDictionary beanDictionary, String propertyName);
}
Modified: incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentInspectorSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentInspectorSkin.java?rev=829838&r1=829837&r2=829838&view=diff
==============================================================================
--- incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentInspectorSkin.java (original)
+++ incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/ComponentInspectorSkin.java Mon Oct 26 15:50:21 2009
@@ -21,8 +21,7 @@
import java.util.Comparator;
import org.apache.pivot.beans.BeanDictionary;
-import org.apache.pivot.beans.BeanMonitor;
-import org.apache.pivot.beans.BeanMonitorListener;
+import org.apache.pivot.beans.BeanDictionaryListener;
import org.apache.pivot.collections.ArrayList;
import org.apache.pivot.collections.EnumList;
import org.apache.pivot.collections.HashMap;
@@ -81,8 +80,7 @@
@WTKX private Form propertiesForm = null;
@WTKX private BoxPane stylesPane = null;
- private BeanDictionary beanDictionary = null;
- private BeanMonitor beanMonitor = new BeanMonitor();
+ private BeanDictionary beanDictionary = new BeanDictionary();
private HashMap<String, Component> inspectorComponents = new HashMap<String, Component>();
@@ -91,9 +89,9 @@
new PropertySourceTypeComparator();
public ComponentInspectorSkin() {
- beanMonitor.getBeanMonitorListeners().add(new BeanMonitorListener.Adapter() {
+ beanDictionary.getBeanDictionaryListeners().add(new BeanDictionaryListener.Adapter() {
@Override
- public void propertyChanged(BeanMonitor beanMonitor, String propertyName) {
+ public void propertyChanged(BeanDictionary beanDictionary, String propertyName) {
Class<?> propertyType = beanDictionary.getType(propertyName);
if (propertyType == Boolean.TYPE) {
@@ -178,18 +176,15 @@
Component source = componentInspector.getSource();
- beanDictionary = null;
- beanMonitor.setSource(source);
+ beanDictionary.setBean(source);
if (source != null) {
- beanDictionary = new BeanDictionary(source);
-
Class<?> sourceType = source.getClass();
HashMap<Class<?>, List<String>> propertyBuckets =
new HashMap<Class<?>, List<String>>(propertySourceTypeComparator);
for (String propertyName : beanDictionary) {
- if (beanMonitor.isNotifyingProperty(propertyName)
+ if (beanDictionary.isNotifying(propertyName)
&& !beanDictionary.isReadOnly(propertyName)) {
Method method = BeanDictionary.getGetterMethod(sourceType, propertyName);
Class<?> declaringClass = method.getDeclaringClass();
Modified: incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/EventLogger.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/EventLogger.java?rev=829838&r1=829837&r2=829838&view=diff
==============================================================================
--- incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/EventLogger.java (original)
+++ incubator/pivot/trunk/tools/src/org/apache/pivot/tools/wtk/EventLogger.java Mon Oct 26 15:50:21 2009
@@ -16,19 +16,68 @@
*/
package org.apache.pivot.tools.wtk;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.Comparator;
-import org.apache.pivot.beans.BeanMonitor;
-import org.apache.pivot.beans.BeanMonitorListener;
+import org.apache.pivot.collections.ArrayList;
import org.apache.pivot.collections.Group;
+import org.apache.pivot.collections.HashMap;
import org.apache.pivot.collections.HashSet;
import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.collections.immutable.ImmutableList;
import org.apache.pivot.collections.immutable.ImmutableSet;
import org.apache.pivot.util.ListenerList;
+import org.apache.pivot.util.ThreadUtilities;
+import org.apache.pivot.util.Vote;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.Container;
public class EventLogger extends Container {
+ private static class EventComparator implements Comparator<Method> {
+ @Override
+ public int compare(Method event1, Method event2) {
+ int result = 0;
+
+ Class<?> listenerInterface1 = event1.getDeclaringClass();
+ Class<?> listenerInterface2 = event2.getDeclaringClass();
+
+ if (listenerInterface1 != listenerInterface2) {
+ result = listenerInterface1.getName().compareTo(listenerInterface2.getName());
+ }
+
+ if (result == 0) {
+ result = event1.getName().compareTo(event2.getName());
+ }
+
+ return result;
+ }
+ }
+
+ private class LoggerInvocationHandler implements InvocationHandler {
+ @Override
+ public Object invoke(Object proxy, Method event, Object[] arguments) throws Throwable {
+ if (includeEvents.contains(event)) {
+ eventLoggerListeners.eventFired(EventLogger.this, event, arguments);
+ }
+
+ Object result = null;
+ Class<?> returnType = event.getReturnType();
+ if (returnType == Vote.class) {
+ result = Vote.APPROVE;
+ } else if (returnType == Boolean.TYPE) {
+ result = false;
+ }
+
+ return result;
+ }
+ }
+
private static class EventLoggerListenerList extends ListenerList<EventLoggerListener>
implements EventLoggerListener {
@Override
@@ -60,21 +109,12 @@
}
}
- private BeanMonitorListener beanMonitorHandler = new BeanMonitorListener.Adapter() {
- @Override
- public void sourceChanged(BeanMonitor meanMonitor, Object previousSource) {
- eventLoggerListeners.sourceChanged(EventLogger.this, (Component)previousSource);
- }
+ private Component source = null;
- @Override
- public void eventFired(BeanMonitor meanMonitor, Method event, Object[] arguments) {
- if (includeEvents.contains(event)) {
- eventLoggerListeners.eventFired(EventLogger.this, event, arguments);
- }
- }
- };
+ private HashMap<Class<?>, Object> eventListenerProxies = new HashMap<Class<?>, Object>();
+ private LoggerInvocationHandler loggerInvocationHandler = new LoggerInvocationHandler();
- private BeanMonitor beanMonitor = new BeanMonitor();
+ private ArrayList<Method> declaredEvents = new ArrayList<Method>(new EventComparator());
private HashSet<Method> includeEvents = new HashSet<Method>();
@@ -85,21 +125,34 @@
}
public EventLogger(Component source) {
- beanMonitor.getBeanMonitorListeners().add(beanMonitorHandler);
setSource(source);
setSkin(new EventLoggerSkin());
}
public Component getSource() {
- return (Component)beanMonitor.getSource();
+ return source;
}
public void setSource(Component source) {
- beanMonitor.setSource(source);
+ Component previousSource = this.source;
+
+ if (source != previousSource) {
+ this.source = source;
+
+ if (previousSource != null) {
+ unregisterEventListeners(previousSource);
+ }
+
+ if (source != null) {
+ registerEventListeners(source);
+ }
+
+ eventLoggerListeners.sourceChanged(this, previousSource);
+ }
}
public Sequence<Method> getDeclaredEvents() {
- return beanMonitor.getDeclaredEvents();
+ return new ImmutableList<Method>(declaredEvents);
}
public Group<Method> getIncludeEvents() {
@@ -124,6 +177,79 @@
return includeEvents.contains(event);
}
+ private void registerEventListeners(Component source) {
+ declaredEvents.clear();
+
+ Method[] methods = source.getClass().getMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (ListenerList.class.isAssignableFrom(method.getReturnType())
+ && (method.getModifiers() & Modifier.STATIC) == 0) {
+ ParameterizedType genericType = (ParameterizedType)method.getGenericReturnType();
+ Type[] typeArguments = genericType.getActualTypeArguments();
+
+ if (typeArguments.length == 1) {
+ Class<?> listenerInterface = (Class<?>)typeArguments[0];
+
+ if (!listenerInterface.isInterface()) {
+ throw new RuntimeException(listenerInterface.getName()
+ + " is not an interface.");
+ }
+
+ Method[] interfaceMethods = listenerInterface.getMethods();
+ for (int j = 0; j < interfaceMethods.length; j++) {
+ Method interfaceMethod = interfaceMethods[j];
+ declaredEvents.add(interfaceMethod);
+ }
+
+ // Get the listener list
+ Object listenerList;
+ try {
+ listenerList = method.invoke(source);
+ } catch (InvocationTargetException exception) {
+ throw new RuntimeException(exception);
+ } catch (IllegalAccessException exception) {
+ throw new RuntimeException(exception);
+ }
+
+ // Get the listener for this interface
+ Object listener = eventListenerProxies.get(listenerInterface);
+ if (listener == null) {
+ listener = Proxy.newProxyInstance(ThreadUtilities.getClassLoader(),
+ new Class[]{listenerInterface}, loggerInvocationHandler);
+ eventListenerProxies.put(listenerInterface, listener);
+ }
+
+ // Add the listener
+ Class<?> listenerListClass = listenerList.getClass();
+ Method addMethod;
+ try {
+ addMethod = listenerListClass.getMethod("add",
+ new Class<?>[] {Object.class});
+ } catch (NoSuchMethodException exception) {
+ throw new RuntimeException(exception);
+ }
+
+ try {
+ addMethod.invoke(listenerList, new Object[] {listener});
+ } catch (IllegalAccessException exception) {
+ throw new RuntimeException(exception);
+ } catch (InvocationTargetException exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+ }
+ }
+ }
+
+ private void unregisterEventListeners(Component source) {
+ declaredEvents.clear();
+
+ // TODO
+ }
+
public ListenerList<EventLoggerListener> getEventLoggerListeners() {
return eventLoggerListeners;
}