mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Removed peer moderation (may be restored after beta testing).
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user