diff --git a/briar-api/src/net/sf/briar/api/transport/ConnectionListener.java b/briar-api/src/net/sf/briar/api/transport/ConnectionListener.java new file mode 100644 index 0000000000000000000000000000000000000000..0d9a027c8bc6f0a7fc312f89ecc6f2854c1abdf6 --- /dev/null +++ b/briar-api/src/net/sf/briar/api/transport/ConnectionListener.java @@ -0,0 +1,13 @@ +package net.sf.briar.api.transport; + +import net.sf.briar.api.ContactId; + +/** An interface for listening for connection and disconnection events. */ +public interface ConnectionListener { + + /** Called when a contact connects and has no existing connections. */ + void contactConnected(ContactId c); + + /** Called when a contact disconnects and has no remaining connections. */ + void contactDisconnected(ContactId c); +} diff --git a/briar-api/src/net/sf/briar/api/transport/ConnectionRegistry.java b/briar-api/src/net/sf/briar/api/transport/ConnectionRegistry.java index 2983fff39cc0dc50fd82dcefc9b01b123167956b..fd3759613a59aa1b5d1888da01bd7c7d79cd2992 100644 --- a/briar-api/src/net/sf/briar/api/transport/ConnectionRegistry.java +++ b/briar-api/src/net/sf/briar/api/transport/ConnectionRegistry.java @@ -10,9 +10,15 @@ import net.sf.briar.api.messaging.TransportId; */ public interface ConnectionRegistry { + void addListener(ConnectionListener c); + + void removeListener(ConnectionListener c); + void registerConnection(ContactId c, TransportId t); void unregisterConnection(ContactId c, TransportId t); Collection<ContactId> getConnectedContacts(TransportId t); + + boolean isConnected(ContactId c); } diff --git a/briar-core/src/net/sf/briar/transport/ConnectionRegistryImpl.java b/briar-core/src/net/sf/briar/transport/ConnectionRegistryImpl.java index ffa0c2c97bf549931314cb5daf7729061b30760c..d1a5b48a64126977fcb5207fe89abd3221a99844 100644 --- a/briar-core/src/net/sf/briar/transport/ConnectionRegistryImpl.java +++ b/briar-core/src/net/sf/briar/transport/ConnectionRegistryImpl.java @@ -6,41 +6,81 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; import net.sf.briar.api.ContactId; import net.sf.briar.api.messaging.TransportId; +import net.sf.briar.api.transport.ConnectionListener; import net.sf.briar.api.transport.ConnectionRegistry; class ConnectionRegistryImpl implements ConnectionRegistry { // Locking: this private final Map<TransportId, Map<ContactId, Integer>> connections; + // Locking: this + private final Map<ContactId, Integer> contactCounts; + private final List<ConnectionListener> listeners; ConnectionRegistryImpl() { connections = new HashMap<TransportId, Map<ContactId, Integer>>(); + contactCounts = new HashMap<ContactId, Integer>(); + listeners = new CopyOnWriteArrayList<ConnectionListener>(); } - public synchronized void registerConnection(ContactId c, TransportId t) { - Map<ContactId, Integer> m = connections.get(t); - if(m == null) { - m = new HashMap<ContactId, Integer>(); - connections.put(t, m); + public void addListener(ConnectionListener c) { + listeners.add(c); + } + + public void removeListener(ConnectionListener c) { + listeners.remove(c); + } + + public void registerConnection(ContactId c, TransportId t) { + boolean firstConnection = false; + synchronized(this) { + Map<ContactId, Integer> m = connections.get(t); + if(m == null) { + m = new HashMap<ContactId, Integer>(); + connections.put(t, m); + } + Integer count = m.get(c); + if(count == null) m.put(c, 1); + else m.put(c, count + 1); + count = contactCounts.get(c); + if(count == null) { + firstConnection = true; + contactCounts.put(c, 1); + } else { + contactCounts.put(c, count + 1); + } } - Integer count = m.get(c); - if(count == null) m.put(c, 1); - else m.put(c, count + 1); + if(firstConnection) + for(ConnectionListener l : listeners) l.contactConnected(c); } - public synchronized void unregisterConnection(ContactId c, TransportId t) { - Map<ContactId, Integer> m = connections.get(t); - if(m == null) throw new IllegalArgumentException(); - Integer count = m.remove(c); - if(count == null) throw new IllegalArgumentException(); - if(count == 1) { - if(m.isEmpty()) connections.remove(t); - } else { - m.put(c, count - 1); + public void unregisterConnection(ContactId c, TransportId t) { + boolean lastConnection = false; + synchronized(this) { + Map<ContactId, Integer> m = connections.get(t); + if(m == null) throw new IllegalArgumentException(); + Integer count = m.remove(c); + if(count == null) throw new IllegalArgumentException(); + if(count == 1) { + if(m.isEmpty()) connections.remove(t); + } else { + m.put(c, count - 1); + } + count = contactCounts.get(c); + if(count == null) throw new IllegalArgumentException(); + if(count == 1) { + lastConnection = true; + contactCounts.remove(c); + } else { + contactCounts.put(c, count - 1); + } } + if(lastConnection) + for(ConnectionListener l : listeners) l.contactDisconnected(c); } public synchronized Collection<ContactId> getConnectedContacts( @@ -50,4 +90,8 @@ class ConnectionRegistryImpl implements ConnectionRegistry { List<ContactId> keys = new ArrayList<ContactId>(m.keySet()); return Collections.unmodifiableList(keys); } + + public synchronized boolean isConnected(ContactId c) { + return contactCounts.containsKey(c); + } }