[DEV] add a real Signal interface

This commit is contained in:
Edouard DUPIN 2021-05-31 21:57:37 +02:00
parent ff07d48196
commit 3d262b8b82
3 changed files with 149 additions and 26 deletions

View File

@ -1,10 +1,31 @@
package org.atriasoft.esignal; package org.atriasoft.esignal;
public class Connection { import java.lang.ref.WeakReference;
public class Connection implements AutoCloseable {
protected final WeakReference<ConnectionRemoveInterface> connection;
public void disconnect() { 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);
}
} }

View File

@ -0,0 +1,5 @@
package org.atriasoft.esignal;
public interface ConnectionRemoveInterface {
void disconnect(final Connection connection);
}

View File

@ -7,8 +7,8 @@ import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
class ConnectedElement<T> { class ConnectedElement<T> {
private final Consumer<T> consumer; protected final Consumer<T> consumer;
private final WeakReference<Object> reference; protected final WeakReference<Object> reference;
public ConnectedElement(final WeakReference<Object> reference, final Consumer<T> consumer) { public ConnectedElement(final WeakReference<Object> reference, final Consumer<T> consumer) {
this.reference = reference; this.reference = reference;
@ -22,40 +22,137 @@ class ConnectedElement<T> {
public WeakReference<Object> getReference() { public WeakReference<Object> getReference() {
return this.reference; 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<T> extends ConnectedElement<T> {
protected final WeakReference<Connection> connection;
public ConnectedElementDynamic(final WeakReference<Connection> connection, final WeakReference<Object> reference, final Consumer<T> consumer) {
super(reference, consumer);
this.connection = connection;
}
public WeakReference<Connection> 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<T> { public class Signal<T> implements ConnectionRemoveInterface {
List<ConnectedElement<T>> data = new ArrayList<>(); List<ConnectedElement<T>> 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) { public void connect(final Object reference, final Consumer<T> function) {
synchronized(this.data) {
return null; WeakReference<Object> weakRef = new WeakReference<Object>(reference);
this.data.add(new ConnectedElement<T>(weakRef, function));
} }
public void disconnect(final Connection connection) {
} }
public void disconnect(final Object obj) { public void disconnect(final Object obj) {
synchronized(this.data) {
}
public void emit(final T value) {
final Iterator<ConnectedElement<T>> iterator = this.data.iterator(); final Iterator<ConnectedElement<T>> iterator = this.data.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
final ConnectedElement<T> elem = iterator.next(); final ConnectedElement<T> elem = iterator.next();
if (elem.getReference().get() == null) { if (elem.isCompatibleWith(obj)) {
iterator.remove(); iterator.remove();
} }
}
}
}
public Connection connectDynamic(final Object reference, final Consumer<T> function) {
WeakReference<Object> weakRef = new WeakReference<Object>(reference);
Connection out = new Connection(this);
WeakReference<Connection> weakConnection = new WeakReference<Connection>(out);
synchronized(this.data) {
this.data.add(new ConnectedElementDynamic<T>(weakConnection, weakRef, function));
}
return out;
}
@Override
public void disconnect(final Connection connection) {
synchronized(this.data) {
final Iterator<ConnectedElement<T>> iterator = this.data.iterator();
while (iterator.hasNext()) {
final ConnectedElement<T> elem = iterator.next();
if (elem.isCompatibleWith(connection)) {
iterator.remove();
}
}
}
}
public void emit(final T value) {
List<ConnectedElement<T>> tmp;
// clean the list:
synchronized(this.data) {
final Iterator<ConnectedElement<T>> iterator = this.data.iterator();
while (iterator.hasNext()) {
final ConnectedElement<T> 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<ConnectedElement<T>> iterator = tmp.iterator();
while (iterator.hasNext()) {
final ConnectedElement<T> elem = iterator.next();
Object tmpObject = elem.getIfAlive();
if (tmpObject == null) {
continue;
}
elem.getConsumer().accept(value); elem.getConsumer().accept(value);
} }
} }
}
public int size() { public int size() {
return this.data.size(); return this.data.size();