Removed peer moderation (may be restored after beta testing).

This commit is contained in:
akwizgran
2013-09-27 18:04:27 +01:00
parent b94954544d
commit 0a153acd02
16 changed files with 80 additions and 1020 deletions

View File

@@ -13,7 +13,6 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP;
import static net.sf.briar.api.messaging.Rating.GOOD;
import java.util.ArrayList;
import java.util.List;
@@ -168,7 +167,6 @@ public class HomeScreenActivity extends RoboActivity {
lifecycleManager.waitForDatabase();
long now = System.currentTimeMillis();
db.addLocalAuthor(a);
db.setRating(a.getId(), GOOD);
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Storing author took " + duration + " ms");

View File

@@ -12,7 +12,6 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP;
import static net.sf.briar.api.messaging.Rating.GOOD;
import java.io.IOException;
import java.util.concurrent.Executor;
@@ -143,7 +142,6 @@ implements OnEditorActionListener, OnClickListener {
lifecycleManager.waitForDatabase();
long now = System.currentTimeMillis();
db.addLocalAuthor(a);
db.setRating(a.getId(), GOOD);
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Storing author took " + duration + " ms");

View File

@@ -20,7 +20,6 @@ import net.sf.briar.api.messaging.GroupStatus;
import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.Offer;
import net.sf.briar.api.messaging.Rating;
import net.sf.briar.api.messaging.Request;
import net.sf.briar.api.messaging.RetentionAck;
import net.sf.briar.api.messaging.RetentionUpdate;
@@ -204,9 +203,6 @@ public interface DatabaseComponent {
Collection<PrivateMessageHeader> getPrivateMessageHeaders(ContactId c)
throws DbException;
/** Returns the user's rating for the given author. */
Rating getRating(AuthorId a) throws DbException;
/** Returns true if the given message has been read. */
boolean getReadFlag(MessageId m) throws DbException;
@@ -313,9 +309,6 @@ public interface DatabaseComponent {
void setConnectionWindow(ContactId c, TransportId t, long period,
long centre, byte[] bitmap) throws DbException;
/** Records the user's rating for the given author. */
void setRating(AuthorId a, Rating r) throws DbException;
/**
* Marks the given message read or unread and returns true if it was
* previously read.

View File

@@ -3,7 +3,6 @@ package net.sf.briar.api.db;
import net.sf.briar.api.Author;
import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.Rating;
public class GroupMessageHeader extends MessageHeader {
@@ -11,9 +10,9 @@ public class GroupMessageHeader extends MessageHeader {
public GroupMessageHeader(MessageId id, MessageId parent, Author author,
String contentType, String subject, long timestamp, boolean read,
boolean starred, Rating rating, GroupId groupId) {
boolean starred, GroupId groupId) {
super(id, parent, author, contentType, subject, timestamp, read,
starred, rating);
starred);
this.groupId = groupId;
}

View File

@@ -2,7 +2,6 @@ package net.sf.briar.api.db;
import net.sf.briar.api.Author;
import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.Rating;
public abstract class MessageHeader {
@@ -11,11 +10,10 @@ public abstract class MessageHeader {
private final String contentType, subject;
private final long timestamp;
private final boolean read, starred;
private final Rating rating;
protected MessageHeader(MessageId id, MessageId parent, Author author,
String contentType, String subject, long timestamp, boolean read,
boolean starred, Rating rating) {
boolean starred) {
this.id = id;
this.parent = parent;
this.author = author;
@@ -24,7 +22,6 @@ public abstract class MessageHeader {
this.timestamp = timestamp;
this.read = read;
this.starred = starred;
this.rating = rating;
}
/** Returns the message's unique identifier. */
@@ -71,12 +68,4 @@ public abstract class MessageHeader {
public boolean isStarred() {
return starred;
}
/**
* Returns the rating for the message's author, or Rating.UNRATED if this
* is an anonymous message.
*/
public Rating getRating() {
return rating;
}
}

View File

@@ -3,7 +3,6 @@ package net.sf.briar.api.db;
import net.sf.briar.api.Author;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.Rating;
public class PrivateMessageHeader extends MessageHeader {
@@ -12,10 +11,9 @@ public class PrivateMessageHeader extends MessageHeader {
public PrivateMessageHeader(MessageId id, MessageId parent, Author author,
String contentType, String subject, long timestamp, boolean read,
boolean starred, Rating rating, ContactId contactId,
boolean incoming) {
boolean starred, ContactId contactId, boolean incoming) {
super(id, parent, author, contentType, subject, timestamp, read,
starred, rating);
starred);
this.contactId = contactId;
this.incoming = incoming;
}

View File

@@ -1,23 +0,0 @@
package net.sf.briar.api.db.event;
import net.sf.briar.api.AuthorId;
import net.sf.briar.api.messaging.Rating;
public class RatingChangedEvent extends DatabaseEvent {
private final AuthorId author;
private final Rating rating;
public RatingChangedEvent(AuthorId author, Rating rating) {
this.author = author;
this.rating = rating;
}
public AuthorId getAuthorId() {
return author;
}
public Rating getRating() {
return rating;
}
}

View File

@@ -1,6 +0,0 @@
package net.sf.briar.api.messaging;
/** The ratings that may be applied to an author in peer moderation. */
public enum Rating {
UNRATED, BAD, GOOD
}

View File

@@ -20,7 +20,6 @@ import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.GroupStatus;
import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.Rating;
import net.sf.briar.api.messaging.RetentionAck;
import net.sf.briar.api.messaging.RetentionUpdate;
import net.sf.briar.api.messaging.SubscriptionAck;
@@ -45,7 +44,6 @@ import net.sf.briar.api.transport.TemporarySecret;
* <li> contact
* <li> identity
* <li> message
* <li> rating
* <li> retention
* <li> subscription
* <li> transport
@@ -270,7 +268,7 @@ interface Database<T> {
/**
* Returns the headers of all messages in the given group.
* <p>
* Locking: message read, rating read.
* Locking: message read.
*/
Collection<GroupMessageHeader> getGroupMessageHeaders(T txn, GroupId g)
throws DbException;
@@ -341,7 +339,7 @@ interface Database<T> {
* Returns the headers of all private messages to or from the given
* contact.
* <p>
* Locking: contact read, identity read, message read, rating read.
* Locking: contact read, identity read, message read.
*/
Collection<PrivateMessageHeader> getPrivateMessageHeaders(T txn,
ContactId c) throws DbException;
@@ -364,15 +362,6 @@ interface Database<T> {
Collection<MessageId> getMessagesToOffer(T txn, ContactId c,
int maxMessages) throws DbException;
/**
* Returns the number of children of the message identified by the given
* ID that are present in the database and have sendability scores greater
* than zero.
* <p>
* Locking: message read.
*/
int getNumberOfSendableChildren(T txn, MessageId m) throws DbException;
/**
* Returns the message identified by the given ID, in serialised form.
* <p>
@@ -398,13 +387,6 @@ interface Database<T> {
*/
Collection<MessageId> getOldMessages(T txn, int size) throws DbException;
/**
* Returns the user's rating for the given author.
* <p>
* Locking: rating read.
*/
Rating getRating(T txn, AuthorId a) throws DbException;
/**
* Returns true if the given message has been read.
* <p>
@@ -443,13 +425,6 @@ interface Database<T> {
*/
Collection<TemporarySecret> getSecrets(T txn) throws DbException;
/**
* Returns the sendability score of the given group message.
* <p>
* Locking: message read.
*/
int getSendability(T txn, MessageId m) throws DbException;
/**
* Returns the IDs of some messages that are eligible to be sent to the
* given contact, with a total length less than or equal to the given
@@ -669,13 +644,6 @@ interface Database<T> {
*/
void setLastConnected(T txn, ContactId c, long now) throws DbException;
/**
* Sets the user's rating for the given author.
* <p>
* Locking: rating write.
*/
Rating setRating(T txn, AuthorId a, Rating r) throws DbException;
/**
* Marks the given message read or unread and returns true if it was
* previously read.
@@ -714,13 +682,6 @@ interface Database<T> {
boolean setRetentionTime(T txn, ContactId c, long retention, long version)
throws DbException;
/**
* Sets the sendability score of the given message.
* <p>
* Locking: message write.
*/
void setSendability(T txn, MessageId m, int sendability) throws DbException;
/**
* Marks the given message starred or unstarred and returns true if it was
* previously starred.

View File

@@ -2,7 +2,6 @@ package net.sf.briar.db;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.api.messaging.Rating.GOOD;
import static net.sf.briar.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
import static net.sf.briar.db.DatabaseConstants.BYTES_PER_SWEEP;
import static net.sf.briar.db.DatabaseConstants.CRITICAL_FREE_SPACE;
@@ -52,7 +51,6 @@ import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent;
import net.sf.briar.api.db.event.MessageExpiredEvent;
import net.sf.briar.api.db.event.MessageReceivedEvent;
import net.sf.briar.api.db.event.PrivateMessageAddedEvent;
import net.sf.briar.api.db.event.RatingChangedEvent;
import net.sf.briar.api.db.event.RemoteRetentionTimeUpdatedEvent;
import net.sf.briar.api.db.event.RemoteSubscriptionsUpdatedEvent;
import net.sf.briar.api.db.event.RemoteTransportsUpdatedEvent;
@@ -68,7 +66,6 @@ import net.sf.briar.api.messaging.GroupStatus;
import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.Offer;
import net.sf.briar.api.messaging.Rating;
import net.sf.briar.api.messaging.Request;
import net.sf.briar.api.messaging.RetentionAck;
import net.sf.briar.api.messaging.RetentionUpdate;
@@ -105,8 +102,6 @@ DatabaseCleaner.Callback {
new ReentrantReadWriteLock(true);
private final ReentrantReadWriteLock messageLock =
new ReentrantReadWriteLock(true);
private final ReentrantReadWriteLock ratingLock =
new ReentrantReadWriteLock(true);
private final ReentrantReadWriteLock retentionLock =
new ReentrantReadWriteLock(true);
private final ReentrantReadWriteLock subscriptionLock =
@@ -290,27 +285,22 @@ DatabaseCleaner.Callback {
try {
messageLock.writeLock().lock();
try {
ratingLock.readLock().lock();
subscriptionLock.readLock().lock();
try {
subscriptionLock.readLock().lock();
T txn = db.startTransaction();
try {
T txn = db.startTransaction();
try {
// Don't store the message if the user has
// unsubscribed from the group
GroupId g = m.getGroup().getId();
if(db.containsSubscription(txn, g))
added = storeGroupMessage(txn, m, null);
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
subscriptionLock.readLock().unlock();
// Don't store the message if the user has
// unsubscribed from the group
GroupId g = m.getGroup().getId();
if(db.containsSubscription(txn, g))
added = storeGroupMessage(txn, m, null);
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
ratingLock.readLock().unlock();
subscriptionLock.readLock().unlock();
}
} finally {
messageLock.writeLock().unlock();
@@ -324,11 +314,10 @@ DatabaseCleaner.Callback {
/**
* If the given message is already in the database, marks it as seen by the
* sender and returns false. Otherwise stores the message, updates the
* sendability of its ancestors if necessary, marks the message as seen by
* the sender and unseen by all other contacts, and returns true.
* sender and returns false. Otherwise stores the message, marks it as seen
* by the sender and unseen by all other contacts, and returns true.
* <p>
* Locking: contact read, message write, rating read.
* Locking: contact read, message write.
* @param sender is null for a locally generated message.
*/
private boolean storeGroupMessage(T txn, Message m, ContactId sender)
@@ -341,13 +330,8 @@ DatabaseCleaner.Callback {
if(sender != null) db.addStatus(txn, sender, id, true);
if(stored) {
// Mark the message as unseen by other contacts
for(ContactId c : db.getContactIds(txn)) {
for(ContactId c : db.getContactIds(txn))
if(!c.equals(sender)) db.addStatus(txn, c, id, false);
}
// Calculate and store the message's sendability
int sendability = calculateSendability(txn, m);
db.setSendability(txn, id, sendability);
if(sendability > 0) updateAncestorSendability(txn, id, true);
// Count the bytes stored
synchronized(spaceLock) {
bytesStoredSinceLastCheck += m.getSerialised().length;
@@ -359,59 +343,6 @@ DatabaseCleaner.Callback {
return stored;
}
/**
* Calculates and returns the sendability score of a message.
* <p>
* Locking: message read, rating read.
*/
private int calculateSendability(T txn, Message m) throws DbException {
int sendability = 0;
// One point for a good rating
Author a = m.getAuthor();
if(a != null && db.getRating(txn, a.getId()) == GOOD) sendability++;
// One point per sendable child (backward inclusion)
sendability += db.getNumberOfSendableChildren(txn, m.getId());
return sendability;
}
/**
* Iteratively updates the sendability of a message's ancestors to reflect
* a change in the message's sendability. Returns the number of ancestors
* that have changed from sendable to not sendable, or vice versa.
* <p>
* Locking: message write.
* @param increment true if the message's sendability has changed from 0 to
* greater than 0, or false if it has changed from greater than 0 to 0.
*/
private int updateAncestorSendability(T txn, MessageId m, boolean increment)
throws DbException {
int affected = 0;
boolean changed = true;
while(changed) {
// Stop if the message has no parent, or the parent isn't in the
// database, or the parent belongs to a different group
MessageId parent = db.getGroupMessageParent(txn, m);
if(parent == null) break;
// Increment or decrement the parent's sendability
int parentSendability = db.getSendability(txn, parent);
if(increment) {
parentSendability++;
changed = parentSendability == 1;
if(changed) affected++;
} else {
assert parentSendability > 0;
parentSendability--;
changed = parentSendability == 0;
if(changed) affected++;
}
db.setSendability(txn, parent, parentSendability);
// Move on to the parent's parent
m = parent;
}
return affected;
}
public void addLocalPrivateMessage(Message m, ContactId c)
throws DbException {
boolean added;
@@ -967,27 +898,22 @@ DatabaseCleaner.Callback {
throws DbException {
messageLock.readLock().lock();
try {
ratingLock.readLock().lock();
subscriptionLock.readLock().lock();
try {
subscriptionLock.readLock().lock();
T txn = db.startTransaction();
try {
T txn = db.startTransaction();
try {
if(!db.containsSubscription(txn, g))
throw new NoSuchSubscriptionException();
Collection<GroupMessageHeader> headers =
db.getGroupMessageHeaders(txn, g);
db.commitTransaction(txn);
return headers;
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
subscriptionLock.readLock().unlock();
if(!db.containsSubscription(txn, g))
throw new NoSuchSubscriptionException();
Collection<GroupMessageHeader> headers =
db.getGroupMessageHeaders(txn, g);
db.commitTransaction(txn);
return headers;
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
ratingLock.readLock().unlock();
subscriptionLock.readLock().unlock();
}
} finally {
messageLock.readLock().unlock();
@@ -1111,20 +1037,15 @@ DatabaseCleaner.Callback {
try {
messageLock.readLock().lock();
try {
ratingLock.readLock().lock();
T txn = db.startTransaction();
try {
T txn = db.startTransaction();
try {
Collection<PrivateMessageHeader> headers =
db.getPrivateMessageHeaders(txn, c);
db.commitTransaction(txn);
return headers;
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
ratingLock.readLock().unlock();
Collection<PrivateMessageHeader> headers =
db.getPrivateMessageHeaders(txn, c);
db.commitTransaction(txn);
return headers;
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
messageLock.readLock().unlock();
@@ -1137,23 +1058,6 @@ DatabaseCleaner.Callback {
}
}
public Rating getRating(AuthorId a) throws DbException {
ratingLock.readLock().lock();
try {
T txn = db.startTransaction();
try {
Rating r = db.getRating(txn, a);
db.commitTransaction(txn);
return r;
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
ratingLock.readLock().unlock();
}
}
public boolean getReadFlag(MessageId m) throws DbException {
messageLock.readLock().lock();
try {
@@ -1463,26 +1367,21 @@ DatabaseCleaner.Callback {
try {
messageLock.writeLock().lock();
try {
ratingLock.readLock().lock();
subscriptionLock.readLock().lock();
try {
subscriptionLock.readLock().lock();
T txn = db.startTransaction();
try {
T txn = db.startTransaction();
try {
if(!db.containsContact(txn, c))
throw new NoSuchContactException();
added = storeMessage(txn, c, m);
db.addMessageToAck(txn, c, m.getId());
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
subscriptionLock.readLock().unlock();
if(!db.containsContact(txn, c))
throw new NoSuchContactException();
added = storeMessage(txn, c, m);
db.addMessageToAck(txn, c, m.getId());
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
ratingLock.readLock().unlock();
subscriptionLock.readLock().unlock();
}
} finally {
messageLock.writeLock().unlock();
@@ -1502,7 +1401,7 @@ DatabaseCleaner.Callback {
* Attempts to store a message received from the given contact, and returns
* true if it was stored.
* <p>
* Locking: contact read, message write, rating read, subscription read.
* Locking: contact read, message write, subscription read.
*/
private boolean storeMessage(T txn, ContactId c, Message m)
throws DbException {
@@ -1823,35 +1722,6 @@ DatabaseCleaner.Callback {
}
}
public void setRating(AuthorId a, Rating r) throws DbException {
boolean changed;
messageLock.writeLock().lock();
try {
ratingLock.writeLock().lock();
try {
T txn = db.startTransaction();
try {
Rating old = db.setRating(txn, a, r);
changed = (old != r);
// Update the sendability of the author's messages
if(r == GOOD && old != GOOD)
updateAuthorSendability(txn, a, true);
else if(r != GOOD && old == GOOD)
updateAuthorSendability(txn, a, false);
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
ratingLock.writeLock().unlock();
}
} finally {
messageLock.writeLock().unlock();
}
if(changed) callListeners(new RatingChangedEvent(a, r));
}
public boolean setReadFlag(MessageId m, boolean read) throws DbException {
messageLock.writeLock().lock();
try {
@@ -1925,31 +1795,6 @@ DatabaseCleaner.Callback {
}
}
/**
* Updates the sendability of all group messages posted by the given
* author, and the ancestors of those messages if necessary.
* <p>
* Locking: message write.
* @param increment true if the user's rating for the author has changed
* from not good to good, or false if it has changed from good to not good.
*/
private void updateAuthorSendability(T txn, AuthorId a, boolean increment)
throws DbException {
for(MessageId id : db.getGroupMessages(txn, a)) {
int sendability = db.getSendability(txn, id);
if(increment) {
db.setSendability(txn, id, sendability + 1);
if(sendability == 0)
updateAncestorSendability(txn, id, true);
} else {
assert sendability > 0;
db.setSendability(txn, id, sendability - 1);
if(sendability == 1)
updateAncestorSendability(txn, id, false);
}
}
}
public boolean setStarredFlag(MessageId m, boolean starred)
throws DbException {
messageLock.writeLock().lock();
@@ -2134,7 +1979,7 @@ DatabaseCleaner.Callback {
try {
expired = db.getOldMessages(txn, size);
if(!expired.isEmpty()) {
for(MessageId m : expired) removeMessage(txn, m);
for(MessageId m : expired) db.removeMessage(txn, m);
db.incrementRetentionVersions(txn);
if(LOG.isLoggable(INFO))
LOG.info("Expired " + expired.size() + " messages");
@@ -2155,19 +2000,6 @@ DatabaseCleaner.Callback {
return true;
}
/**
* Removes the given message (and all associated state) from the database.
* <p>
* Locking: message write.
*/
private void removeMessage(T txn, MessageId m) throws DbException {
int sendability = db.getSendability(txn, m);
// If the message is sendable, deleting it may affect its ancestors'
// sendability (backward inclusion)
if(sendability > 0) updateAncestorSendability(txn, m, false);
db.removeMessage(txn, m);
}
public boolean shouldCheckFreeSpace() {
synchronized(spaceLock) {
long now = clock.currentTimeMillis();

View File

@@ -6,7 +6,6 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
import static net.sf.briar.api.messaging.MessagingConstants.RETENTION_MODULUS;
import static net.sf.briar.api.messaging.Rating.UNRATED;
import static net.sf.briar.db.ExponentialBackoff.calculateExpiry;
import java.io.IOException;
@@ -45,7 +44,6 @@ import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.GroupStatus;
import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.Rating;
import net.sf.briar.api.messaging.RetentionAck;
import net.sf.briar.api.messaging.RetentionUpdate;
import net.sf.briar.api.messaging.SubscriptionAck;
@@ -154,7 +152,6 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " bodyLength INT NOT NULL,"
+ " raw BLOB NOT NULL,"
+ " incoming BOOLEAN NOT NULL,"
+ " sendability INT UNSIGNED," // Null for private messages
+ " contactId INT UNSIGNED," // Null for group messages
+ " read BOOLEAN NOT NULL,"
+ " starred BOOLEAN NOT NULL,"
@@ -166,18 +163,12 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " REFERENCES contacts (contactId)"
+ " ON DELETE CASCADE)";
private static final String INDEX_MESSAGES_BY_PARENT =
"CREATE INDEX messagesByParent ON messages (parentId)";
private static final String INDEX_MESSAGES_BY_AUTHOR =
"CREATE INDEX messagesByAuthor ON messages (authorId)";
private static final String INDEX_MESSAGES_BY_TIMESTAMP =
"CREATE INDEX messagesByTimestamp ON messages (timestamp)";
private static final String INDEX_MESSAGES_BY_SENDABILITY =
"CREATE INDEX messagesBySendability ON messages (sendability)";
// Locking: message
private static final String CREATE_MESSAGES_TO_ACK =
"CREATE TABLE messagesToAck"
@@ -210,13 +201,6 @@ abstract class JdbcDatabase implements Database<Connection> {
private static final String INDEX_STATUSES_BY_CONTACT =
"CREATE INDEX statusesByContact ON statuses (contactId)";
// Locking: rating
private static final String CREATE_RATINGS =
"CREATE TABLE ratings"
+ " (authorId HASH NOT NULL,"
+ " rating SMALLINT NOT NULL,"
+ " PRIMARY KEY (authorId))";
// Locking: retention
private static final String CREATE_RETENTION_VERSIONS =
"CREATE TABLE retentionVersions"
@@ -403,15 +387,12 @@ abstract class JdbcDatabase implements Database<Connection> {
s.executeUpdate(insertTypeNames(CREATE_CONTACT_GROUPS));
s.executeUpdate(insertTypeNames(CREATE_GROUP_VERSIONS));
s.executeUpdate(insertTypeNames(CREATE_MESSAGES));
s.executeUpdate(INDEX_MESSAGES_BY_PARENT);
s.executeUpdate(INDEX_MESSAGES_BY_AUTHOR);
s.executeUpdate(INDEX_MESSAGES_BY_TIMESTAMP);
s.executeUpdate(INDEX_MESSAGES_BY_SENDABILITY);
s.executeUpdate(insertTypeNames(CREATE_MESSAGES_TO_ACK));
s.executeUpdate(insertTypeNames(CREATE_STATUSES));
s.executeUpdate(INDEX_STATUSES_BY_MESSAGE);
s.executeUpdate(INDEX_STATUSES_BY_CONTACT);
s.executeUpdate(insertTypeNames(CREATE_RATINGS));
s.executeUpdate(insertTypeNames(CREATE_RETENTION_VERSIONS));
s.executeUpdate(insertTypeNames(CREATE_TRANSPORTS));
s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_CONFIGS));
@@ -681,8 +662,8 @@ abstract class JdbcDatabase implements Database<Connection> {
String sql = "INSERT INTO messages (messageId, parentId, groupId,"
+ " authorId, authorName, authorKey, contentType, subject,"
+ " timestamp, length, bodyStart, bodyLength, raw,"
+ " incoming, sendability, read, starred)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0,"
+ " incoming, read, starred)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,"
+ " FALSE, FALSE)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getId().getBytes());
@@ -1307,12 +1288,10 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT messageId, parentId, m.authorId, authorName,"
+ " authorKey, rating, contentType, subject, timestamp,"
+ " read, starred"
+ " FROM messages AS m"
+ " LEFT OUTER JOIN ratings AS r"
+ " ON m.authorId = r.authorId"
String sql = "SELECT messageId, parentId, authorId, authorName,"
+ " authorKey, contentType, subject, timestamp, read,"
+ " starred"
+ " FROM messages"
+ " WHERE groupId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, g.getBytes());
@@ -1324,27 +1303,22 @@ abstract class JdbcDatabase implements Database<Connection> {
byte[] b = rs.getBytes(2);
MessageId parent = b == null ? null : new MessageId(b);
Author author;
Rating rating;
b = rs.getBytes(3);
if(b == null) {
author = null;
rating = UNRATED;
} else {
AuthorId authorId = new AuthorId(b);
String authorName = rs.getString(4);
byte[] authorKey = rs.getBytes(5);
author = new Author(authorId, authorName, authorKey);
// NULL == 0 == UNRATED
rating = Rating.values()[rs.getByte(6)];
}
String contentType = rs.getString(7);
String subject = rs.getString(8);
long timestamp = rs.getLong(9);
boolean read = rs.getBoolean(10);
boolean starred = rs.getBoolean(11);
String contentType = rs.getString(6);
String subject = rs.getString(7);
long timestamp = rs.getLong(8);
boolean read = rs.getBoolean(9);
boolean starred = rs.getBoolean(10);
headers.add(new GroupMessageHeader(id, parent, author,
contentType, subject, timestamp, read, starred, rating,
g));
contentType, subject, timestamp, read, starred, g));
}
rs.close();
ps.close();
@@ -1626,7 +1600,6 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " WHERE cg.contactId = ?"
+ " AND timestamp >= retention"
+ " AND seen = FALSE AND s.expiry < ?"
+ " AND sendability > 0"
+ " ORDER BY timestamp DESC LIMIT ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
@@ -1644,41 +1617,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public int getNumberOfSendableChildren(Connection txn, MessageId m)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
// Children in other groups should not be counted
String sql = "SELECT groupId FROM messages WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if(!rs.next()) throw new DbStateException();
byte[] groupId = rs.getBytes(1);
if(rs.next()) throw new DbStateException();
rs.close();
ps.close();
sql = "SELECT COUNT (messageId) FROM messages"
+ " WHERE parentId = ? AND groupId = ?"
+ " AND sendability > 0";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
ps.setBytes(2, groupId);
rs = ps.executeQuery();
if(!rs.next()) throw new DbStateException();
int count = rs.getInt(1);
if(rs.next()) throw new DbStateException();
rs.close();
ps.close();
return count;
} catch(SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
public Collection<MessageId> getOldMessages(Connection txn, int capacity)
throws DbException {
PreparedStatement ps = null;
@@ -1713,13 +1651,10 @@ abstract class JdbcDatabase implements Database<Connection> {
try {
// Get the incoming message headers
String sql = "SELECT m.messageId, parentId, contentType, subject,"
+ " timestamp, read, starred, c.authorId, name, publicKey,"
+ " rating"
+ " timestamp, read, starred, c.authorId, name, publicKey"
+ " FROM messages AS m"
+ " JOIN contacts AS c"
+ " ON m.contactId = c.contactId"
+ " LEFT OUTER JOIN ratings AS r"
+ " ON c.authorId = r.authorId"
+ " WHERE m.contactId = ?"
+ " AND groupId IS NULL"
+ " AND incoming = TRUE";
@@ -1741,25 +1676,21 @@ abstract class JdbcDatabase implements Database<Connection> {
String authorName = rs.getString(9);
byte[] authorKey = rs.getBytes(10);
Author author = new Author(authorId, authorName, authorKey);
// NULL == 0 == UNRATED
Rating rating = Rating.values()[rs.getByte(11)];
headers.add(new PrivateMessageHeader(id, parent, author,
contentType, subject, timestamp, read, starred, rating,
c, true));
contentType, subject, timestamp, read, starred, c,
true));
}
rs.close();
ps.close();
// Get the outgoing message headers
sql = "SELECT m.messageId, parentId, contentType, subject,"
+ " timestamp, read, starred, a.authorId, a.name,"
+ " a.publicKey, rating"
+ " a.publicKey"
+ " FROM messages AS m"
+ " JOIN contacts AS c"
+ " ON m.contactId = c.contactId"
+ " JOIN localAuthors AS a"
+ " ON c.localAuthorId = a.authorId"
+ " LEFT OUTER JOIN ratings AS r"
+ " ON c.localAuthorId = r.authorId"
+ " WHERE m.contactId = ?"
+ " AND groupId IS NULL"
+ " AND incoming = FALSE";
@@ -1779,11 +1710,9 @@ abstract class JdbcDatabase implements Database<Connection> {
String authorName = rs.getString(9);
byte[] authorKey = rs.getBytes(10);
Author author = new Author(authorId, authorName, authorKey);
// NULL == 0 == UNRATED
Rating rating = Rating.values()[rs.getByte(11)];
headers.add(new PrivateMessageHeader(id, parent, author,
contentType, subject, timestamp, read, starred, rating,
c, false));
contentType, subject, timestamp, read, starred, c,
false));
}
rs.close();
ps.close();
@@ -1795,28 +1724,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public Rating getRating(Connection txn, AuthorId a) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT rating FROM ratings WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, a.getBytes());
rs = ps.executeQuery();
Rating r;
if(rs.next()) r = Rating.values()[rs.getByte(1)];
else r = UNRATED;
if(rs.next()) throw new DbStateException();
rs.close();
ps.close();
return r;
} catch(SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
public byte[] getRawMessage(Connection txn, MessageId m)
throws DbException {
PreparedStatement ps = null;
@@ -1883,8 +1790,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " WHERE m.messageId = ?"
+ " AND cg.contactId = ?"
+ " AND timestamp >= retention"
+ " AND seen = FALSE AND s.expiry < ?"
+ " AND sendability > 0";
+ " AND seen = FALSE AND s.expiry < ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
ps.setInt(2, c.getInt());
@@ -2080,27 +1986,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public int getSendability(Connection txn, MessageId m) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT sendability FROM messages WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if(!rs.next()) throw new DbStateException();
int sendability = rs.getInt(1);
if(rs.next()) throw new DbStateException();
rs.close();
ps.close();
return sendability;
} catch(SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
public Collection<MessageId> getSendableMessages(Connection txn,
ContactId c, int maxLength) throws DbException {
long now = clock.currentTimeMillis();
@@ -2143,7 +2028,6 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " WHERE cg.contactId = ?"
+ " AND timestamp >= retention"
+ " AND seen = FALSE AND s.expiry < ?"
+ " AND sendability > 0"
+ " ORDER BY timestamp DESC";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
@@ -2587,7 +2471,6 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " WHERE cg.contactId = ?"
+ " AND timestamp >= retention"
+ " AND seen = FALSE AND s.expiry < ?"
+ " AND sendability > 0"
+ " LIMIT 1";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
@@ -2940,53 +2823,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public Rating setRating(Connection txn, AuthorId a, Rating r)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT rating FROM ratings WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, a.getBytes());
rs = ps.executeQuery();
Rating old = UNRATED;
boolean exists = false;
if(rs.next()) {
old = Rating.values()[rs.getByte(1)];
exists = true;
}
if(rs.next()) throw new DbStateException();
rs.close();
ps.close();
if(old == r) return old;
if(exists) {
// A rating row exists - update it
sql = "UPDATE ratings SET rating = ? WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setByte(1, (byte) r.ordinal());
ps.setBytes(2, a.getBytes());
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
} else {
// No rating row exists - create one
sql = "INSERT INTO ratings (authorId, rating)"
+ " VALUES (?, ?)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, a.getBytes());
ps.setByte(2, (byte) r.ordinal());
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
}
return old;
} catch(SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
public boolean setReadFlag(Connection txn, MessageId m, boolean read)
throws DbException {
PreparedStatement ps = null;
@@ -3181,24 +3017,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public void setSendability(Connection txn, MessageId m, int sendability)
throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE messages SET sendability = ?"
+ " WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, sendability);
ps.setBytes(2, m.getBytes());
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
} catch(SQLException e) {
tryToClose(ps);
throw new DbException(e);
}
}
public boolean setStarredFlag(Connection txn, MessageId m, boolean starred)
throws DbException {
PreparedStatement ps = null;

View File

@@ -9,7 +9,6 @@ import static net.sf.briar.api.TransportPropertyConstants.MAX_PROPERTIES_PER_TRA
import static net.sf.briar.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static net.sf.briar.api.invitation.InvitationConstants.CONNECTION_TIMEOUT;
import static net.sf.briar.api.invitation.InvitationConstants.HASH_LENGTH;
import static net.sf.briar.api.messaging.Rating.GOOD;
import java.io.IOException;
import java.security.GeneralSecurityException;
@@ -263,8 +262,6 @@ abstract class Connector extends Thread {
long epoch, boolean alice) throws DbException {
// Add the contact to the database
contactId = db.addContact(remoteAuthor, localAuthor.getId());
// Add a positive rating for the contact's pseudonym
db.setRating(remoteAuthor.getId(), GOOD);
// Store the remote transport properties
db.setRemoteProperties(contactId, remoteProps);
// Create an endpoint for each transport shared with the contact

View File

@@ -3,7 +3,6 @@ package net.sf.briar.messaging.duplex;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.sf.briar.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
import static net.sf.briar.api.messaging.Rating.GOOD;
import java.io.IOException;
import java.io.InputStream;
@@ -35,7 +34,6 @@ import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent;
import net.sf.briar.api.db.event.MessageExpiredEvent;
import net.sf.briar.api.db.event.MessageReceivedEvent;
import net.sf.briar.api.db.event.PrivateMessageAddedEvent;
import net.sf.briar.api.db.event.RatingChangedEvent;
import net.sf.briar.api.db.event.RemoteRetentionTimeUpdatedEvent;
import net.sf.briar.api.db.event.RemoteSubscriptionsUpdatedEvent;
import net.sf.briar.api.db.event.RemoteTransportsUpdatedEvent;
@@ -157,10 +155,6 @@ abstract class DuplexConnection implements DatabaseListener {
if(canSendOffer.getAndSet(false))
dbExecutor.execute(new GenerateOffer());
}
} else if(e instanceof RatingChangedEvent) {
RatingChangedEvent r = (RatingChangedEvent) e;
if(r.getRating() == GOOD && canSendOffer.getAndSet(false))
dbExecutor.execute(new GenerateOffer());
} else if(e instanceof RemoteRetentionTimeUpdatedEvent) {
dbExecutor.execute(new GenerateRetentionAck());
} else if(e instanceof RemoteSubscriptionsUpdatedEvent) {

View File

@@ -3,7 +3,6 @@ package net.sf.briar.db;
import static net.sf.briar.db.DatabaseConstants.BYTES_PER_SWEEP;
import static net.sf.briar.db.DatabaseConstants.MIN_FREE_SPACE;
import java.util.Arrays;
import java.util.Collections;
import net.sf.briar.api.clock.SystemClock;
@@ -66,68 +65,6 @@ public class DatabaseComponentImplTest extends DatabaseComponentTest {
context.assertIsSatisfied();
}
@Test
public void testExpiringUnsendableMessageDoesNotTriggerBackwardInclusion()
throws DbException {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
context.checking(new Expectations() {{
oneOf(database).getFreeSpace();
will(returnValue(MIN_FREE_SPACE - 1));
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).getOldMessages(txn, BYTES_PER_SWEEP);
will(returnValue(Arrays.asList(messageId)));
oneOf(database).getSendability(txn, messageId);
will(returnValue(0));
oneOf(database).removeMessage(txn, messageId);
oneOf(database).incrementRetentionVersions(txn);
oneOf(database).commitTransaction(txn);
oneOf(database).getFreeSpace();
will(returnValue(MIN_FREE_SPACE));
}});
Callback db = createDatabaseComponentImpl(database, cleaner, shutdown);
db.checkFreeSpaceAndClean();
context.assertIsSatisfied();
}
@Test
public void testExpiringSendableMessageTriggersBackwardInclusion()
throws DbException {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
context.checking(new Expectations() {{
oneOf(database).getFreeSpace();
will(returnValue(MIN_FREE_SPACE - 1));
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).getOldMessages(txn, BYTES_PER_SWEEP);
will(returnValue(Arrays.asList(messageId)));
oneOf(database).getSendability(txn, messageId);
will(returnValue(1));
oneOf(database).getGroupMessageParent(txn, messageId);
will(returnValue(null));
oneOf(database).removeMessage(txn, messageId);
oneOf(database).incrementRetentionVersions(txn);
oneOf(database).commitTransaction(txn);
oneOf(database).getFreeSpace();
will(returnValue(MIN_FREE_SPACE));
}});
Callback db = createDatabaseComponentImpl(database, cleaner, shutdown);
db.checkFreeSpaceAndClean();
context.assertIsSatisfied();
}
@Override
protected <T> DatabaseComponent createDatabaseComponent(
Database<T> database, DatabaseCleaner cleaner,

View File

@@ -2,8 +2,6 @@ package net.sf.briar.db;
import static net.sf.briar.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static net.sf.briar.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
import static net.sf.briar.api.messaging.Rating.GOOD;
import static net.sf.briar.api.messaging.Rating.UNRATED;
import java.util.ArrayList;
import java.util.Arrays;
@@ -34,7 +32,6 @@ import net.sf.briar.api.db.event.DatabaseListener;
import net.sf.briar.api.db.event.GroupMessageAddedEvent;
import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent;
import net.sf.briar.api.db.event.PrivateMessageAddedEvent;
import net.sf.briar.api.db.event.RatingChangedEvent;
import net.sf.briar.api.db.event.SubscriptionAddedEvent;
import net.sf.briar.api.db.event.SubscriptionRemovedEvent;
import net.sf.briar.api.lifecycle.ShutdownManager;
@@ -124,9 +121,9 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final DatabaseListener listener = context.mock(DatabaseListener.class);
context.checking(new Expectations() {{
exactly(13).of(database).startTransaction();
exactly(10).of(database).startTransaction();
will(returnValue(txn));
exactly(13).of(database).commitTransaction(txn);
exactly(10).of(database).commitTransaction(txn);
// open()
oneOf(database).open();
will(returnValue(false));
@@ -135,18 +132,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
with(any(long.class)));
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
will(returnValue(shutdownHandle));
// getRating(authorId)
oneOf(database).getRating(txn, authorId);
will(returnValue(UNRATED));
// setRating(authorId, GOOD)
oneOf(database).setRating(txn, authorId, GOOD);
will(returnValue(UNRATED));
oneOf(database).getGroupMessages(txn, authorId);
will(returnValue(Collections.emptyList()));
oneOf(listener).eventOccurred(with(any(RatingChangedEvent.class)));
// setRating(authorId, GOOD) again
oneOf(database).setRating(txn, authorId, GOOD);
will(returnValue(GOOD));
// addLocalAuthor(localAuthor)
oneOf(database).addLocalAuthor(txn, localAuthor);
// addContact(author, localAuthorId)
@@ -204,9 +189,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
assertFalse(db.open());
db.addListener(listener);
assertEquals(UNRATED, db.getRating(authorId));
db.setRating(authorId, GOOD); // First time - listeners called
db.setRating(authorId, GOOD); // Second time - not called
db.addLocalAuthor(localAuthor);
assertEquals(contactId, db.addContact(author, localAuthorId));
assertEquals(Arrays.asList(contact), db.getContacts());
@@ -225,114 +207,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
context.assertIsSatisfied();
}
@Test
public void testNullParentStopsBackwardInclusion() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
context.checking(new Expectations() {{
// setRating(authorId, GOOD)
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).setRating(txn, authorId, GOOD);
will(returnValue(UNRATED));
// The sendability of the author's messages should be incremented
oneOf(database).getGroupMessages(txn, authorId);
will(returnValue(Arrays.asList(messageId)));
oneOf(database).getSendability(txn, messageId);
will(returnValue(0));
oneOf(database).setSendability(txn, messageId, 1);
// Backward inclusion stops when the message has no parent
oneOf(database).getGroupMessageParent(txn, messageId);
will(returnValue(null));
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown);
db.setRating(authorId, GOOD);
context.assertIsSatisfied();
}
@Test
public void testUnaffectedParentStopsBackwardInclusion() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
context.checking(new Expectations() {{
// setRating(authorId, GOOD)
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).setRating(txn, authorId, GOOD);
will(returnValue(UNRATED));
// The sendability of the author's messages should be incremented
oneOf(database).getGroupMessages(txn, authorId);
will(returnValue(Arrays.asList(messageId)));
oneOf(database).getSendability(txn, messageId);
will(returnValue(0));
oneOf(database).setSendability(txn, messageId, 1);
// The parent exists, is in the DB, and is in the same group
oneOf(database).getGroupMessageParent(txn, messageId);
will(returnValue(messageId1));
// The parent is already sendable
oneOf(database).getSendability(txn, messageId1);
will(returnValue(1));
oneOf(database).setSendability(txn, messageId1, 2);
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown);
db.setRating(authorId, GOOD);
context.assertIsSatisfied();
}
@Test
public void testAffectedParentContinuesBackwardInclusion()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
context.checking(new Expectations() {{
// setRating(authorId, GOOD)
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).setRating(txn, authorId, GOOD);
will(returnValue(UNRATED));
// The sendability of the author's messages should be incremented
oneOf(database).getGroupMessages(txn, authorId);
will(returnValue(Arrays.asList(messageId)));
oneOf(database).getSendability(txn, messageId);
will(returnValue(0));
oneOf(database).setSendability(txn, messageId, 1);
// The parent exists, is in the DB, and is in the same group
oneOf(database).getGroupMessageParent(txn, messageId);
will(returnValue(messageId1));
// The parent is not already sendable
oneOf(database).getSendability(txn, messageId1);
will(returnValue(0));
oneOf(database).setSendability(txn, messageId1, 1);
// The parent has no parent
oneOf(database).getGroupMessageParent(txn, messageId1);
will(returnValue(null));
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown);
db.setRating(authorId, GOOD);
context.assertIsSatisfied();
}
@Test
public void testGroupMessagesAreNotStoredUnlessSubscribed()
throws Exception {
@@ -401,51 +275,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
oneOf(database).getContactIds(txn);
will(returnValue(Arrays.asList(contactId)));
oneOf(database).addStatus(txn, contactId, messageId, false);
// The author is unrated and there are no sendable children
oneOf(database).getRating(txn, authorId);
will(returnValue(UNRATED));
oneOf(database).getNumberOfSendableChildren(txn, messageId);
will(returnValue(0));
oneOf(database).setSendability(txn, messageId, 0);
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown);
db.addLocalGroupMessage(message);
context.assertIsSatisfied();
}
@Test
public void testAddingSendableMessageTriggersBackwardInclusion()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
context.checking(new Expectations() {{
// addLocalGroupMessage(message)
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsSubscription(txn, groupId);
will(returnValue(true));
oneOf(database).addGroupMessage(txn, message, false);
will(returnValue(true));
oneOf(database).setReadFlag(txn, messageId, true);
oneOf(database).getContactIds(txn);
will(returnValue(Arrays.asList(contactId)));
oneOf(database).addStatus(txn, contactId, messageId, false);
// The author is rated GOOD and there are two sendable children
oneOf(database).getRating(txn, authorId);
will(returnValue(GOOD));
oneOf(database).getNumberOfSendableChildren(txn, messageId);
will(returnValue(2));
oneOf(database).setSendability(txn, messageId, 3);
// The sendability of the message's ancestors should be updated
oneOf(database).getGroupMessageParent(txn, messageId);
will(returnValue(null));
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
@@ -1226,124 +1055,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
context.assertIsSatisfied();
}
@Test
public void testReceiveMessageDoesNotCalculateSendabilityForDuplicates()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).commitTransaction(txn);
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
// Only store messages belonging to visible, subscribed groups
oneOf(database).containsVisibleSubscription(txn, contactId,
groupId);
will(returnValue(true));
// The message is not stored, it's a duplicate
oneOf(database).addGroupMessage(txn, message, true);
will(returnValue(false));
oneOf(database).addStatus(txn, contactId, messageId, true);
// The message must be acked
oneOf(database).addMessageToAck(txn, contactId, messageId);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown);
db.receiveMessage(contactId, message);
context.assertIsSatisfied();
}
@Test
public void testReceiveMessageCalculatesSendability() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).commitTransaction(txn);
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
// Only store messages belonging to visible, subscribed groups
oneOf(database).containsVisibleSubscription(txn, contactId,
groupId);
will(returnValue(true));
// The message is stored, and it's not a duplicate
oneOf(database).addGroupMessage(txn, message, true);
will(returnValue(true));
oneOf(database).addStatus(txn, contactId, messageId, true);
// Set the status to seen = true for all other contacts (none)
oneOf(database).getContactIds(txn);
will(returnValue(Arrays.asList(contactId)));
// Calculate the sendability - zero, so ancestors aren't updated
oneOf(database).getRating(txn, authorId);
will(returnValue(UNRATED));
oneOf(database).getNumberOfSendableChildren(txn, messageId);
will(returnValue(0));
oneOf(database).setSendability(txn, messageId, 0);
// The message must be acked
oneOf(database).addMessageToAck(txn, contactId, messageId);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown);
db.receiveMessage(contactId, message);
context.assertIsSatisfied();
}
@Test
public void testReceiveMessageUpdatesAncestorSendability()
throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).commitTransaction(txn);
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
// Only store messages belonging to visible, subscribed groups
oneOf(database).containsVisibleSubscription(txn, contactId,
groupId);
will(returnValue(true));
// The message is stored, and it's not a duplicate
oneOf(database).addGroupMessage(txn, message, true);
will(returnValue(true));
oneOf(database).addStatus(txn, contactId, messageId, true);
// Set the status to seen = true for all other contacts (none)
oneOf(database).getContactIds(txn);
will(returnValue(Arrays.asList(contactId)));
// Calculate the sendability - ancestors are updated
oneOf(database).getRating(txn, authorId);
will(returnValue(GOOD));
oneOf(database).getNumberOfSendableChildren(txn, messageId);
will(returnValue(1));
oneOf(database).setSendability(txn, messageId, 2);
oneOf(database).getGroupMessageParent(txn, messageId);
will(returnValue(null));
// The message must be acked
oneOf(database).addMessageToAck(txn, contactId, messageId);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown);
db.receiveMessage(contactId, message);
context.assertIsSatisfied();
}
@Test
public void testReceiveOffer() throws Exception {
final MessageId messageId1 = new MessageId(TestUtils.getRandomId());
@@ -1527,11 +1238,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
oneOf(database).getContactIds(txn);
will(returnValue(Arrays.asList(contactId)));
oneOf(database).addStatus(txn, contactId, messageId, false);
oneOf(database).getRating(txn, authorId);
will(returnValue(UNRATED));
oneOf(database).getNumberOfSendableChildren(txn, messageId);
will(returnValue(0));
oneOf(database).setSendability(txn, messageId, 0);
oneOf(database).commitTransaction(txn);
// The message was added, so the listener should be called
oneOf(listener).eventOccurred(with(any(

View File

@@ -3,8 +3,6 @@ package net.sf.briar.db;
import static java.util.concurrent.TimeUnit.SECONDS;
import static net.sf.briar.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static net.sf.briar.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
import static net.sf.briar.api.messaging.Rating.GOOD;
import static net.sf.briar.api.messaging.Rating.UNRATED;
import static org.junit.Assert.assertArrayEquals;
import java.io.File;
@@ -153,22 +151,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.close();
}
@Test
public void testRatings() throws Exception {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Unknown authors should be unrated
assertEquals(UNRATED, db.getRating(txn, authorId));
// Store a rating
db.setRating(txn, authorId, GOOD);
// Check that the rating was stored
assertEquals(GOOD, db.getRating(txn, authorId));
db.commitTransaction(txn);
db.close();
}
@Test
public void testUnsubscribingRemovesGroupMessage() throws Exception {
Database<Connection> db = open(false);
@@ -264,45 +246,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.close();
}
@Test
public void testSendableGroupMessagesMustHavePositiveSendability()
throws Exception {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addSubscription(txn, group);
db.addVisibility(txn, contactId, groupId);
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
db.addGroupMessage(txn, message, false);
db.addStatus(txn, contactId, messageId, false);
// The message should not be sendable
assertFalse(db.hasSendableMessages(txn, contactId));
Iterator<MessageId> it =
db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertFalse(it.hasNext());
// Changing the sendability to > 0 should make the message sendable
db.setSendability(txn, messageId, 1);
assertTrue(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertTrue(it.hasNext());
assertEquals(messageId, it.next());
assertFalse(it.hasNext());
// Changing the sendability to 0 should make the message unsendable
db.setSendability(txn, messageId, 0);
assertFalse(db.hasSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertFalse(it.hasNext());
db.commitTransaction(txn);
db.close();
}
@Test
public void testSendableGroupMessagesMustHaveSeenFlagFalse()
throws Exception {
@@ -316,7 +259,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.addVisibility(txn, contactId, groupId);
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
db.addGroupMessage(txn, message, false);
db.setSendability(txn, messageId, 1);
// The message has no status yet, so it should not be sendable
assertFalse(db.hasSendableMessages(txn, contactId));
@@ -353,7 +295,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.addSubscription(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addGroupMessage(txn, message, false);
db.setSendability(txn, messageId, 1);
db.addStatus(txn, contactId, messageId, false);
// The contact is not subscribed, so the message should not be sendable
@@ -392,7 +333,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.addVisibility(txn, contactId, groupId);
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
db.addGroupMessage(txn, message, false);
db.setSendability(txn, messageId, 1);
db.addStatus(txn, contactId, messageId, false);
// The message is sendable, but too large to send
@@ -423,7 +363,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.addSubscription(txn, group);
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
db.addGroupMessage(txn, message, false);
db.setSendability(txn, messageId, 1);
db.addStatus(txn, contactId, messageId, false);
// The subscription is not visible to the contact, so the message
@@ -509,7 +448,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.addVisibility(txn, contactId, groupId);
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
db.addGroupMessage(txn, message, false);
db.setSendability(txn, messageId, 1);
db.addStatus(txn, contactId, messageId, false);
// Retrieve the message from the database and mark it as sent
@@ -568,47 +506,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.close();
}
@Test
public void testGetNumberOfSendableChildren() throws Exception {
MessageId childId1 = new MessageId(TestUtils.getRandomId());
MessageId childId2 = new MessageId(TestUtils.getRandomId());
MessageId childId3 = new MessageId(TestUtils.getRandomId());
GroupId groupId1 = new GroupId(TestUtils.getRandomId());
Group group1 = new Group(groupId1, "Another group",
new byte[GROUP_SALT_LENGTH]);
Message child1 = new TestMessage(childId1, messageId, group, author,
contentType, subject, timestamp, raw);
Message child2 = new TestMessage(childId2, messageId, group, author,
contentType, subject, timestamp, raw);
// The third child is in a different group
Message child3 = new TestMessage(childId3, messageId, group1, author,
contentType, subject, timestamp, raw);
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Subscribe to the groups and store the messages
db.addSubscription(txn, group);
db.addSubscription(txn, group1);
db.addGroupMessage(txn, message, false);
db.addGroupMessage(txn, child1, false);
db.addGroupMessage(txn, child2, false);
db.addGroupMessage(txn, child3, false);
// Make all the children sendable
db.setSendability(txn, childId1, 1);
db.setSendability(txn, childId2, 5);
db.setSendability(txn, childId3, 3);
// There should be two sendable children
assertEquals(2, db.getNumberOfSendableChildren(txn, messageId));
// Make one of the children unsendable
db.setSendability(txn, childId1, 0);
// Now there should be one sendable child
assertEquals(1, db.getNumberOfSendableChildren(txn, messageId));
db.commitTransaction(txn);
db.close();
}
@Test
public void testGetOldMessages() throws Exception {
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
@@ -902,8 +799,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
db.addGroupMessage(txn, message, false);
// Set the sendability to > 0 and the status to seen = true
db.setSendability(txn, messageId, 1);
// Set the status to seen = true
db.addStatus(txn, contactId, messageId, true);
// The message is not sendable because its status is seen = true
@@ -913,31 +809,6 @@ public class H2DatabaseTest extends BriarTestCase {
db.close();
}
@Test
public void testGetMessageIfSendableReturnsNullIfNotSendable()
throws Exception {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addSubscription(txn, group);
db.addVisibility(txn, contactId, groupId);
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
db.addGroupMessage(txn, message, false);
// Set the sendability to 0 and the status to seen = false
db.setSendability(txn, messageId, 0);
db.addStatus(txn, contactId, messageId, false);
// The message is not sendable because its sendability is 0
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
db.commitTransaction(txn);
db.close();
}
@Test
public void testGetMessageIfSendableReturnsNullIfOld() throws Exception {
Database<Connection> db = open(false);
@@ -953,8 +824,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.setRetentionTime(txn, contactId, timestamp + 1, 1);
db.addGroupMessage(txn, message, false);
// Set the sendability to > 0 and the status to seen = false
db.setSendability(txn, messageId, 1);
// Set the status to seen = false
db.addStatus(txn, contactId, messageId, false);
// The message is not sendable because it's too old
@@ -977,8 +847,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
db.addGroupMessage(txn, message, false);
// Set the sendability to > 0 and the status to seen = false
db.setSendability(txn, messageId, 1);
// Set the status to seen = false
db.addStatus(txn, contactId, messageId, false);
// The message is sendable so it should be returned