Revert "taverna-observer moved to taverna-engine (!)"
This reverts commit 7db92d5b4817762fc1a07c9bd396840920fffd46.
diff --git a/taverna-observer/pom.xml b/taverna-observer/pom.xml
new file mode 100644
index 0000000..5bf4236
--- /dev/null
+++ b/taverna-observer/pom.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>net.sf.taverna.t2.lang</groupId>
+ <artifactId>observer</artifactId>
+ <name>Observer pattern</name>
+ <parent>
+ <groupId>net.sf.taverna.t2</groupId>
+ <artifactId>lang</artifactId>
+ <version>1.6-SNAPSHOT</version>
+ </parent>
+ <description>Implementation of the Observer pattern.</description>
+ <dependencies>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/MultiCaster.java b/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/MultiCaster.java
new file mode 100644
index 0000000..d563e39
--- /dev/null
+++ b/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/MultiCaster.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.lang.observer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Send notifications to registered observers about changes to models
+ *
+ * @author Ian Dunlop
+ * @author Stian Soiland
+ *
+ * @param <Message>
+ */
+public class MultiCaster<Message> implements Observable<Message> {
+
+ private static Logger logger = Logger.getLogger(MultiCaster.class);
+
+ private Observable<Message> observable;
+
+ protected List<Observer<Message>> observers = new ArrayList<Observer<Message>>();
+
+ /**
+ * Set the {@link #observable} ie. the class that changes are happening to
+ * and it's Message for this {@link MultiCaster}
+ *
+ * @param observable
+ */
+ public MultiCaster(Observable<Message> observable) {
+ this.observable = observable;
+ }
+
+ /**
+ * Tell all the registered observers about the change to the model
+ *
+ * @param message
+ */
+ @SuppressWarnings("unchecked")
+ public void notify(Message message) {
+ // Use a copy that can be iterated even if register/remove is called
+ for (Observer<Message> observer : getObservers()) {
+ try {
+ observer.notify(observable, message);
+ } catch (Exception ex) {
+ logger.warn("Could not notify " + observer, ex);
+ }
+ }
+ }
+
+ /**
+ * Register an observer ie. someone who wants informed about changes
+ */
+ public synchronized void addObserver(Observer<Message> observer) {
+ observers.add(observer);
+ }
+
+ /**
+ * Remove the observer and no longer send out any notifications about it
+ */
+ public synchronized void removeObserver(Observer<Message> observer) {
+ observers.remove(observer);
+ }
+
+ /**
+ * A list of all the classes currently registered with this
+ * {@link MultiCaster}
+ */
+ public synchronized List<Observer<Message>> getObservers() {
+ return new ArrayList<Observer<Message>>(observers);
+ }
+
+}
diff --git a/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/Observable.java b/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/Observable.java
new file mode 100644
index 0000000..1fa7425
--- /dev/null
+++ b/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/Observable.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.lang.observer;
+
+import java.util.List;
+
+/**
+ * Implements this if you want to notify other classes about changes
+ *
+ * @author Ian Dunlop
+ * @author Stian Soiland
+ *
+ * @param <Message>
+ */
+public interface Observable<Message> {
+ /**
+ * Register an {@link Observer}
+ *
+ * @param observer
+ * the class who wants notified of changes
+ */
+ public void addObserver(Observer<Message> observer);
+
+ /**
+ * Remove a class who is currently observing
+ *
+ * @param observer
+ * the class who no longer wants notified
+ */
+ public void removeObserver(Observer<Message> observer);
+
+ /**
+ * A list of all the currently registered {@link Observer}s
+ *
+ * @return
+ */
+ public List<Observer<Message>> getObservers();
+}
diff --git a/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/Observer.java b/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/Observer.java
new file mode 100644
index 0000000..81b7c85
--- /dev/null
+++ b/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/Observer.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.lang.observer;
+
+/**
+ * Implement if you want to register with an {@link Observable}
+ *
+ * @author Ian Dunlop
+ * @author Stian Soiland
+ *
+ * @param <Message>
+ */
+public interface Observer<Message> {
+ /**
+ * Called by the {@link Observable} to notify the implementing class of
+ * changes
+ *
+ * @param sender
+ * the class where the changes have happened
+ * @param message
+ * what has changed
+ * @throws Exception
+ */
+ public void notify(Observable<Message> sender, Message message)
+ throws Exception;
+}
diff --git a/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/package-info.java b/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/package-info.java
new file mode 100644
index 0000000..e9d3ff2
--- /dev/null
+++ b/taverna-observer/src/main/java/net/sf/taverna/t2/lang/observer/package-info.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+/**
+ * Implementation of the observer pattern. {@link Observer}s registers with an
+ * {@link Observable} using {@link Observable#addObserver(Observer)}, and will receive
+ * notifications as a call to {@link Observer#notify(Observable, Object)}.
+ * <p>
+ * Typical implementations of {@link Observable} will be delegating to a
+ * {@link MultiCaster} to do the boring observer registration and message
+ * dispatching.
+ * </p>
+ * <p>
+ * Example of Observable:
+ * <pre>
+ * public class MyObservable implements Observable<MyEvent> {
+ * public static class MyEvent {
+ * // ..
+ * }
+ * private MultiCaster<:MyEvent> multiCaster = new MultiCaster<:MyEvent>(this);
+ *
+ * public void doStuff() {
+ * multiCaster.notify(new MyEvent());
+ * }
+ *
+ * public void addObserver(Observer<MyEvent> observer) {
+ * multiCaster.addObserver(observer);
+ * }
+ *
+ * public List<Observer<MyEvent>> getObservers() {
+ * return multiCaster.getObservers();
+ * }
+ *
+ * public void removeObserver(Observer<MyEvent> observer) {
+ * multiCaster.removeObserver(observer);
+ * }
+ * }
+ * </pre>
+ * And an observer that is notified when MyObservable.doStuff() is called:
+ * <pre>
+ * public class MyObserver implements Observer<MyEvent> {
+ * public void notify(Observable<MyEvent> sender, MyEvent message) {
+ * System.out.println("Receieved " + message + " from " + sender);
+ * }
+ * }
+ * </pre>
+ * Example of usage:
+ * <pre>
+ * MyObservable observable = new MyObservable();
+ * MyObserver observer = new MyObserver();
+ * observable.addObserver(observer);
+ * observable.doStuff();
+ * </pre>
+ */
+package net.sf.taverna.t2.lang.observer;
+
diff --git a/taverna-observer/src/test/java/net/sf/taverna/t2/lang/observer/ObserverTest.java b/taverna-observer/src/test/java/net/sf/taverna/t2/lang/observer/ObserverTest.java
new file mode 100644
index 0000000..661cbbc
--- /dev/null
+++ b/taverna-observer/src/test/java/net/sf/taverna/t2/lang/observer/ObserverTest.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.lang.observer;
+
+import static org.junit.Assert.*;
+
+import java.util.List;
+
+import net.sf.taverna.t2.lang.observer.MultiCaster;
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+
+import org.junit.Test;
+
+public class ObserverTest {
+
+ @Test
+ public void registerObserver() throws Exception {
+ MyObservable observable = new MyObservable();
+ MyObserver observer1 = new MyObserver();
+ MyObserver observer2 = new MyObserver();
+
+ observable.triggerEvent(); // don't notify, but increase count
+ assertNull(observer1.lastMessage);
+ observable.addObserver(observer1);
+ assertNull(observer1.lastMessage);
+ assertNull(observer2.lastMessage);
+ assertNull(observer1.lastSender);
+ assertNull(observer2.lastSender);
+ observable.triggerEvent();
+ assertEquals("This is message 1", observer1.lastMessage);
+ assertSame(observable, observer1.lastSender);
+ assertNull(observer2.lastSender);
+
+ observable.addObserver(observer2);
+ assertNull(observer2.lastMessage);
+ observable.triggerEvent();
+ assertEquals("This is message 2", observer1.lastMessage);
+ assertEquals("This is message 2", observer2.lastMessage);
+ assertSame(observable, observer1.lastSender);
+ assertSame(observable, observer2.lastSender);
+
+ MyObservable otherObservable = new MyObservable();
+ otherObservable.addObserver(observer2);
+ otherObservable.triggerEvent();
+ // New instance, should start from 0
+ assertEquals("This is message 0", observer2.lastMessage);
+ assertSame(otherObservable, observer2.lastSender);
+
+ // observer1 unchanged
+ assertEquals("This is message 2", observer1.lastMessage);
+ assertSame(observable, observer1.lastSender);
+
+ }
+
+ @Test
+ public void concurrencyTest() {
+ MyObservable observable = new MyObservable();
+ MyObserver dummyObserver = new MyObserver();
+ SelvRemovingObserver selfRemoving = new SelvRemovingObserver();
+ observable.addObserver(dummyObserver);
+ observable.addObserver(selfRemoving);
+ assertEquals(2, observable.getObservers().size());
+ observable.triggerEvent();
+
+
+ }
+
+ public class MyObservable implements Observable<String> {
+
+ private int counter = 0;
+ MultiCaster<String> multiCaster = new MultiCaster<String>(this);
+
+ public void addObserver(Observer<String> observer) {
+ multiCaster.addObserver(observer);
+ }
+
+ public void removeObserver(Observer<String> observer) {
+ multiCaster.removeObserver(observer);
+ }
+
+ public void triggerEvent() {
+ multiCaster.notify("This is message " + counter++);
+ }
+
+ public List<Observer<String>> getObservers() {
+ return multiCaster.getObservers();
+ }
+ }
+
+ public class MyObserver implements Observer<String> {
+ String lastMessage = null;
+ Observable<String> lastSender = null;
+
+ public void notify(Observable<String> sender, String message) {
+ lastSender = sender;
+ lastMessage = message;
+ }
+ }
+
+ public class SelvRemovingObserver implements Observer<String> {
+
+ public int called=0;
+
+ public void notify(Observable<String> sender, String message) {
+ called++;
+ if (called > 1) {
+ fail("Did not remove itself");
+ }
+ sender.removeObserver(this);
+ }
+
+ }
+
+}