mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Listeners for subscription changes.
This commit is contained in:
@@ -48,11 +48,11 @@ public interface DatabaseComponent {
|
||||
/** Waits for any open transactions to finish and closes the database. */
|
||||
void close() throws DbException;
|
||||
|
||||
/** Adds a listener to be notified when new messages are available. */
|
||||
void addListener(MessageListener m);
|
||||
/** Adds a listener to be notified when database events occur. */
|
||||
void addListener(DatabaseListener d);
|
||||
|
||||
/** Removes a listener. */
|
||||
void removeListener(MessageListener m);
|
||||
void removeListener(DatabaseListener d);
|
||||
|
||||
/**
|
||||
* Adds a new contact to the database with the given transport details and
|
||||
|
||||
13
api/net/sf/briar/api/db/DatabaseListener.java
Normal file
13
api/net/sf/briar/api/db/DatabaseListener.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.sf.briar.api.db;
|
||||
|
||||
/** An interface for receiving notifications when database events occur. */
|
||||
public interface DatabaseListener {
|
||||
|
||||
static enum Event {
|
||||
MESSAGES_ADDED,
|
||||
SUBSCRIPTIONS_UPDATED,
|
||||
TRANSPORTS_UPDATED
|
||||
};
|
||||
|
||||
void eventOccurred(Event e);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.sf.briar.api.db;
|
||||
|
||||
/**
|
||||
* An interface for receiving notifications when the database may have new
|
||||
* messages available.
|
||||
*/
|
||||
public interface MessageListener {
|
||||
|
||||
void messagesAdded();
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.Rating;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.MessageListener;
|
||||
import net.sf.briar.api.db.DatabaseListener;
|
||||
import net.sf.briar.api.db.Status;
|
||||
import net.sf.briar.api.protocol.AuthorId;
|
||||
import net.sf.briar.api.protocol.Message;
|
||||
@@ -29,8 +29,8 @@ DatabaseCleaner.Callback {
|
||||
protected final Database<Txn> db;
|
||||
protected final DatabaseCleaner cleaner;
|
||||
|
||||
private final List<MessageListener> listeners =
|
||||
new ArrayList<MessageListener>(); // Locking: self
|
||||
private final List<DatabaseListener> listeners =
|
||||
new ArrayList<DatabaseListener>(); // Locking: self
|
||||
private final Object spaceLock = new Object();
|
||||
private final Object writeLock = new Object();
|
||||
private long bytesStoredSinceLastCheck = 0L; // Locking: spaceLock
|
||||
@@ -47,15 +47,15 @@ DatabaseCleaner.Callback {
|
||||
cleaner.startCleaning();
|
||||
}
|
||||
|
||||
public void addListener(MessageListener m) {
|
||||
public void addListener(DatabaseListener d) {
|
||||
synchronized(listeners) {
|
||||
listeners.add(m);
|
||||
listeners.add(d);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(MessageListener m) {
|
||||
public void removeListener(DatabaseListener d) {
|
||||
synchronized(listeners) {
|
||||
listeners.remove(m);
|
||||
listeners.remove(d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,13 +80,13 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
|
||||
/** Notifies all MessageListeners that new messages may be available. */
|
||||
protected void callMessageListeners() {
|
||||
protected void callListeners(DatabaseListener.Event e) {
|
||||
synchronized(listeners) {
|
||||
if(!listeners.isEmpty()) {
|
||||
// Shuffle the listeners so we don't always send new messages
|
||||
// Shuffle the listeners so we don't always send new packets
|
||||
// to contacts in the same order
|
||||
Collections.shuffle(listeners);
|
||||
for(MessageListener m : listeners) m.messagesAdded();
|
||||
for(DatabaseListener d : listeners) d.eventOccurred(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.Rating;
|
||||
import net.sf.briar.api.db.DatabaseListener;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.NoSuchContactException;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
@@ -193,7 +194,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
contactLock.readLock().unlock();
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(added) callMessageListeners();
|
||||
if(added) callListeners(DatabaseListener.Event.MESSAGES_ADDED);
|
||||
}
|
||||
|
||||
public void findLostBatches(ContactId c) throws DbException {
|
||||
@@ -742,7 +743,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
contactLock.readLock().unlock();
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(anyAdded) callMessageListeners();
|
||||
if(anyAdded) callListeners(DatabaseListener.Event.MESSAGES_ADDED);
|
||||
}
|
||||
|
||||
public void receiveOffer(ContactId c, Offer o, RequestWriter r)
|
||||
@@ -931,11 +932,15 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
|
||||
public void subscribe(Group g) throws DbException {
|
||||
if(LOG.isLoggable(Level.FINE)) LOG.fine("Subscribing to " + g);
|
||||
boolean added = false;
|
||||
subscriptionLock.writeLock().lock();
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
try {
|
||||
db.addSubscription(txn, g);
|
||||
if(!db.containsSubscription(txn, g.getId())) {
|
||||
db.addSubscription(txn, g);
|
||||
added = true;
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
@@ -944,10 +949,13 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
} finally {
|
||||
subscriptionLock.writeLock().unlock();
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(added) callListeners(DatabaseListener.Event.SUBSCRIPTIONS_UPDATED);
|
||||
}
|
||||
|
||||
public void unsubscribe(GroupId g) throws DbException {
|
||||
if(LOG.isLoggable(Level.FINE)) LOG.fine("Unsubscribing from " + g);
|
||||
boolean removed = false;
|
||||
contactLock.readLock().lock();
|
||||
try {
|
||||
messageLock.writeLock().lock();
|
||||
@@ -958,7 +966,10 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
try {
|
||||
Txn txn = db.startTransaction();
|
||||
try {
|
||||
db.removeSubscription(txn, g);
|
||||
if(db.containsSubscription(txn, g)) {
|
||||
db.removeSubscription(txn, g);
|
||||
removed = true;
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
@@ -976,5 +987,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
} finally {
|
||||
contactLock.readLock().unlock();
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(removed) callListeners(DatabaseListener.Event.SUBSCRIPTIONS_UPDATED);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import java.util.logging.Logger;
|
||||
|
||||
import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.Rating;
|
||||
import net.sf.briar.api.db.DatabaseListener;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.NoSuchContactException;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
@@ -146,7 +147,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
}
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(added) callMessageListeners();
|
||||
if(added) callListeners(DatabaseListener.Event.MESSAGES_ADDED);
|
||||
}
|
||||
|
||||
public void findLostBatches(ContactId c) throws DbException {
|
||||
@@ -550,7 +551,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
}
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(anyAdded) callMessageListeners();
|
||||
if(anyAdded) callListeners(DatabaseListener.Event.MESSAGES_ADDED);
|
||||
}
|
||||
|
||||
public void receiveOffer(ContactId c, Offer o, RequestWriter r)
|
||||
@@ -691,27 +692,37 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
|
||||
public void subscribe(Group g) throws DbException {
|
||||
if(LOG.isLoggable(Level.FINE)) LOG.fine("Subscribing to " + g);
|
||||
boolean added = false;
|
||||
synchronized(subscriptionLock) {
|
||||
Txn txn = db.startTransaction();
|
||||
try {
|
||||
db.addSubscription(txn, g);
|
||||
if(!db.containsSubscription(txn, g.getId())) {
|
||||
db.addSubscription(txn, g);
|
||||
added = true;
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(added) callListeners(DatabaseListener.Event.SUBSCRIPTIONS_UPDATED);
|
||||
}
|
||||
|
||||
public void unsubscribe(GroupId g) throws DbException {
|
||||
if(LOG.isLoggable(Level.FINE)) LOG.fine("Unsubscribing from " + g);
|
||||
boolean removed = false;
|
||||
synchronized(contactLock) {
|
||||
synchronized(messageLock) {
|
||||
synchronized(messageStatusLock) {
|
||||
synchronized(subscriptionLock) {
|
||||
Txn txn = db.startTransaction();
|
||||
try {
|
||||
db.removeSubscription(txn, g);
|
||||
if(db.containsSubscription(txn, g)) {
|
||||
db.removeSubscription(txn, g);
|
||||
removed = true;
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
@@ -721,5 +732,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Call the listeners outside the lock
|
||||
if(removed) callListeners(DatabaseListener.Event.SUBSCRIPTIONS_UPDATED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import net.sf.briar.api.ContactId;
|
||||
import net.sf.briar.api.Rating;
|
||||
import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.MessageListener;
|
||||
import net.sf.briar.api.db.DatabaseListener;
|
||||
import net.sf.briar.api.db.NoSuchContactException;
|
||||
import net.sf.briar.api.db.Status;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
@@ -81,7 +81,7 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
final Database<Object> database = context.mock(Database.class);
|
||||
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
|
||||
final Group group = context.mock(Group.class);
|
||||
final MessageListener listener = context.mock(MessageListener.class);
|
||||
final DatabaseListener listener = context.mock(DatabaseListener.class);
|
||||
context.checking(new Expectations() {{
|
||||
allowing(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -104,12 +104,22 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
oneOf(database).getTransports(txn, contactId);
|
||||
will(returnValue(transports));
|
||||
// subscribe(group)
|
||||
oneOf(group).getId();
|
||||
will(returnValue(groupId));
|
||||
oneOf(database).containsSubscription(txn, groupId);
|
||||
will(returnValue(false));
|
||||
oneOf(database).addSubscription(txn, group);
|
||||
oneOf(listener).eventOccurred(
|
||||
DatabaseListener.Event.SUBSCRIPTIONS_UPDATED);
|
||||
// getSubscriptions()
|
||||
oneOf(database).getSubscriptions(txn);
|
||||
will(returnValue(Collections.singletonList(groupId)));
|
||||
// unsubscribe(groupId)
|
||||
oneOf(database).containsSubscription(txn, groupId);
|
||||
will(returnValue(true));
|
||||
oneOf(database).removeSubscription(txn, groupId);
|
||||
oneOf(listener).eventOccurred(
|
||||
DatabaseListener.Event.SUBSCRIPTIONS_UPDATED);
|
||||
// removeContact(contactId)
|
||||
oneOf(database).removeContact(txn, contactId);
|
||||
// close()
|
||||
@@ -1035,7 +1045,7 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Database<Object> database = context.mock(Database.class);
|
||||
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
|
||||
final MessageListener listener = context.mock(MessageListener.class);
|
||||
final DatabaseListener listener = context.mock(DatabaseListener.class);
|
||||
context.checking(new Expectations() {{
|
||||
// addLocallyGeneratedMessage(message)
|
||||
oneOf(database).startTransaction();
|
||||
@@ -1054,7 +1064,8 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
oneOf(database).setSendability(txn, messageId, 0);
|
||||
oneOf(database).commitTransaction(txn);
|
||||
// The message was added, so the listener should be called
|
||||
oneOf(listener).messagesAdded();
|
||||
oneOf(listener).eventOccurred(
|
||||
DatabaseListener.Event.MESSAGES_ADDED);
|
||||
}});
|
||||
DatabaseComponent db = createDatabaseComponent(database, cleaner);
|
||||
|
||||
@@ -1070,7 +1081,7 @@ public abstract class DatabaseComponentTest extends TestCase {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Database<Object> database = context.mock(Database.class);
|
||||
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
|
||||
final MessageListener listener = context.mock(MessageListener.class);
|
||||
final DatabaseListener listener = context.mock(DatabaseListener.class);
|
||||
context.checking(new Expectations() {{
|
||||
// addLocallyGeneratedMessage(message)
|
||||
oneOf(database).startTransaction();
|
||||
|
||||
Reference in New Issue
Block a user