summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Pingel2012-02-23 18:01:34 (EST)
committerSteffen Pingel2012-02-23 18:20:26 (EST)
commita847c34384fe171d9dcadcbc34b50e58579a8889 (patch)
tree581cf4ebfa62ca1e891505e198dae5d27a398cc5
parentbbe877f0a30365cb7662ef4bbbd8265befd96619 (diff)
downloadorg.eclipse.mylyn.commons-a847c34384fe171d9dcadcbc34b50e58579a8889.zip
org.eclipse.mylyn.commons-a847c34384fe171d9dcadcbc34b50e58579a8889.tar.gz
org.eclipse.mylyn.commons-a847c34384fe171d9dcadcbc34b50e58579a8889.tar.bz2
NEW - bug 372432: [api] provide a generic list for managing listeners
https://bugs.eclipse.org/bugs/show_bug.cgi?id=372432 Change-Id: I6671363039aae57826a1537ab5d6ef6479c1f959
-rw-r--r--org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/CommonListenerList.java106
-rw-r--r--org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java2
-rw-r--r--org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/CommonListenerListTest.java110
3 files changed, 218 insertions, 0 deletions
diff --git a/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/CommonListenerList.java b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/CommonListenerList.java
new file mode 100644
index 0000000..2138160
--- /dev/null
+++ b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/CommonListenerList.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.core;
+
+import java.util.Iterator;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * A list like class for managing listeners. It is safe to call this class from different threads concurrently.
+ *
+ * @since 3.7
+ */
+public class CommonListenerList<T> implements Iterable<T> {
+
+ /**
+ * Subclasses should extend to not
+ */
+ public static abstract class Notifier<T> {
+
+ /**
+ * Fires an event to <code>listener</code>.
+ *
+ * @param listener
+ * the listener to be notified
+ * @throws Exception
+ * indicates a unrecoverable problem with <code>listener</code>
+ */
+ public abstract void run(T listener) throws Exception;
+
+ }
+
+ private final CopyOnWriteArrayList<T> listeners;
+
+ private final String pluginId;
+
+ /**
+ * Constructs an empty list.
+ *
+ * @param pluginId
+ * the ID of the bundle that is managing this instance
+ */
+ public CommonListenerList(String pluginId) {
+ Assert.isNotNull(pluginId);
+ this.pluginId = pluginId;
+ this.listeners = new CopyOnWriteArrayList<T>();
+ }
+
+ /**
+ * Adds <code>listener</code> to the list of listeners.
+ */
+ public void add(T listener) {
+ Assert.isNotNull(listener);
+ listeners.addIfAbsent(listener);
+ }
+
+ /**
+ * Iterates over the list of listeners.
+ */
+ public Iterator<T> iterator() {
+ return listeners.iterator();
+ }
+
+ /**
+ * Invokes <code>runnable</code> for each listener. If {@link Notifier#run(Object)} throws an exception the
+ * corresponding listener is removed from the list and a message is logged.
+ */
+ public void notify(final Notifier<T> runnable) {
+ for (final T listener : listeners) {
+ SafeRunner.run(new ISafeRunnable() {
+ public void handleException(Throwable e) {
+ StatusHandler.log(new Status(IStatus.ERROR, pluginId, NLS.bind(
+ "Unexpected error notifying listener {0}", listener.getClass()), e)); //$NON-NLS-1$
+ remove(listener);
+ }
+
+ public void run() throws Exception {
+ runnable.run(listener);
+ }
+ });
+ }
+ }
+
+ /**
+ * Removes <code>listener</code> to the list of listeners.
+ */
+ public void remove(T listener) {
+ listeners.remove(listener);
+ }
+
+}
diff --git a/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java
index 720f47a..1f4210d 100644
--- a/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java
+++ b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/AllCommonsTests.java
@@ -15,6 +15,7 @@ import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.mylyn.commons.tests.core.AuthenticatedProxyTest;
+import org.eclipse.mylyn.commons.tests.core.CommonListenerListTest;
import org.eclipse.mylyn.commons.tests.core.CoreUtilTest;
import org.eclipse.mylyn.commons.tests.core.ExtensionPointReaderTest;
import org.eclipse.mylyn.commons.tests.net.NetUtilTest;
@@ -40,6 +41,7 @@ public class AllCommonsTests {
suite.addTestSuite(TimeoutInputStreamTest.class);
suite.addTestSuite(BrowserUtilTest.class);
suite.addTestSuite(ExtensionPointReaderTest.class);
+ suite.addTestSuite(CommonListenerListTest.class);
return suite;
}
diff --git a/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/CommonListenerListTest.java b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/CommonListenerListTest.java
new file mode 100644
index 0000000..28704fb
--- /dev/null
+++ b/org.eclipse.mylyn.commons.tests/src/org/eclipse/mylyn/commons/tests/core/CommonListenerListTest.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Tasktop Technologies and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.tests.core;
+
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+import org.eclipse.mylyn.commons.core.CommonListenerList;
+import org.eclipse.mylyn.commons.core.CommonListenerList.Notifier;
+
+/**
+ * @author Steffen Pingel
+ */
+public class CommonListenerListTest extends TestCase {
+
+ private class Listener {
+
+ private boolean notified;
+
+ }
+
+ public void testAddRemove() {
+ final Listener addedListener = new Listener();
+ CommonListenerList<Listener> list = new CommonListenerList<Listener>("a");
+
+ list.add(addedListener);
+ assertTrue(list.iterator().hasNext());
+ assertSame(addedListener, list.iterator().next());
+
+ list.remove(addedListener);
+ assertFalse(list.iterator().hasNext());
+ }
+
+ public void testAddTwice() {
+ final Listener addedListener = new Listener();
+ CommonListenerList<Listener> list = new CommonListenerList<Listener>("a");
+ list.add(addedListener);
+ list.add(addedListener);
+
+ Iterator<Listener> iterator = list.iterator();
+ assertTrue(iterator.hasNext());
+ iterator.next();
+ assertFalse(iterator.hasNext());
+ }
+
+ public void testIterator() {
+ final Listener listener1 = new Listener();
+ final Listener listener2 = new Listener();
+ final Listener listener3 = new Listener();
+ CommonListenerList<Listener> list = new CommonListenerList<Listener>("a");
+ list.add(listener1);
+ list.add(listener2);
+ list.add(listener3);
+ list.add(listener1);
+
+ Iterator<Listener> iterator = list.iterator();
+ assertSame(listener1, iterator.next());
+ assertSame(listener2, iterator.next());
+ assertSame(listener3, iterator.next());
+ }
+
+ public void testNotify() {
+ final Listener addedListener = new Listener();
+ CommonListenerList<Listener> list = new CommonListenerList<Listener>("a");
+ list.add(addedListener);
+
+ list.notify(new Notifier<Listener>() {
+ @Override
+ public void run(Listener listener) throws Exception {
+ assertSame(listener, addedListener);
+ addedListener.notified = true;
+ }
+ });
+ assertTrue(addedListener.notified);
+ }
+
+ public void testNotifyException() {
+ final Listener addedListener = new Listener();
+ CommonListenerList<Listener> list = new CommonListenerList<Listener>("a");
+ list.add(addedListener);
+
+ list.notify(new Notifier<Listener>() {
+ @Override
+ public void run(Listener listener) throws Exception {
+ // should cause listener to get removed
+ throw new LinkageError();
+ }
+ });
+ assertFalse(list.iterator().hasNext());
+
+ list.notify(new Notifier<Listener>() {
+ @Override
+ public void run(Listener listener) throws Exception {
+ addedListener.notified = true;
+ }
+ });
+ assertFalse(addedListener.notified);
+ }
+
+}