mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Exposed message handling methods through DatabaseComponent interface.
This commit is contained in:
@@ -152,12 +152,21 @@ public interface DatabaseComponent {
|
||||
/** Returns the local transport properties for the given transport. */
|
||||
TransportProperties getLocalProperties(TransportId t) throws DbException;
|
||||
|
||||
/** Returns the body of the message with the given ID. */
|
||||
byte[] getMessageBody(MessageId m) throws DbException;
|
||||
|
||||
/** Returns the header of the message with the given ID. */
|
||||
MessageHeader getMessageHeader(MessageId m) throws DbException;
|
||||
|
||||
/** Returns the headers of all messages in the given group. */
|
||||
Collection<MessageHeader> getMessageHeaders(GroupId g) 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;
|
||||
|
||||
/** Returns all remote transport properties for the given transport. */
|
||||
Map<ContactId, TransportProperties> getRemoteProperties(TransportId t)
|
||||
throws DbException;
|
||||
@@ -165,6 +174,9 @@ public interface DatabaseComponent {
|
||||
/** Returns all temporary secrets. */
|
||||
Collection<TemporarySecret> getSecrets() throws DbException;
|
||||
|
||||
/** Returns true if the given message has been starred. */
|
||||
boolean getStarredFlag(MessageId m) throws DbException;
|
||||
|
||||
/** Returns the set of groups to which the user subscribes. */
|
||||
Collection<Group> getSubscriptions() throws DbException;
|
||||
|
||||
@@ -251,9 +263,21 @@ public interface DatabaseComponent {
|
||||
/** 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.
|
||||
*/
|
||||
boolean setReadFlag(MessageId m, boolean read) throws DbException;
|
||||
|
||||
/** Records the given messages as having been seen by the given contact. */
|
||||
void setSeen(ContactId c, Collection<MessageId> seen) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks the given message starred or unstarred and returns true if it was
|
||||
* previously starred.
|
||||
*/
|
||||
boolean setStarredFlag(MessageId m, boolean starred) throws DbException;
|
||||
|
||||
/**
|
||||
* Makes the given group visible to the given set of contacts and invisible
|
||||
* to any other contacts.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.sf.briar.api.db;
|
||||
|
||||
/**
|
||||
* Thrown when a database operation is attempted for a message that is not in
|
||||
* the database. This exception may occur due to concurrent updates and does
|
||||
* not indicate a database error.
|
||||
*/
|
||||
public class NoSuchMessageException extends DbException {
|
||||
|
||||
private static final long serialVersionUID = 9191508339698803848L;
|
||||
}
|
||||
@@ -233,13 +233,6 @@ interface Database<T> {
|
||||
TransportProperties getLocalProperties(T txn, TransportId t)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the message identified by the given ID, in serialised form.
|
||||
* <p>
|
||||
* Locking: message read.
|
||||
*/
|
||||
byte[] getMessage(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the body of the message identified by the given ID.
|
||||
* <p>
|
||||
@@ -247,6 +240,13 @@ interface Database<T> {
|
||||
*/
|
||||
byte[] getMessageBody(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the header of the message identified by the given ID.
|
||||
* <p>
|
||||
* Locking: message read.
|
||||
*/
|
||||
MessageHeader getMessageHeader(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the headers of all messages in the given group.
|
||||
* <p>
|
||||
@@ -255,16 +255,6 @@ interface Database<T> {
|
||||
Collection<MessageHeader> getMessageHeaders(T txn, GroupId g)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the message identified by the given ID, in raw format, or null
|
||||
* if the message is not present in the database or is not sendable to the
|
||||
* given contact.
|
||||
* <p>
|
||||
* Locking: contact read, message read, subscription read.
|
||||
*/
|
||||
byte[] getMessageIfSendable(T txn, ContactId c, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the IDs of all messages signed by the given author.
|
||||
* <p>
|
||||
@@ -300,6 +290,23 @@ interface Database<T> {
|
||||
*/
|
||||
int getNumberOfSendableChildren(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the message identified by the given ID, in serialised form.
|
||||
* <p>
|
||||
* Locking: message read.
|
||||
*/
|
||||
byte[] getRawMessage(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the message identified by the given ID, in serialised form, or
|
||||
* null if the message is not present in the database or is not sendable to
|
||||
* the given contact.
|
||||
* <p>
|
||||
* Locking: contact read, message read, subscription read.
|
||||
*/
|
||||
byte[] getRawMessageIfSendable(T txn, ContactId c, MessageId m)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the IDs of the oldest messages in the database, with a total
|
||||
* size less than or equal to the given size.
|
||||
@@ -569,7 +576,7 @@ interface Database<T> {
|
||||
* <p>
|
||||
* Locking: message write.
|
||||
*/
|
||||
boolean setRead(T txn, MessageId m, boolean read) throws DbException;
|
||||
boolean setReadFlag(T txn, MessageId m, boolean read) throws DbException;
|
||||
|
||||
/**
|
||||
* Updates the remote transport properties for the given contact and the
|
||||
@@ -605,7 +612,8 @@ interface Database<T> {
|
||||
* <p>
|
||||
* Locking: message write.
|
||||
*/
|
||||
boolean setStarred(T txn, MessageId m, boolean starred) throws DbException;
|
||||
boolean setStarredFlag(T txn, MessageId m, boolean starred)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the status of the given message with respect to the given contact.
|
||||
|
||||
@@ -29,6 +29,7 @@ import net.sf.briar.api.db.DatabaseComponent;
|
||||
import net.sf.briar.api.db.DbException;
|
||||
import net.sf.briar.api.db.MessageHeader;
|
||||
import net.sf.briar.api.db.NoSuchContactException;
|
||||
import net.sf.briar.api.db.NoSuchMessageException;
|
||||
import net.sf.briar.api.db.NoSuchSubscriptionException;
|
||||
import net.sf.briar.api.db.NoSuchTransportException;
|
||||
import net.sf.briar.api.db.event.ContactAddedEvent;
|
||||
@@ -503,7 +504,7 @@ DatabaseCleaner.Callback {
|
||||
throw new NoSuchContactException();
|
||||
ids = db.getSendableMessages(txn, c, maxLength);
|
||||
for(MessageId m : ids) {
|
||||
messages.add(db.getMessage(txn, m));
|
||||
messages.add(db.getRawMessage(txn, m));
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
@@ -555,7 +556,7 @@ DatabaseCleaner.Callback {
|
||||
Iterator<MessageId> it = requested.iterator();
|
||||
while(it.hasNext()) {
|
||||
MessageId m = it.next();
|
||||
byte[] raw = db.getMessageIfSendable(txn, c, m);
|
||||
byte[] raw = db.getRawMessageIfSendable(txn, c, m);
|
||||
if(raw != null) {
|
||||
if(raw.length > maxLength) break;
|
||||
messages.add(raw);
|
||||
@@ -828,6 +829,44 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getMessageBody(MessageId m) throws DbException {
|
||||
messageLock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
byte[] body = db.getMessageBody(txn, m);
|
||||
db.commitTransaction(txn);
|
||||
return body;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
messageLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public MessageHeader getMessageHeader(MessageId m) throws DbException {
|
||||
messageLock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
MessageHeader h = db.getMessageHeader(txn, m);
|
||||
db.commitTransaction(txn);
|
||||
return h;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
messageLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<MessageHeader> getMessageHeaders(GroupId g)
|
||||
throws DbException {
|
||||
messageLock.readLock().lock();
|
||||
@@ -866,6 +905,25 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getReadFlag(MessageId m) throws DbException {
|
||||
messageLock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
boolean read = db.getReadFlag(txn, m);
|
||||
db.commitTransaction(txn);
|
||||
return read;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
messageLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<ContactId, TransportProperties> getRemoteProperties(
|
||||
TransportId t) throws DbException {
|
||||
contactLock.readLock().lock();
|
||||
@@ -918,6 +976,25 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getStarredFlag(MessageId m) throws DbException {
|
||||
messageLock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
boolean starred = db.getStarredFlag(txn, m);
|
||||
db.commitTransaction(txn);
|
||||
return starred;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
messageLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Group> getSubscriptions() throws DbException {
|
||||
subscriptionLock.readLock().lock();
|
||||
try {
|
||||
@@ -1494,6 +1571,25 @@ DatabaseCleaner.Callback {
|
||||
if(changed) callListeners(new RatingChangedEvent(a, r));
|
||||
}
|
||||
|
||||
public boolean setReadFlag(MessageId m, boolean read) throws DbException {
|
||||
messageLock.writeLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
boolean wasRead = db.setReadFlag(txn, m, read);
|
||||
db.commitTransaction(txn);
|
||||
return wasRead;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
messageLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSeen(ContactId c, Collection<MessageId> seen)
|
||||
throws DbException {
|
||||
contactLock.readLock().lock();
|
||||
@@ -1506,9 +1602,8 @@ DatabaseCleaner.Callback {
|
||||
try {
|
||||
if(!db.containsContact(txn, c))
|
||||
throw new NoSuchContactException();
|
||||
for(MessageId m : seen) {
|
||||
for(MessageId m : seen)
|
||||
db.setStatusSeenIfVisible(txn, c, m);
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
@@ -1550,6 +1645,26 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setStarredFlag(MessageId m, boolean starred)
|
||||
throws DbException {
|
||||
messageLock.writeLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(!db.containsMessage(txn, m))
|
||||
throw new NoSuchMessageException();
|
||||
boolean wasStarred = db.setStarredFlag(txn, m, starred);
|
||||
db.commitTransaction(txn);
|
||||
return wasStarred;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
messageLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void setVisibility(GroupId g, Collection<ContactId> visible)
|
||||
throws DbException {
|
||||
Collection<ContactId> affected = new ArrayList<ContactId>();
|
||||
|
||||
@@ -1074,29 +1074,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getMessage(Connection txn, MessageId m) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT length, raw FROM messages WHERE messageId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
if(!rs.next()) throw new DbStateException();
|
||||
int length = rs.getInt(1);
|
||||
byte[] raw = rs.getBlob(2).getBytes(1, length);
|
||||
if(raw.length != length) throw new DbStateException();
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return raw;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getMessageBody(Connection txn, MessageId m)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -1123,14 +1100,48 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public MessageHeader getMessageHeader(Connection txn, MessageId m)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT parentId, authorId, groupId, subject,"
|
||||
+ " timestamp, read, starred"
|
||||
+ " FROM messages"
|
||||
+ " WHERE messageId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
if(!rs.next()) throw new DbStateException();
|
||||
byte[] b = rs.getBytes(1);
|
||||
MessageId parent = b == null ? null : new MessageId(b);
|
||||
AuthorId author = new AuthorId(rs.getBytes(2));
|
||||
b = rs.getBytes(3);
|
||||
GroupId group = b == null ? null : new GroupId(b);
|
||||
String subject = rs.getString(4);
|
||||
long timestamp = rs.getLong(5);
|
||||
boolean read = rs.getBoolean(6);
|
||||
boolean starred = rs.getBoolean(7);
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return new MessageHeaderImpl(m, parent, group, author, subject,
|
||||
timestamp, read, starred);
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<MessageHeader> getMessageHeaders(Connection txn,
|
||||
GroupId g) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT m.messageId, parentId, authorId,"
|
||||
+ " subject, timestamp, read, starred"
|
||||
+ " FROM messages AS m"
|
||||
String sql = "SELECT messageId, parentId, authorId, subject,"
|
||||
+ " timestamp, read, starred"
|
||||
+ " FROM messages"
|
||||
+ " WHERE groupId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, g.getBytes());
|
||||
@@ -1143,8 +1154,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
AuthorId author = new AuthorId(rs.getBytes(3));
|
||||
String subject = rs.getString(4);
|
||||
long timestamp = rs.getLong(5);
|
||||
boolean read = rs.getBoolean(6); // False if absent
|
||||
boolean starred = rs.getBoolean(7); // False if absent
|
||||
boolean read = rs.getBoolean(6);
|
||||
boolean starred = rs.getBoolean(7);
|
||||
headers.add(new MessageHeaderImpl(id, parent, g, author,
|
||||
subject, timestamp, read, starred));
|
||||
}
|
||||
@@ -1158,70 +1169,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getMessageIfSendable(Connection txn, ContactId c, MessageId m)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
// Do we have a sendable private message with the given ID?
|
||||
String sql = "SELECT length, raw FROM messages AS m"
|
||||
+ " JOIN statuses AS s"
|
||||
+ " ON m.messageId = s.messageId"
|
||||
+ " WHERE m.messageId = ? AND m.contactId = ?"
|
||||
+ " AND status = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
ps.setInt(2, c.getInt());
|
||||
ps.setShort(3, (short) Status.NEW.ordinal());
|
||||
rs = ps.executeQuery();
|
||||
byte[] raw = null;
|
||||
if(rs.next()) {
|
||||
int length = rs.getInt(1);
|
||||
raw = rs.getBlob(2).getBytes(1, length);
|
||||
if(raw.length != length) throw new DbStateException();
|
||||
}
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
if(raw != null) return raw;
|
||||
// Do we have a sendable group message with the given ID?
|
||||
sql = "SELECT length, raw FROM messages AS m"
|
||||
+ " JOIN contactGroups AS cg"
|
||||
+ " ON m.groupId = cg.groupId"
|
||||
+ " JOIN groupVisibilities AS gv"
|
||||
+ " ON m.groupId = gv.groupId"
|
||||
+ " AND cg.contactId = gv.contactId"
|
||||
+ " JOIN retentionVersions AS rv"
|
||||
+ " ON cg.contactId = rv.contactId"
|
||||
+ " JOIN statuses AS s"
|
||||
+ " ON m.messageId = s.messageId"
|
||||
+ " AND cg.contactId = s.contactId"
|
||||
+ " WHERE m.messageId = ?"
|
||||
+ " AND cg.contactId = ?"
|
||||
+ " AND timestamp >= retention"
|
||||
+ " AND status = ?"
|
||||
+ " AND sendability > ZERO()";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
ps.setInt(2, c.getInt());
|
||||
ps.setShort(3, (short) Status.NEW.ordinal());
|
||||
rs = ps.executeQuery();
|
||||
if(rs.next()) {
|
||||
int length = rs.getInt(1);
|
||||
raw = rs.getBlob(2).getBytes(1, length);
|
||||
if(raw.length != length) throw new DbStateException();
|
||||
}
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return raw;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<MessageId> getMessagesByAuthor(Connection txn, AuthorId a)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -1406,6 +1353,94 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getRawMessage(Connection txn, MessageId m)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT length, raw FROM messages WHERE messageId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
if(!rs.next()) throw new DbStateException();
|
||||
int length = rs.getInt(1);
|
||||
byte[] raw = rs.getBlob(2).getBytes(1, length);
|
||||
if(raw.length != length) throw new DbStateException();
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return raw;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getRawMessageIfSendable(Connection txn, ContactId c,
|
||||
MessageId m) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
// Do we have a sendable private message with the given ID?
|
||||
String sql = "SELECT length, raw FROM messages AS m"
|
||||
+ " JOIN statuses AS s"
|
||||
+ " ON m.messageId = s.messageId"
|
||||
+ " WHERE m.messageId = ? AND m.contactId = ?"
|
||||
+ " AND status = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
ps.setInt(2, c.getInt());
|
||||
ps.setShort(3, (short) Status.NEW.ordinal());
|
||||
rs = ps.executeQuery();
|
||||
byte[] raw = null;
|
||||
if(rs.next()) {
|
||||
int length = rs.getInt(1);
|
||||
raw = rs.getBlob(2).getBytes(1, length);
|
||||
if(raw.length != length) throw new DbStateException();
|
||||
}
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
if(raw != null) return raw;
|
||||
// Do we have a sendable group message with the given ID?
|
||||
sql = "SELECT length, raw FROM messages AS m"
|
||||
+ " JOIN contactGroups AS cg"
|
||||
+ " ON m.groupId = cg.groupId"
|
||||
+ " JOIN groupVisibilities AS gv"
|
||||
+ " ON m.groupId = gv.groupId"
|
||||
+ " AND cg.contactId = gv.contactId"
|
||||
+ " JOIN retentionVersions AS rv"
|
||||
+ " ON cg.contactId = rv.contactId"
|
||||
+ " JOIN statuses AS s"
|
||||
+ " ON m.messageId = s.messageId"
|
||||
+ " AND cg.contactId = s.contactId"
|
||||
+ " WHERE m.messageId = ?"
|
||||
+ " AND cg.contactId = ?"
|
||||
+ " AND timestamp >= retention"
|
||||
+ " AND status = ?"
|
||||
+ " AND sendability > ZERO()";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
ps.setInt(2, c.getInt());
|
||||
ps.setShort(3, (short) Status.NEW.ordinal());
|
||||
rs = ps.executeQuery();
|
||||
if(rs.next()) {
|
||||
int length = rs.getInt(1);
|
||||
raw = rs.getBlob(2).getBytes(1, length);
|
||||
if(raw.length != length) throw new DbStateException();
|
||||
}
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return raw;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getReadFlag(Connection txn, MessageId m) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
@@ -2415,7 +2450,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setRead(Connection txn, MessageId m, boolean read)
|
||||
public boolean setReadFlag(Connection txn, MessageId m, boolean read)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
@@ -2543,7 +2578,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setStarred(Connection txn, MessageId m, boolean starred)
|
||||
public boolean setStarredFlag(Connection txn, MessageId m, boolean starred)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
@@ -689,9 +689,9 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
// Get the sendable messages
|
||||
oneOf(database).getSendableMessages(txn, contactId, size * 2);
|
||||
will(returnValue(sendable));
|
||||
oneOf(database).getMessage(txn, messageId);
|
||||
oneOf(database).getRawMessage(txn, messageId);
|
||||
will(returnValue(raw));
|
||||
oneOf(database).getMessage(txn, messageId1);
|
||||
oneOf(database).getRawMessage(txn, messageId1);
|
||||
will(returnValue(raw1));
|
||||
// Record the outstanding messages
|
||||
oneOf(database).addOutstandingMessages(txn, contactId, sendable);
|
||||
@@ -723,11 +723,11 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
allowing(database).containsContact(txn, contactId);
|
||||
will(returnValue(true));
|
||||
// Try to get the requested messages
|
||||
oneOf(database).getMessageIfSendable(txn, contactId, messageId);
|
||||
oneOf(database).getRawMessageIfSendable(txn, contactId, messageId);
|
||||
will(returnValue(null)); // Message is not sendable
|
||||
oneOf(database).getMessageIfSendable(txn, contactId, messageId1);
|
||||
oneOf(database).getRawMessageIfSendable(txn, contactId, messageId1);
|
||||
will(returnValue(raw1)); // Message is sendable
|
||||
oneOf(database).getMessageIfSendable(txn, contactId, messageId2);
|
||||
oneOf(database).getRawMessageIfSendable(txn, contactId, messageId2);
|
||||
will(returnValue(null)); // Message is not sendable
|
||||
// Record the outstanding messages
|
||||
oneOf(database).addOutstandingMessages(txn, contactId,
|
||||
|
||||
@@ -111,10 +111,10 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
assertTrue(db.containsContact(txn, contactId));
|
||||
assertTrue(db.containsSubscription(txn, groupId));
|
||||
assertTrue(db.containsMessage(txn, messageId));
|
||||
byte[] raw1 = db.getMessage(txn, messageId);
|
||||
byte[] raw1 = db.getRawMessage(txn, messageId);
|
||||
assertArrayEquals(raw, raw1);
|
||||
assertTrue(db.containsMessage(txn, messageId1));
|
||||
raw1 = db.getMessage(txn, messageId1);
|
||||
raw1 = db.getRawMessage(txn, messageId1);
|
||||
assertArrayEquals(raw, raw1);
|
||||
// Delete the records
|
||||
db.removeMessage(txn, messageId);
|
||||
@@ -892,7 +892,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1L);
|
||||
|
||||
// The message is not in the database
|
||||
assertNull(db.getMessageIfSendable(txn, contactId, messageId));
|
||||
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
@@ -914,7 +914,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.setStatus(txn, contactId, messageId, Status.SEEN);
|
||||
|
||||
// The message is not sendable because its status is SEEN
|
||||
assertNull(db.getMessageIfSendable(txn, contactId, messageId));
|
||||
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
@@ -937,7 +937,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.setStatus(txn, contactId, messageId, Status.NEW);
|
||||
|
||||
// The message is not sendable because its sendability is 0
|
||||
assertNull(db.getMessageIfSendable(txn, contactId, messageId));
|
||||
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
@@ -962,7 +962,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.setStatus(txn, contactId, messageId, Status.NEW);
|
||||
|
||||
// The message is not sendable because it's too old
|
||||
assertNull(db.getMessageIfSendable(txn, contactId, messageId));
|
||||
assertNull(db.getRawMessageIfSendable(txn, contactId, messageId));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
@@ -985,7 +985,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.setStatus(txn, contactId, messageId, Status.NEW);
|
||||
|
||||
// The message is sendable so it should be returned
|
||||
byte[] b = db.getMessageIfSendable(txn, contactId, messageId);
|
||||
byte[] b = db.getRawMessageIfSendable(txn, contactId, messageId);
|
||||
assertArrayEquals(raw, b);
|
||||
|
||||
db.commitTransaction(txn);
|
||||
@@ -1280,8 +1280,8 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
System.arraycopy(raw, 10, expectedBody1, 0, bodyLength);
|
||||
|
||||
// Retrieve the raw messages
|
||||
assertArrayEquals(raw, db.getMessage(txn, messageId));
|
||||
assertArrayEquals(raw, db.getMessage(txn, messageId1));
|
||||
assertArrayEquals(raw, db.getRawMessage(txn, messageId));
|
||||
assertArrayEquals(raw, db.getRawMessage(txn, messageId1));
|
||||
|
||||
// Retrieve the message bodies
|
||||
byte[] body = db.getMessageBody(txn, messageId);
|
||||
@@ -1310,7 +1310,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
authorId, subject, timestamp1, raw);
|
||||
db.addGroupMessage(txn, message1);
|
||||
// Mark one of the messages read
|
||||
assertFalse(db.setRead(txn, messageId, true));
|
||||
assertFalse(db.setReadFlag(txn, messageId, true));
|
||||
|
||||
// Retrieve the message headers
|
||||
Collection<MessageHeader> headers = db.getMessageHeaders(txn, groupId);
|
||||
@@ -1381,13 +1381,13 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
// The message should be unread by default
|
||||
assertFalse(db.getReadFlag(txn, messageId));
|
||||
// Marking the message read should return the old value
|
||||
assertFalse(db.setRead(txn, messageId, true));
|
||||
assertTrue(db.setRead(txn, messageId, true));
|
||||
assertFalse(db.setReadFlag(txn, messageId, true));
|
||||
assertTrue(db.setReadFlag(txn, messageId, true));
|
||||
// The message should be read
|
||||
assertTrue(db.getReadFlag(txn, messageId));
|
||||
// Marking the message unread should return the old value
|
||||
assertTrue(db.setRead(txn, messageId, false));
|
||||
assertFalse(db.setRead(txn, messageId, false));
|
||||
assertTrue(db.setReadFlag(txn, messageId, false));
|
||||
assertFalse(db.setReadFlag(txn, messageId, false));
|
||||
// Unsubscribe from the group
|
||||
db.removeSubscription(txn, groupId);
|
||||
|
||||
@@ -1407,13 +1407,13 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
// The message should be unstarred by default
|
||||
assertFalse(db.getStarredFlag(txn, messageId));
|
||||
// Starring the message should return the old value
|
||||
assertFalse(db.setStarred(txn, messageId, true));
|
||||
assertTrue(db.setStarred(txn, messageId, true));
|
||||
assertFalse(db.setStarredFlag(txn, messageId, true));
|
||||
assertTrue(db.setStarredFlag(txn, messageId, true));
|
||||
// The message should be starred
|
||||
assertTrue(db.getStarredFlag(txn, messageId));
|
||||
// Unstarring the message should return the old value
|
||||
assertTrue(db.setStarred(txn, messageId, false));
|
||||
assertFalse(db.setStarred(txn, messageId, false));
|
||||
assertTrue(db.setStarredFlag(txn, messageId, false));
|
||||
assertFalse(db.setStarredFlag(txn, messageId, false));
|
||||
// Unsubscribe from the group
|
||||
db.removeSubscription(txn, groupId);
|
||||
|
||||
@@ -1446,7 +1446,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.addGroupMessage(txn, message2);
|
||||
|
||||
// Mark one of the messages in the first group read
|
||||
assertFalse(db.setRead(txn, messageId, true));
|
||||
assertFalse(db.setReadFlag(txn, messageId, true));
|
||||
|
||||
// There should be one unread message in each group
|
||||
Map<GroupId, Integer> counts = db.getUnreadMessageCounts(txn);
|
||||
@@ -1459,10 +1459,10 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
assertEquals(1, count.intValue());
|
||||
|
||||
// Mark the read message unread (it will now be false rather than null)
|
||||
assertTrue(db.setRead(txn, messageId, false));
|
||||
assertTrue(db.setReadFlag(txn, messageId, false));
|
||||
|
||||
// Mark the message in the second group read
|
||||
assertFalse(db.setRead(txn, messageId2, true));
|
||||
assertFalse(db.setReadFlag(txn, messageId2, true));
|
||||
|
||||
// There should be two unread messages in the first group, none in
|
||||
// the second group
|
||||
@@ -1812,7 +1812,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
Connection txn = db.startTransaction();
|
||||
try {
|
||||
// Ask for a nonexistent message - an exception should be thrown
|
||||
db.getMessage(txn, messageId);
|
||||
db.getRawMessage(txn, messageId);
|
||||
fail();
|
||||
} catch(DbException expected) {
|
||||
// It should be possible to abort the transaction without error
|
||||
|
||||
Reference in New Issue
Block a user