From af23b1effd57a89deda86e8a33c737b9cb9115e8 Mon Sep 17 00:00:00 2001 From: Jani Laakso Date: Thu, 31 Jan 2008 11:06:01 +0000 Subject: [PATCH] Fixed #588 (partially, other places still need fixes) EventRouter * is now thread safe * listenerList contains unique listeners, duplicates are not allowed ListenerMethod * implemented proper equals and hashCode methods AbstractComponent * @deprecated Use {@link #addListener(Class, Object, Method)} or {@link #addListener(com.itmill.toolkit.ui.Component.Listener)} instead. Using this method is discouraged because it cannot be checked during compilation. svn changeset:3681/svn branch:trunk --- src/com/itmill/toolkit/event/EventRouter.java | 92 +++++++++++-------- .../itmill/toolkit/event/ListenerMethod.java | 38 +++++++- .../itmill/toolkit/ui/AbstractComponent.java | 4 + 3 files changed, 95 insertions(+), 39 deletions(-) diff --git a/src/com/itmill/toolkit/event/EventRouter.java b/src/com/itmill/toolkit/event/EventRouter.java index c6f04c51ad..78f8a77df1 100644 --- a/src/com/itmill/toolkit/event/EventRouter.java +++ b/src/com/itmill/toolkit/event/EventRouter.java @@ -5,9 +5,11 @@ package com.itmill.toolkit.event; import java.lang.reflect.Method; +import java.util.Collections; import java.util.EventObject; import java.util.Iterator; -import java.util.LinkedList; +import java.util.LinkedHashSet; +import java.util.Set; /** * EventRouter class implementing the inheritable event listening @@ -24,7 +26,7 @@ public class EventRouter implements MethodEventSource { /** * List of registered listeners. */ - private LinkedList listenerList = null; + private Set listenerList = null; /* * Registers a new listener with the specified activation method to listen @@ -34,10 +36,12 @@ public class EventRouter implements MethodEventSource { public void addListener(Class eventType, Object object, Method method) { if (listenerList == null) { - listenerList = new LinkedList(); + listenerList = Collections.synchronizedSet(new LinkedHashSet()); } - listenerList.add(new ListenerMethod(eventType, object, method)); + synchronized (listenerList) { + listenerList.add(new ListenerMethod(eventType, object, method)); + } } /* @@ -48,10 +52,12 @@ public class EventRouter implements MethodEventSource { public void addListener(Class eventType, Object object, String methodName) { if (listenerList == null) { - listenerList = new LinkedList(); + listenerList = Collections.synchronizedSet(new LinkedHashSet()); } - listenerList.add(new ListenerMethod(eventType, object, methodName)); + synchronized (listenerList) { + listenerList.add(new ListenerMethod(eventType, object, methodName)); + } } /* @@ -60,17 +66,19 @@ public class EventRouter implements MethodEventSource { * interface. */ public void removeListener(Class eventType, Object target) { - if (listenerList != null) { - final Iterator i = listenerList.iterator(); - while (i.hasNext()) { - try { - final ListenerMethod lm = (ListenerMethod) i.next(); - if (lm.matches(eventType, target)) { - i.remove(); + synchronized (listenerList) { + final Iterator i = listenerList.iterator(); + while (i.hasNext()) { + try { + final ListenerMethod lm = (ListenerMethod) i.next(); + if (lm.matches(eventType, target)) { + i.remove(); + return; + } + } catch (final java.lang.ClassCastException e) { + // Class cast exceptions are ignored } - } catch (final java.lang.ClassCastException e) { - // Class cast exceptions are ignored } } } @@ -84,22 +92,25 @@ public class EventRouter implements MethodEventSource { public void removeListener(Class eventType, Object target, Method method) { if (listenerList != null) { - final Iterator i = listenerList.iterator(); - while (i.hasNext()) { - try { - final ListenerMethod lm = (ListenerMethod) i.next(); - if (lm.matches(eventType, target, method)) { - i.remove(); + synchronized (listenerList) { + final Iterator i = listenerList.iterator(); + while (i.hasNext()) { + try { + final ListenerMethod lm = (ListenerMethod) i.next(); + if (lm.matches(eventType, target, method)) { + i.remove(); + return; + } + } catch (final java.lang.ClassCastException e) { + // Class cast exceptions are ignored } - } catch (final java.lang.ClassCastException e) { - // Class cast exceptions are ignored } } } } /* - * Removes the event listener method matching the given given paramaters. + * Removes the event listener method matching the given given parameters. * Don't add a JavaDoc comment here, we use the default documentation from * implemented interface. */ @@ -119,15 +130,18 @@ public class EventRouter implements MethodEventSource { // Remove the listeners if (listenerList != null) { - final Iterator i = listenerList.iterator(); - while (i.hasNext()) { - try { - final ListenerMethod lm = (ListenerMethod) i.next(); - if (lm.matches(eventType, target, method)) { - i.remove(); + synchronized (listenerList) { + final Iterator i = listenerList.iterator(); + while (i.hasNext()) { + try { + final ListenerMethod lm = (ListenerMethod) i.next(); + if (lm.matches(eventType, target, method)) { + i.remove(); + return; + } + } catch (final java.lang.ClassCastException e) { + // Class cast exceptions are ignored } - } catch (final java.lang.ClassCastException e) { - // Class cast exceptions are ignored } } } @@ -137,7 +151,9 @@ public class EventRouter implements MethodEventSource { * Removes all listeners from event router. */ public void removeAllListeners() { - listenerList = null; + synchronized (listenerList) { + listenerList = null; + } } /** @@ -148,15 +164,15 @@ public class EventRouter implements MethodEventSource { * the Event to be sent to all listeners. */ public void fireEvent(EventObject event) { - // It is not necessary to send any events if there are no listeners if (listenerList != null) { - // Send the event to all listeners. The listeners themselves // will filter out unwanted events. - final Iterator i = new LinkedList(listenerList).iterator(); - while (i.hasNext()) { - ((ListenerMethod) i.next()).receiveEvent(event); + synchronized (listenerList) { + final Iterator i = listenerList.iterator(); + while (i.hasNext()) { + ((ListenerMethod) i.next()).receiveEvent(event); + } } } } diff --git a/src/com/itmill/toolkit/event/ListenerMethod.java b/src/com/itmill/toolkit/event/ListenerMethod.java index eaaf2a4e0f..8cf1d17c3e 100644 --- a/src/com/itmill/toolkit/event/ListenerMethod.java +++ b/src/com/itmill/toolkit/event/ListenerMethod.java @@ -5,6 +5,7 @@ package com.itmill.toolkit.event; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.EventListener; import java.util.EventObject; @@ -456,7 +457,7 @@ public class ListenerMethod implements EventListener { * by this listener. * @return true if target is the same object * as the one stored in this object and eventType - * equals the event type stored in this object. + * equals the event type stored in this object. * */ public boolean matches(Class eventType, Object target) { return (target == object) && (eventType.equals(this.eventType)); @@ -486,6 +487,41 @@ public class ListenerMethod implements EventListener { .equals(this.method)); } + public int hashCode() { + int hash = 7; + + hash = 31 * hash + eventArgumentIndex; + hash = 31 * hash + (eventType == null ? 0 : eventType.hashCode()); + hash = 31 * hash + (object == null ? 0 : object.hashCode()); + hash = 31 * hash + (method == null ? 0 : method.hashCode()); + hash = 31 * hash + (arguments == null ? 0 : Arrays.hashCode(arguments)); + + return hash; + } + + public boolean equals(Object obj) { + + if (this == obj) + return true; + + // return false if obj is a subclass (do not use instanceof check) + if ((obj == null) || (obj.getClass() != this.getClass())) + return false; + + // obj is of same class, test it further + ListenerMethod t = (ListenerMethod) obj; + + return eventArgumentIndex == t.eventArgumentIndex + && (eventType == t.eventType || (eventType != null && eventType + .equals(t.eventType))) + && (object == t.object || (object != null && object + .equals(t.object))) + && (method == t.method || (method != null && method + .equals(t.method))) + && (arguments == t.arguments || (Arrays.deepEquals(arguments, + t.arguments))); + } + /** * Exception that wraps an exception thrown by an invoked method. When * ListenerMethod invokes the target method, it may throw diff --git a/src/com/itmill/toolkit/ui/AbstractComponent.java b/src/com/itmill/toolkit/ui/AbstractComponent.java index dc305af320..23b7aa4934 100644 --- a/src/com/itmill/toolkit/ui/AbstractComponent.java +++ b/src/com/itmill/toolkit/ui/AbstractComponent.java @@ -822,6 +822,10 @@ public abstract class AbstractComponent implements Component, MethodEventSource * the object instance who owns the activation method. * @param methodName * the name of the activation method. + * @deprecated Use {@link #addListener(Class, Object, Method)} or + * {@link #addListener(com.itmill.toolkit.ui.Component.Listener)} + * instead. Using this method is discouraged because it cannot + * be checked during compilation. */ public void addListener(Class eventType, Object object, String methodName) { if (eventRouter == null) { -- 2.39.5