mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-21 15:19:53 +01:00
Attach the affected contact IDs to subscription update events.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package net.sf.briar.api.db.event;
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
/** An event that is broadcast when a batch of messages is received. */
|
||||||
public class BatchReceivedEvent extends DatabaseEvent {
|
public class BatchReceivedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.sf.briar.api.db.event;
|
|||||||
|
|
||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
|
|
||||||
|
/** An event that is broadcast when a contact is added. */
|
||||||
public class ContactAddedEvent extends DatabaseEvent {
|
public class ContactAddedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package net.sf.briar.api.db.event;
|
|||||||
|
|
||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
|
|
||||||
|
/** An event that is broadcast when a contact is removed. */
|
||||||
public class ContactRemovedEvent extends ContactAddedEvent {
|
public class ContactRemovedEvent extends ContactAddedEvent {
|
||||||
|
|
||||||
public ContactRemovedEvent(ContactId contactId) {
|
public ContactRemovedEvent(ContactId contactId) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.sf.briar.api.db.event;
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
/** An abstract superclass for database events. */
|
||||||
public abstract class DatabaseEvent {
|
public abstract class DatabaseEvent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package net.sf.briar.api.db.event;
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
|
||||||
/** An interface for receiving notifications when database events occur. */
|
/** An interface for receiving notifications when database events occur. */
|
||||||
public interface DatabaseListener {
|
public interface DatabaseListener {
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package net.sf.briar.api.db.event;
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is broadcast when one or more messages are added to the
|
||||||
|
* database.
|
||||||
|
*/
|
||||||
public class MessagesAddedEvent extends DatabaseEvent {
|
public class MessagesAddedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,27 @@
|
|||||||
package net.sf.briar.api.db.event;
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is broadcast when the set of subscriptions visible to one or
|
||||||
|
* more contacts is updated.
|
||||||
|
*/
|
||||||
public class SubscriptionsUpdatedEvent extends DatabaseEvent {
|
public class SubscriptionsUpdatedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
private final Collection<ContactId> affectedContacts;
|
private final Collection<ContactId> affectedContacts;
|
||||||
|
|
||||||
// FIXME: Replace this constructor
|
|
||||||
public SubscriptionsUpdatedEvent() {
|
public SubscriptionsUpdatedEvent() {
|
||||||
affectedContacts = null;
|
affectedContacts = Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SubscriptionsUpdatedEvent(Collection<ContactId> affectedContacts) {
|
||||||
|
this.affectedContacts = affectedContacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the contacts affected by the update. */
|
||||||
public Collection<ContactId> getAffectedContacts() {
|
public Collection<ContactId> getAffectedContacts() {
|
||||||
return affectedContacts;
|
return affectedContacts;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.sf.briar.api.db.event;
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
/** An event that is broadcast when the local transports are updated. */
|
||||||
public class TransportsUpdatedEvent extends DatabaseEvent {
|
public class TransportsUpdatedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,11 +116,12 @@ interface Database<T> {
|
|||||||
boolean addPrivateMessage(T txn, Message m, ContactId c) throws DbException;
|
boolean addPrivateMessage(T txn, Message m, ContactId c) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to the given group.
|
* Subscribes to the given group and returns true if the subscription did
|
||||||
|
* not previously exist.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: subscriptions write.
|
* Locking: subscriptions write.
|
||||||
*/
|
*/
|
||||||
void addSubscription(T txn, Group g) throws DbException;
|
boolean addSubscription(T txn, Group g) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the database contains the given contact.
|
* Returns true if the database contains the given contact.
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -1277,19 +1278,19 @@ DatabaseCleaner.Callback {
|
|||||||
|
|
||||||
public void setVisibility(GroupId g, Collection<ContactId> visible)
|
public void setVisibility(GroupId g, Collection<ContactId> visible)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
Collection<ContactId> then, now;
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
subscriptionLock.writeLock().lock();
|
subscriptionLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
// Remove any ex-contacts from the set
|
// Get the contacts to which the group used to be visible
|
||||||
Collection<ContactId> present =
|
then = new HashSet<ContactId>(db.getVisibility(txn, g));
|
||||||
new ArrayList<ContactId>(visible.size());
|
// Don't try to make the group visible to ex-contacts
|
||||||
for(ContactId c : visible) {
|
now = new HashSet<ContactId>(visible);
|
||||||
if(db.containsContact(txn, c)) present.add(c);
|
now.retainAll(new HashSet<ContactId>(db.getContacts(txn)));
|
||||||
}
|
db.setVisibility(txn, g, now);
|
||||||
db.setVisibility(txn, g, present);
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
@@ -1301,19 +1302,22 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
|
// Work out which contacts were affected by the change
|
||||||
|
Collection<ContactId> affected = new ArrayList<ContactId>();
|
||||||
|
for(ContactId c : then) if(!now.contains(c)) affected.add(c);
|
||||||
|
for(ContactId c : now) if(!then.contains(c)) affected.add(c);
|
||||||
|
// Call the listeners outside the lock
|
||||||
|
callListeners(new SubscriptionsUpdatedEvent(affected));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void subscribe(Group g) throws DbException {
|
public void subscribe(Group g) throws DbException {
|
||||||
if(LOG.isLoggable(Level.FINE)) LOG.fine("Subscribing to " + g);
|
if(LOG.isLoggable(Level.FINE)) LOG.fine("Subscribing to " + g);
|
||||||
boolean added = false;
|
boolean added;
|
||||||
subscriptionLock.writeLock().lock();
|
subscriptionLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
if(db.containsSubscription(txn, g.getId())) {
|
added = db.addSubscription(txn, g);
|
||||||
db.addSubscription(txn, g);
|
|
||||||
added = true;
|
|
||||||
}
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
@@ -1328,7 +1332,8 @@ DatabaseCleaner.Callback {
|
|||||||
|
|
||||||
public void unsubscribe(GroupId g) throws DbException {
|
public void unsubscribe(GroupId g) throws DbException {
|
||||||
if(LOG.isLoggable(Level.FINE)) LOG.fine("Unsubscribing from " + g);
|
if(LOG.isLoggable(Level.FINE)) LOG.fine("Unsubscribing from " + g);
|
||||||
boolean removed = false;
|
boolean removed;
|
||||||
|
Collection<ContactId> affected;
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
@@ -1339,6 +1344,7 @@ DatabaseCleaner.Callback {
|
|||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
|
affected = db.getVisibility(txn, g);
|
||||||
removed = db.removeSubscription(txn, g);
|
removed = db.removeSubscription(txn, g);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
@@ -1358,7 +1364,7 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
// Call the listeners outside the lock
|
// Call the listeners outside the lock
|
||||||
if(removed) callListeners(new SubscriptionsUpdatedEvent());
|
if(removed) callListeners(new SubscriptionsUpdatedEvent(affected));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkFreeSpaceAndClean() throws DbException {
|
public void checkFreeSpaceAndClean() throws DbException {
|
||||||
|
|||||||
@@ -652,10 +652,20 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSubscription(Connection txn, Group g) throws DbException {
|
public boolean addSubscription(Connection txn, Group g) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "INSERT INTO subscriptions"
|
String sql = "SELECT NULL FROM subscriptions WHERE groupId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setBytes(1, g.getId().getBytes());
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
boolean found = rs.next();
|
||||||
|
if(rs.next()) throw new DbStateException();
|
||||||
|
rs.close();
|
||||||
|
ps.close();
|
||||||
|
if(found) return false;
|
||||||
|
sql = "INSERT INTO subscriptions"
|
||||||
+ " (groupId, groupName, groupKey, start)"
|
+ " (groupId, groupName, groupKey, start)"
|
||||||
+ " VALUES (?, ?, ?, ?)";
|
+ " VALUES (?, ?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
@@ -666,6 +676,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
int affected = ps.executeUpdate();
|
int affected = ps.executeUpdate();
|
||||||
if(affected != 1) throw new DbStateException();
|
if(affected != 1) throw new DbStateException();
|
||||||
ps.close();
|
ps.close();
|
||||||
|
return true;
|
||||||
} catch(SQLException e) {
|
} catch(SQLException e) {
|
||||||
tryToClose(ps);
|
tryToClose(ps);
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
|
|||||||
@@ -102,9 +102,12 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
writerFlags |= Flags.MESSAGES_ADDED;
|
writerFlags |= Flags.MESSAGES_ADDED;
|
||||||
notifyAll();
|
notifyAll();
|
||||||
} else if(e instanceof SubscriptionsUpdatedEvent) {
|
} else if(e instanceof SubscriptionsUpdatedEvent) {
|
||||||
// FIXME: Check whether the change affected this contact
|
Collection<ContactId> affected =
|
||||||
writerFlags |= Flags.SUBSCRIPTIONS_UPDATED;
|
((SubscriptionsUpdatedEvent) e).getAffectedContacts();
|
||||||
notifyAll();
|
if(affected.contains(contactId)) {
|
||||||
|
writerFlags |= Flags.SUBSCRIPTIONS_UPDATED;
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
} else if(e instanceof TransportsUpdatedEvent) {
|
} else if(e instanceof TransportsUpdatedEvent) {
|
||||||
writerFlags |= Flags.TRANSPORTS_UPDATED;
|
writerFlags |= Flags.TRANSPORTS_UPDATED;
|
||||||
notifyAll();
|
notifyAll();
|
||||||
|
|||||||
@@ -134,27 +134,26 @@ public abstract class DatabaseComponentTest extends TestCase {
|
|||||||
oneOf(database).getRemoteProperties(txn, transportId);
|
oneOf(database).getRemoteProperties(txn, transportId);
|
||||||
will(returnValue(remoteProperties));
|
will(returnValue(remoteProperties));
|
||||||
// subscribe(group)
|
// subscribe(group)
|
||||||
oneOf(group).getId();
|
|
||||||
will(returnValue(groupId));
|
|
||||||
oneOf(database).containsSubscription(txn, groupId);
|
|
||||||
will(returnValue(false));
|
|
||||||
oneOf(database).addSubscription(txn, group);
|
oneOf(database).addSubscription(txn, group);
|
||||||
|
will(returnValue(true));
|
||||||
oneOf(listener).eventOccurred(with(any(
|
oneOf(listener).eventOccurred(with(any(
|
||||||
SubscriptionsUpdatedEvent.class)));
|
SubscriptionsUpdatedEvent.class)));
|
||||||
// subscribe(group) again
|
// subscribe(group) again
|
||||||
oneOf(group).getId();
|
oneOf(database).addSubscription(txn, group);
|
||||||
will(returnValue(groupId));
|
will(returnValue(false));
|
||||||
oneOf(database).containsSubscription(txn, groupId);
|
|
||||||
will(returnValue(true));
|
|
||||||
// getSubscriptions()
|
// getSubscriptions()
|
||||||
oneOf(database).getSubscriptions(txn);
|
oneOf(database).getSubscriptions(txn);
|
||||||
will(returnValue(Collections.singletonList(groupId)));
|
will(returnValue(Collections.singletonList(groupId)));
|
||||||
// unsubscribe(groupId)
|
// unsubscribe(groupId)
|
||||||
|
oneOf(database).getVisibility(txn, groupId);
|
||||||
|
will(returnValue(Collections.<ContactId>emptySet()));
|
||||||
oneOf(database).removeSubscription(txn, groupId);
|
oneOf(database).removeSubscription(txn, groupId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(listener).eventOccurred(with(any(
|
oneOf(listener).eventOccurred(with(any(
|
||||||
SubscriptionsUpdatedEvent.class)));
|
SubscriptionsUpdatedEvent.class)));
|
||||||
// unsubscribe(groupId) again
|
// unsubscribe(groupId) again
|
||||||
|
oneOf(database).getVisibility(txn, groupId);
|
||||||
|
will(returnValue(Collections.<ContactId>emptySet()));
|
||||||
oneOf(database).removeSubscription(txn, groupId);
|
oneOf(database).removeSubscription(txn, groupId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
// setConnectionWindow(contactId, 123, connectionWindow)
|
// setConnectionWindow(contactId, 123, connectionWindow)
|
||||||
|
|||||||
Reference in New Issue
Block a user