From 3d262b8b82bf1e2868fad8aa64c7422276f3239f Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Mon, 31 May 2021 21:57:37 +0200 Subject: [PATCH] [DEV] add a real Signal interface --- src/org/atriasoft/esignal/Connection.java | 29 +++- .../esignal/ConnectionRemoveInterface.java | 5 + src/org/atriasoft/esignal/Signal.java | 141 +++++++++++++++--- 3 files changed, 149 insertions(+), 26 deletions(-) create mode 100644 src/org/atriasoft/esignal/ConnectionRemoveInterface.java diff --git a/src/org/atriasoft/esignal/Connection.java b/src/org/atriasoft/esignal/Connection.java index 1282723..68aec53 100644 --- a/src/org/atriasoft/esignal/Connection.java +++ b/src/org/atriasoft/esignal/Connection.java @@ -1,10 +1,31 @@ package org.atriasoft.esignal; -public class Connection { +import java.lang.ref.WeakReference; + +public class Connection implements AutoCloseable { + protected final WeakReference connection; public void disconnect() { - // TODO Auto-generated method stub - + close(); + } + + public Connection( final ConnectionRemoveInterface object ) { + this.connection = new WeakReference<>(object); + } + + public Connection() { + this.connection = null; + } + + @Override + public void close() { + if (this.connection == null) { + return; + } + ConnectionRemoveInterface tmp = this.connection.get(); + if (tmp == null) { + return; + } + tmp.disconnect(this); } - } diff --git a/src/org/atriasoft/esignal/ConnectionRemoveInterface.java b/src/org/atriasoft/esignal/ConnectionRemoveInterface.java new file mode 100644 index 0000000..fe80970 --- /dev/null +++ b/src/org/atriasoft/esignal/ConnectionRemoveInterface.java @@ -0,0 +1,5 @@ +package org.atriasoft.esignal; + +public interface ConnectionRemoveInterface { + void disconnect(final Connection connection); +} diff --git a/src/org/atriasoft/esignal/Signal.java b/src/org/atriasoft/esignal/Signal.java index 04af838..f637ebf 100644 --- a/src/org/atriasoft/esignal/Signal.java +++ b/src/org/atriasoft/esignal/Signal.java @@ -7,8 +7,8 @@ import java.util.List; import java.util.function.Consumer; class ConnectedElement { - private final Consumer consumer; - private final WeakReference reference; + protected final Consumer consumer; + protected final WeakReference reference; public ConnectedElement(final WeakReference reference, final Consumer consumer) { this.reference = reference; @@ -22,38 +22,135 @@ class ConnectedElement { public WeakReference getReference() { return this.reference; } + public Object getIfAlive() { + return this.reference.get(); + } + public boolean isCompatibleWith(final Object elem) { + Object out = this.reference.get(); + if (out == elem) { + return true; + } + return false; + } +} +class ConnectedElementDynamic extends ConnectedElement { + protected final WeakReference connection; + + public ConnectedElementDynamic(final WeakReference connection, final WeakReference reference, final Consumer consumer) { + super(reference, consumer); + this.connection = connection; + } + + public WeakReference getConnection() { + return this.connection; + } + + @Override + public Object getIfAlive() { + Object out = this.reference.get(); + if (out == null) { + return null; + } + Object outConnection = this.connection.get(); + if (outConnection == null) { + return null; + } + return out; + } + @Override + public boolean isCompatibleWith(final Object elem) { + if (super.isCompatibleWith(elem)) { + return true; + } + Object outConnection = this.connection.get(); + if (outConnection == elem) { + return true; + } + return false; + } } -public class Signal { - +public class Signal implements ConnectionRemoveInterface { List> data = new ArrayList<>(); - public void clear(final Object obj) { - + public void clear() { + synchronized(this.data) { + this.data = new ArrayList<>(); + } } - - public Connection connect(final Object reference, final T fucntion) { - - return null; + + public void connect(final Object reference, final Consumer function) { + synchronized(this.data) { + WeakReference weakRef = new WeakReference(reference); + this.data.add(new ConnectedElement(weakRef, function)); + } } - - public void disconnect(final Connection connection) { - - } - public void disconnect(final Object obj) { - + synchronized(this.data) { + final Iterator> iterator = this.data.iterator(); + while (iterator.hasNext()) { + final ConnectedElement elem = iterator.next(); + if (elem.isCompatibleWith(obj)) { + iterator.remove(); + } + } + } } + public Connection connectDynamic(final Object reference, final Consumer function) { + WeakReference weakRef = new WeakReference(reference); + Connection out = new Connection(this); + WeakReference weakConnection = new WeakReference(out); + synchronized(this.data) { + this.data.add(new ConnectedElementDynamic(weakConnection, weakRef, function)); + } + return out; + } + + @Override + public void disconnect(final Connection connection) { + synchronized(this.data) { + final Iterator> iterator = this.data.iterator(); + while (iterator.hasNext()) { + final ConnectedElement elem = iterator.next(); + if (elem.isCompatibleWith(connection)) { + iterator.remove(); + } + } + } + } + public void emit(final T value) { - final Iterator> iterator = this.data.iterator(); - while (iterator.hasNext()) { - final ConnectedElement elem = iterator.next(); - if (elem.getReference().get() == null) { - iterator.remove(); + List> tmp; + // clean the list: + synchronized(this.data) { + final Iterator> iterator = this.data.iterator(); + while (iterator.hasNext()) { + final ConnectedElement elem = iterator.next(); + Object tmpObject = elem.getIfAlive(); + if (tmpObject == null) { + iterator.remove(); + } + } + // simple optimization: + if (this.data.isEmpty()) { + return; + } + // clone the list to permit to have asynchronous remove call + tmp = new ArrayList<>(this.data); + } + // real call elements + { + final Iterator> iterator = tmp.iterator(); + while (iterator.hasNext()) { + final ConnectedElement elem = iterator.next(); + Object tmpObject = elem.getIfAlive(); + if (tmpObject == null) { + continue; + } + elem.getConsumer().accept(value); } - elem.getConsumer().accept(value); } }