Added columns to the DB to support retrieval of message headers.

This commit is contained in:
akwizgran
2013-02-28 12:49:48 +00:00
parent 88aea1bb72
commit bfd4ee5e9f
17 changed files with 296 additions and 229 deletions

View File

@@ -166,11 +166,13 @@ public interface DatabaseComponent {
/** Returns the body of the message with the given ID. */ /** Returns the body of the message with the given ID. */
byte[] getMessageBody(MessageId m) throws DbException; 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. */ /** Returns the headers of all messages in the given group. */
Collection<MessageHeader> getMessageHeaders(GroupId g) throws DbException; Collection<GroupMessageHeader> getMessageHeaders(GroupId g)
throws DbException;
/** Returns the headers of all private messages. */
Collection<PrivateMessageHeader> getPrivateMessageHeaders()
throws DbException;
/** Returns the user's rating for the given author. */ /** Returns the user's rating for the given author. */
Rating getRating(AuthorId a) throws DbException; Rating getRating(AuthorId a) throws DbException;

View File

@@ -0,0 +1,31 @@
package net.sf.briar.api.db;
import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.MessageId;
public class GroupMessageHeader extends MessageHeader {
private final GroupId groupId;
private final Author author;
public GroupMessageHeader(MessageId id, MessageId parent, String subject,
long timestamp, boolean read, boolean starred, GroupId groupId,
Author author) {
super(id, parent, subject, timestamp, read, starred);
this.groupId = groupId;
this.author = author;
}
/** Returns the ID of the group to which the message belongs. */
public GroupId getGroupId() {
return groupId;
}
/**
* Returns the message's author, or null if this is an anonymous message.
*/
public Author getAuthor() {
return author;
}
}

View File

@@ -1,25 +1,18 @@
package net.sf.briar.api.db; package net.sf.briar.api.db;
import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.MessageId; import net.sf.briar.api.messaging.MessageId;
public class MessageHeader { public abstract class MessageHeader {
private final MessageId id, parent; private final MessageId id, parent;
private final GroupId group;
private final AuthorId author;
private final String subject; private final String subject;
private final long timestamp; private final long timestamp;
private final boolean read, starred; private final boolean read, starred;
public MessageHeader(MessageId id, MessageId parent, GroupId group, protected MessageHeader(MessageId id, MessageId parent, String subject,
AuthorId author, String subject, long timestamp, boolean read, long timestamp, boolean read, boolean starred) {
boolean starred) {
this.id = id; this.id = id;
this.parent = parent; this.parent = parent;
this.group = group;
this.author = author;
this.subject = subject; this.subject = subject;
this.timestamp = timestamp; this.timestamp = timestamp;
this.read = read; this.read = read;
@@ -39,22 +32,6 @@ public class MessageHeader {
return parent; return parent;
} }
/**
* Returns the ID of the group to which the message belongs, or null if
* this is a private message.
*/
public GroupId getGroup() {
return group;
}
/**
* Returns the ID of the message's author, or null if this is an
* anonymous message.
*/
public AuthorId getAuthor() {
return author;
}
/** Returns the message's subject line. */ /** Returns the message's subject line. */
public String getSubject() { public String getSubject() {
return subject; return subject;

View File

@@ -0,0 +1,31 @@
package net.sf.briar.api.db;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.messaging.MessageId;
public class PrivateMessageHeader extends MessageHeader {
private final ContactId contactId;
private final boolean incoming;
public PrivateMessageHeader(MessageId id, MessageId parent, String subject,
long timestamp, boolean read, boolean starred, ContactId contactId,
boolean incoming) {
super(id, parent, subject, timestamp, read, starred);
this.contactId = contactId;
this.incoming = incoming;
}
/**
* Returns the ID of the contact who is the sender (if incoming) or
* recipient (if outgoing) of this message.
*/
public ContactId getContactId() {
return contactId;
}
/** Returns true if this is an incoming message. */
public boolean isIncoming() {
return incoming;
}
}

View File

@@ -1,9 +0,0 @@
package net.sf.briar.api.db.event;
/**
* An event that is broadcast when the retention time of the local database
* changes.
*/
public class LocalRetentionTimeUpdatedEvent extends DatabaseEvent {
}

View File

@@ -0,0 +1,9 @@
package net.sf.briar.api.db.event;
/**
* An event that is broadcast when one or messages expire from the database,
* potentially changing the database's retention time.
*/
public class MessageExpiredEvent extends DatabaseEvent {
}

View File

@@ -12,16 +12,16 @@ public interface Message {
MessageId getParent(); MessageId getParent();
/** /**
* Returns the identifier of the {@link Group} to which the message * Returns the {@link Group} to which the message belongs, or null if this
* belongs, or null if this is a private message. * is a private message.
*/ */
GroupId getGroup(); Group getGroup();
/** /**
* Returns the identifier of the message's {@link Author}, or null if this * Returns the message's {@link Author}, or null if this is an anonymous
* is an anonymous message. * message.
*/ */
AuthorId getAuthor(); Author getAuthor();
/** Returns the message's subject line. */ /** Returns the message's subject line. */
String getSubject(); String getSubject();

View File

@@ -10,7 +10,8 @@ import net.sf.briar.api.Rating;
import net.sf.briar.api.TransportConfig; import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportProperties; import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.DbException;
import net.sf.briar.api.db.MessageHeader; import net.sf.briar.api.db.GroupMessageHeader;
import net.sf.briar.api.db.PrivateMessageHeader;
import net.sf.briar.api.messaging.AuthorId; import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.GroupId;
@@ -263,19 +264,20 @@ interface Database<T> {
*/ */
byte[] getMessageBody(T txn, MessageId m) throws DbException; 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. * Returns the headers of all messages in the given group.
* <p> * <p>
* Locking: message read. * Locking: message read.
*/ */
Collection<MessageHeader> getMessageHeaders(T txn, GroupId g) Collection<GroupMessageHeader> getMessageHeaders(T txn, GroupId g)
throws DbException;
/**
* Returns the headers of all private messages.
* <p>
* Locking: message read.
*/
Collection<PrivateMessageHeader> getPrivateMessageHeaders(T txn)
throws DbException; throws DbException;
/** /**

View File

@@ -30,19 +30,20 @@ import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.clock.Clock; import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseComponent;
import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.DbException;
import net.sf.briar.api.db.MessageHeader; import net.sf.briar.api.db.GroupMessageHeader;
import net.sf.briar.api.db.NoSuchContactException; import net.sf.briar.api.db.NoSuchContactException;
import net.sf.briar.api.db.NoSuchMessageException; import net.sf.briar.api.db.NoSuchMessageException;
import net.sf.briar.api.db.NoSuchSubscriptionException; import net.sf.briar.api.db.NoSuchSubscriptionException;
import net.sf.briar.api.db.NoSuchTransportException; import net.sf.briar.api.db.NoSuchTransportException;
import net.sf.briar.api.db.PrivateMessageHeader;
import net.sf.briar.api.db.event.ContactAddedEvent; import net.sf.briar.api.db.event.ContactAddedEvent;
import net.sf.briar.api.db.event.ContactRemovedEvent; import net.sf.briar.api.db.event.ContactRemovedEvent;
import net.sf.briar.api.db.event.DatabaseEvent; import net.sf.briar.api.db.event.DatabaseEvent;
import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.DatabaseListener;
import net.sf.briar.api.db.event.LocalRetentionTimeUpdatedEvent;
import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent; import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent;
import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent; import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent;
import net.sf.briar.api.db.event.MessageAddedEvent; import net.sf.briar.api.db.event.MessageAddedEvent;
import net.sf.briar.api.db.event.MessageExpiredEvent;
import net.sf.briar.api.db.event.MessageReceivedEvent; import net.sf.briar.api.db.event.MessageReceivedEvent;
import net.sf.briar.api.db.event.RatingChangedEvent; import net.sf.briar.api.db.event.RatingChangedEvent;
import net.sf.briar.api.db.event.RemoteRetentionTimeUpdatedEvent; import net.sf.briar.api.db.event.RemoteRetentionTimeUpdatedEvent;
@@ -52,6 +53,7 @@ import net.sf.briar.api.db.event.TransportAddedEvent;
import net.sf.briar.api.db.event.TransportRemovedEvent; import net.sf.briar.api.db.event.TransportRemovedEvent;
import net.sf.briar.api.lifecycle.ShutdownManager; import net.sf.briar.api.lifecycle.ShutdownManager;
import net.sf.briar.api.messaging.Ack; import net.sf.briar.api.messaging.Ack;
import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.messaging.AuthorId; import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.GroupId;
@@ -258,7 +260,7 @@ DatabaseCleaner.Callback {
try { try {
// Don't store the message if the user has // Don't store the message if the user has
// unsubscribed from the group // unsubscribed from the group
if(db.containsSubscription(txn, m.getGroup())) if(db.containsSubscription(txn, m.getGroup().getId()))
added = storeGroupMessage(txn, m, null); added = storeGroupMessage(txn, m, null);
db.commitTransaction(txn); db.commitTransaction(txn);
} catch(DbException e) { } catch(DbException e) {
@@ -318,8 +320,8 @@ DatabaseCleaner.Callback {
private int calculateSendability(T txn, Message m) throws DbException { private int calculateSendability(T txn, Message m) throws DbException {
int sendability = 0; int sendability = 0;
// One point for a good rating // One point for a good rating
AuthorId a = m.getAuthor(); Author a = m.getAuthor();
if(a != null && db.getRating(txn, a) == GOOD) sendability++; if(a != null && db.getRating(txn, a.getId()) == GOOD) sendability++;
// One point per sendable child (backward inclusion) // One point per sendable child (backward inclusion)
sendability += db.getNumberOfSendableChildren(txn, m.getId()); sendability += db.getNumberOfSendableChildren(txn, m.getId());
return sendability; return sendability;
@@ -445,10 +447,10 @@ DatabaseCleaner.Callback {
} }
/** /**
* If the given message is already in the database, returns false.
* Otherwise stores the message and marks it as new or seen with respect to * Otherwise stores the message and marks it as new or seen with respect to
* the given contact, depending on whether the message is outgoing or * the given contact, depending on whether the message is outgoing or
* incoming, respectively; or returns false if the message is already in * incoming, respectively.
* the database.
* <p> * <p>
* Locking: contact read, message write. * Locking: contact read, message write.
*/ */
@@ -457,9 +459,7 @@ DatabaseCleaner.Callback {
if(m.getGroup() != null) throw new IllegalArgumentException(); if(m.getGroup() != null) throw new IllegalArgumentException();
if(m.getAuthor() != null) throw new IllegalArgumentException(); if(m.getAuthor() != null) throw new IllegalArgumentException();
if(!db.addPrivateMessage(txn, m, c)) return false; if(!db.addPrivateMessage(txn, m, c)) return false;
MessageId id = m.getId(); db.addStatus(txn, c, m.getId(), incoming);
if(incoming) db.addStatus(txn, c, id, true);
else db.addStatus(txn, c, id, false);
// Count the bytes stored // Count the bytes stored
synchronized(spaceLock) { synchronized(spaceLock) {
bytesStoredSinceLastCheck += m.getSerialised().length; bytesStoredSinceLastCheck += m.getSerialised().length;
@@ -878,16 +878,18 @@ DatabaseCleaner.Callback {
} }
} }
public MessageHeader getMessageHeader(MessageId m) throws DbException { public Collection<GroupMessageHeader> getMessageHeaders(GroupId g)
throws DbException {
messageLock.readLock().lock(); messageLock.readLock().lock();
try { try {
T txn = db.startTransaction(); T txn = db.startTransaction();
try { try {
if(!db.containsMessage(txn, m)) if(!db.containsSubscription(txn, g))
throw new NoSuchMessageException(); throw new NoSuchSubscriptionException();
MessageHeader h = db.getMessageHeader(txn, m); Collection<GroupMessageHeader> headers =
db.getMessageHeaders(txn, g);
db.commitTransaction(txn); db.commitTransaction(txn);
return h; return headers;
} catch(DbException e) { } catch(DbException e) {
db.abortTransaction(txn); db.abortTransaction(txn);
throw e; throw e;
@@ -897,16 +899,14 @@ DatabaseCleaner.Callback {
} }
} }
public Collection<MessageHeader> getMessageHeaders(GroupId g) public Collection<PrivateMessageHeader> getPrivateMessageHeaders()
throws DbException { throws DbException {
messageLock.readLock().lock(); messageLock.readLock().lock();
try { try {
T txn = db.startTransaction(); T txn = db.startTransaction();
try { try {
if(!db.containsSubscription(txn, g)) Collection<PrivateMessageHeader> headers =
throw new NoSuchSubscriptionException(); db.getPrivateMessageHeaders(txn);
Collection<MessageHeader> headers =
db.getMessageHeaders(txn, g);
db.commitTransaction(txn); db.commitTransaction(txn);
return headers; return headers;
} catch(DbException e) { } catch(DbException e) {
@@ -1285,9 +1285,9 @@ DatabaseCleaner.Callback {
private boolean storeMessage(T txn, ContactId c, Message m) private boolean storeMessage(T txn, ContactId c, Message m)
throws DbException { throws DbException {
if(m.getTimestamp() > clock.currentTimeMillis()) return false; if(m.getTimestamp() > clock.currentTimeMillis()) return false;
GroupId g = m.getGroup(); Group g = m.getGroup();
if(g == null) return storePrivateMessage(txn, m, c, true); if(g == null) return storePrivateMessage(txn, m, c, true);
if(!db.containsVisibleSubscription(txn, c, g)) return false; if(!db.containsVisibleSubscription(txn, c, g.getId())) return false;
return storeGroupMessage(txn, m, c); return storeGroupMessage(txn, m, c);
} }
@@ -1846,7 +1846,7 @@ DatabaseCleaner.Callback {
} finally { } finally {
contactLock.readLock().unlock(); contactLock.readLock().unlock();
} }
if(removed) callListeners(new LocalRetentionTimeUpdatedEvent()); if(removed) callListeners(new MessageExpiredEvent());
return removed; return removed;
} }

View File

@@ -1,6 +1,7 @@
package net.sf.briar.db; package net.sf.briar.db;
import static java.sql.Types.BINARY; import static java.sql.Types.BINARY;
import static java.sql.Types.VARCHAR;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static net.sf.briar.api.Rating.UNRATED; import static net.sf.briar.api.Rating.UNRATED;
@@ -34,7 +35,9 @@ import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.clock.Clock; import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.db.DbClosedException; import net.sf.briar.api.db.DbClosedException;
import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.DbException;
import net.sf.briar.api.db.MessageHeader; import net.sf.briar.api.db.GroupMessageHeader;
import net.sf.briar.api.db.PrivateMessageHeader;
import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.messaging.AuthorId; import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.GroupId;
@@ -117,7 +120,9 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " (messageId HASH NOT NULL," + " (messageId HASH NOT NULL,"
+ " parentId HASH," // Null for the first msg in a thread + " parentId HASH," // Null for the first msg in a thread
+ " groupId HASH," // Null for private messages + " groupId HASH," // Null for private messages
+ " authorId HASH," // Null for private or anonymous msgs + " authorId HASH," // Null for private/anon messages
+ " authorName VARCHAR," // Null for private/anon messages
+ " authorKey VARCHAR," // Null for private/anon messages
+ " subject VARCHAR NOT NULL," + " subject VARCHAR NOT NULL,"
+ " timestamp BIGINT NOT NULL," + " timestamp BIGINT NOT NULL,"
+ " length INT NOT NULL," + " length INT NOT NULL,"
@@ -620,29 +625,38 @@ abstract class JdbcDatabase implements Database<Connection> {
public boolean addGroupMessage(Connection txn, Message m) public boolean addGroupMessage(Connection txn, Message m)
throws DbException { throws DbException {
assert m.getGroup() != null; if(m.getGroup() == null) throw new IllegalArgumentException();
if(containsMessage(txn, m.getId())) return false; if(containsMessage(txn, m.getId())) return false;
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "INSERT INTO messages (messageId, parentId, groupId," String sql = "INSERT INTO messages (messageId, parentId, groupId,"
+ " authorId, subject, timestamp, length, bodyStart," + " authorId, authorName, authorKey, subject, timestamp,"
+ " bodyLength, raw, sendability, read, starred)" + " length, bodyStart, bodyLength, raw, sendability, read,"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ZERO(), FALSE," + " starred)"
+ " FALSE)"; + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ZERO(),"
+ " FALSE, FALSE)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getId().getBytes()); ps.setBytes(1, m.getId().getBytes());
if(m.getParent() == null) ps.setNull(2, BINARY); if(m.getParent() == null) ps.setNull(2, BINARY);
else ps.setBytes(2, m.getParent().getBytes()); else ps.setBytes(2, m.getParent().getBytes());
ps.setBytes(3, m.getGroup().getBytes()); ps.setBytes(3, m.getGroup().getId().getBytes());
if(m.getAuthor() == null) ps.setNull(4, BINARY); Author a = m.getAuthor();
else ps.setBytes(4, m.getAuthor().getBytes()); if(a == null) {
ps.setString(5, m.getSubject()); ps.setNull(4, BINARY);
ps.setLong(6, m.getTimestamp()); ps.setNull(5, VARCHAR);
ps.setNull(6, BINARY);
} else {
ps.setBytes(4, a.getId().getBytes());
ps.setString(5, a.getName());
ps.setBytes(6, a.getPublicKey());
}
ps.setString(7, m.getSubject());
ps.setLong(8, m.getTimestamp());
byte[] raw = m.getSerialised(); byte[] raw = m.getSerialised();
ps.setInt(7, raw.length); ps.setInt(9, raw.length);
ps.setInt(8, m.getBodyStart()); ps.setInt(10, m.getBodyStart());
ps.setInt(9, m.getBodyLength()); ps.setInt(11, m.getBodyLength());
ps.setBytes(10, raw); ps.setBytes(12, raw);
int affected = ps.executeUpdate(); int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException(); if(affected != 1) throw new DbStateException();
ps.close(); ps.close();
@@ -686,13 +700,13 @@ abstract class JdbcDatabase implements Database<Connection> {
public boolean addPrivateMessage(Connection txn, Message m, ContactId c) public boolean addPrivateMessage(Connection txn, Message m, ContactId c)
throws DbException { throws DbException {
assert m.getGroup() == null; if(m.getGroup() != null) throw new IllegalArgumentException();
if(containsMessage(txn, m.getId())) return false; if(containsMessage(txn, m.getId())) return false;
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "INSERT INTO messages" String sql = "INSERT INTO messages (messageId, parentId, subject,"
+ " (messageId, parentId, subject, timestamp, length," + " timestamp, length, bodyStart, bodyLength, raw,"
+ " bodyStart, bodyLength, raw, contactId, read, starred)" + " contactId, read, starred)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, FALSE)"; + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, FALSE)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getId().getBytes()); ps.setBytes(1, m.getId().getBytes());
@@ -1211,33 +1225,42 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public MessageHeader getMessageHeader(Connection txn, MessageId m) public Collection<GroupMessageHeader> getMessageHeaders(Connection txn,
throws DbException { GroupId g) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT parentId, authorId, groupId, subject," String sql = "SELECT messageId, parentId, authorId, authorName,"
+ " timestamp, read, starred" + " authorKey, subject, timestamp, read, starred"
+ " FROM messages" + " FROM messages"
+ " WHERE messageId = ?"; + " WHERE groupId = ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes()); ps.setBytes(1, g.getBytes());
rs = ps.executeQuery(); rs = ps.executeQuery();
if(!rs.next()) throw new DbStateException(); List<GroupMessageHeader> headers =
byte[] b = rs.getBytes(1); new ArrayList<GroupMessageHeader>();
MessageId parent = b == null ? null : new MessageId(b); while(rs.next()) {
AuthorId author = new AuthorId(rs.getBytes(2)); MessageId id = new MessageId(rs.getBytes(1));
b = rs.getBytes(3); byte[] b = rs.getBytes(2);
GroupId group = b == null ? null : new GroupId(b); MessageId parent = b == null ? null : new MessageId(b);
String subject = rs.getString(4); Author author = null;
long timestamp = rs.getLong(5); b = rs.getBytes(3);
boolean read = rs.getBoolean(6); if(b != null) {
boolean starred = rs.getBoolean(7); AuthorId authorId = new AuthorId(b);
if(rs.next()) throw new DbStateException(); String authorName = rs.getString(4);
byte[] authorKey = rs.getBytes(5);
author = new Author(authorId, authorName, authorKey);
}
String subject = rs.getString(6);
long timestamp = rs.getLong(7);
boolean read = rs.getBoolean(8);
boolean starred = rs.getBoolean(9);
headers.add(new GroupMessageHeader(id, parent, subject,
timestamp, read, starred, g, author));
}
rs.close(); rs.close();
ps.close(); ps.close();
return new MessageHeader(m, parent, group, author, subject, return Collections.unmodifiableList(headers);
timestamp, read, starred);
} catch(SQLException e) { } catch(SQLException e) {
tryToClose(rs); tryToClose(rs);
tryToClose(ps); tryToClose(ps);
@@ -1245,30 +1268,33 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public Collection<MessageHeader> getMessageHeaders(Connection txn, public Collection<PrivateMessageHeader> getPrivateMessageHeaders(
GroupId g) throws DbException { Connection txn) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT messageId, parentId, authorId, subject," String sql = "SELECT m.messageId, parentId, subject, timestamp,"
+ " timestamp, read, starred" + " contactId, read, starred, seen"
+ " FROM messages" + " FROM messages AS m"
+ " WHERE groupId = ?"; + " JOIN statuses AS s"
+ " ON m.messageId = s.messageId"
+ " WHERE groupId IS NULL";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, g.getBytes());
rs = ps.executeQuery(); rs = ps.executeQuery();
List<MessageHeader> headers = new ArrayList<MessageHeader>(); List<PrivateMessageHeader> headers =
new ArrayList<PrivateMessageHeader>();
while(rs.next()) { while(rs.next()) {
MessageId id = new MessageId(rs.getBytes(1)); MessageId id = new MessageId(rs.getBytes(1));
byte[] p = rs.getBytes(2); byte[] b = rs.getBytes(2);
MessageId parent = p == null ? null : new MessageId(p); MessageId parent = b == null ? null : new MessageId(b);
AuthorId author = new AuthorId(rs.getBytes(3)); String subject = rs.getString(3);
String subject = rs.getString(4); long timestamp = rs.getLong(4);
long timestamp = rs.getLong(5); ContactId contactId = new ContactId(rs.getInt(5));
boolean read = rs.getBoolean(6); boolean read = rs.getBoolean(6);
boolean starred = rs.getBoolean(7); boolean starred = rs.getBoolean(7);
headers.add(new MessageHeader(id, parent, g, author, subject, boolean seen = rs.getBoolean(8);
timestamp, read, starred)); headers.add(new PrivateMessageHeader(id, parent, subject,
timestamp, read, starred, contactId, !seen));
} }
rs.close(); rs.close();
ps.close(); ps.close();

View File

@@ -20,9 +20,7 @@ import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest; import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.messaging.Author; import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.Message; import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageFactory; import net.sf.briar.api.messaging.MessageFactory;
import net.sf.briar.api.messaging.MessageId; import net.sf.briar.api.messaging.MessageId;
@@ -150,12 +148,9 @@ class MessageFactoryImpl implements MessageFactory {
} }
// Hash the message, including the signatures, to get the message ID // Hash the message, including the signatures, to get the message ID
w.removeConsumer(digestingConsumer); w.removeConsumer(digestingConsumer);
byte[] raw = out.toByteArray();
MessageId id = new MessageId(messageDigest.digest()); MessageId id = new MessageId(messageDigest.digest());
GroupId groupId = group == null ? null : group.getId(); return new MessageImpl(id, parent, group, author, subject,
AuthorId authorId = author == null ? null : author.getId(); timestamp, out.toByteArray(), bodyStart, body.length);
return new MessageImpl(id, parent, groupId, authorId, subject,
timestamp, raw, bodyStart, body.length);
} }
private void writeGroup(Writer w, Group g) throws IOException { private void writeGroup(Writer w, Group g) throws IOException {

View File

@@ -1,8 +1,8 @@
package net.sf.briar.messaging; package net.sf.briar.messaging;
import static net.sf.briar.api.messaging.MessagingConstants.MAX_BODY_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
import net.sf.briar.api.messaging.AuthorId; import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.Message; import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageId; import net.sf.briar.api.messaging.MessageId;
@@ -10,15 +10,15 @@ import net.sf.briar.api.messaging.MessageId;
class MessageImpl implements Message { class MessageImpl implements Message {
private final MessageId id, parent; private final MessageId id, parent;
private final GroupId group; private final Group group;
private final AuthorId author; private final Author author;
private final String subject; private final String subject;
private final long timestamp; private final long timestamp;
private final byte[] raw; private final byte[] raw;
private final int bodyStart, bodyLength; private final int bodyStart, bodyLength;
public MessageImpl(MessageId id, MessageId parent, GroupId group, public MessageImpl(MessageId id, MessageId parent, Group group,
AuthorId author, String subject, long timestamp, byte[] raw, Author author, String subject, long timestamp, byte[] raw,
int bodyStart, int bodyLength) { int bodyStart, int bodyLength) {
if(bodyStart + bodyLength > raw.length) if(bodyStart + bodyLength > raw.length)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@@ -43,11 +43,11 @@ class MessageImpl implements Message {
return parent; return parent;
} }
public GroupId getGroup() { public Group getGroup() {
return group; return group;
} }
public AuthorId getAuthor() { public Author getAuthor() {
return author; return author;
} }

View File

@@ -8,9 +8,7 @@ import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.KeyParser; import net.sf.briar.api.crypto.KeyParser;
import net.sf.briar.api.crypto.MessageDigest; import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.messaging.Author; import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.Message; import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageId; import net.sf.briar.api.messaging.MessageId;
import net.sf.briar.api.messaging.MessageVerifier; import net.sf.briar.api.messaging.MessageVerifier;
@@ -55,10 +53,7 @@ class MessageVerifierImpl implements MessageVerifier {
if(!signature.verify(m.getGroupSignature())) if(!signature.verify(m.getGroupSignature()))
throw new GeneralSecurityException(); throw new GeneralSecurityException();
} }
GroupId groupId = group == null ? null : group.getId(); return new MessageImpl(id, m.getParent(), group, author, m.getSubject(),
AuthorId authorId = author == null ? null : author.getId(); m.getTimestamp(), raw, m.getBodyStart(), m.getBodyLength());
return new MessageImpl(id, m.getParent(), groupId, authorId,
m.getSubject(), m.getTimestamp(), raw, m.getBodyStart(),
m.getBodyLength());
} }
} }

View File

@@ -29,7 +29,7 @@ import net.sf.briar.api.db.DbException;
import net.sf.briar.api.db.event.ContactRemovedEvent; import net.sf.briar.api.db.event.ContactRemovedEvent;
import net.sf.briar.api.db.event.DatabaseEvent; import net.sf.briar.api.db.event.DatabaseEvent;
import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.DatabaseListener;
import net.sf.briar.api.db.event.LocalRetentionTimeUpdatedEvent; import net.sf.briar.api.db.event.MessageExpiredEvent;
import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent; import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent;
import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent; import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent;
import net.sf.briar.api.db.event.MessageAddedEvent; import net.sf.briar.api.db.event.MessageAddedEvent;
@@ -134,7 +134,7 @@ abstract class DuplexConnection implements DatabaseListener {
if(e instanceof ContactRemovedEvent) { if(e instanceof ContactRemovedEvent) {
ContactRemovedEvent c = (ContactRemovedEvent) e; ContactRemovedEvent c = (ContactRemovedEvent) e;
if(contactId.equals(c.getContactId())) dispose(false, true); if(contactId.equals(c.getContactId())) dispose(false, true);
} else if(e instanceof LocalRetentionTimeUpdatedEvent) { } else if(e instanceof MessageExpiredEvent) {
dbExecutor.execute(new GenerateRetentionUpdate()); dbExecutor.execute(new GenerateRetentionUpdate());
} else if(e instanceof LocalSubscriptionsUpdatedEvent) { } else if(e instanceof LocalSubscriptionsUpdatedEvent) {
LocalSubscriptionsUpdatedEvent l = LocalSubscriptionsUpdatedEvent l =

View File

@@ -3,28 +3,28 @@ package net.sf.briar;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import net.sf.briar.api.messaging.AuthorId; import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.Message; import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageId; import net.sf.briar.api.messaging.MessageId;
public class TestMessage implements Message { public class TestMessage implements Message {
private final MessageId id, parent; private final MessageId id, parent;
private final GroupId group; private final Group group;
private final AuthorId author; private final Author author;
private final String subject; private final String subject;
private final long timestamp; private final long timestamp;
private final byte[] raw; private final byte[] raw;
private final int bodyStart, bodyLength; private final int bodyStart, bodyLength;
public TestMessage(MessageId id, MessageId parent, GroupId group, public TestMessage(MessageId id, MessageId parent, Group group,
AuthorId author, String subject, long timestamp, byte[] raw) { Author author, String subject, long timestamp, byte[] raw) {
this(id, parent, group, author, subject, timestamp, raw, 0, raw.length); this(id, parent, group, author, subject, timestamp, raw, 0, raw.length);
} }
public TestMessage(MessageId id, MessageId parent, GroupId group, public TestMessage(MessageId id, MessageId parent, Group group,
AuthorId author, String subject, long timestamp, byte[] raw, Author author, String subject, long timestamp, byte[] raw,
int bodyStart, int bodyLength) { int bodyStart, int bodyLength) {
this.id = id; this.id = id;
this.parent = parent; this.parent = parent;
@@ -45,11 +45,11 @@ public class TestMessage implements Message {
return parent; return parent;
} }
public GroupId getGroup() { public Group getGroup() {
return group; return group;
} }
public AuthorId getAuthor() { public Author getAuthor() {
return author; return author;
} }

View File

@@ -29,6 +29,7 @@ import net.sf.briar.api.db.event.MessageAddedEvent;
import net.sf.briar.api.db.event.RatingChangedEvent; import net.sf.briar.api.db.event.RatingChangedEvent;
import net.sf.briar.api.lifecycle.ShutdownManager; import net.sf.briar.api.lifecycle.ShutdownManager;
import net.sf.briar.api.messaging.Ack; import net.sf.briar.api.messaging.Ack;
import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.messaging.AuthorId; import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.GroupId;
@@ -53,43 +54,46 @@ import org.junit.Test;
public abstract class DatabaseComponentTest extends BriarTestCase { public abstract class DatabaseComponentTest extends BriarTestCase {
protected final Object txn = new Object(); protected final Object txn = new Object();
protected final AuthorId authorId;
protected final ContactId contactId;
protected final GroupId groupId; protected final GroupId groupId;
protected final Group group;
protected final AuthorId authorId;
protected final Author author;
protected final MessageId messageId, messageId1; protected final MessageId messageId, messageId1;
private final String contactName, subject; protected final String subject;
private final long timestamp; protected final long timestamp;
private final int size; protected final int size;
private final byte[] raw; protected final byte[] raw;
private final Contact contact; protected final Message message, privateMessage;
private final Message message, privateMessage; protected final TransportId transportId;
private final Group group; protected final TransportProperties transportProperties;
private final TransportId transportId; protected final ContactId contactId;
private final TransportProperties transportProperties; protected final String contactName;
private final Endpoint endpoint; protected final Contact contact;
private final TemporarySecret temporarySecret; protected final Endpoint endpoint;
protected final TemporarySecret temporarySecret;
public DatabaseComponentTest() { public DatabaseComponentTest() {
super(); super();
authorId = new AuthorId(TestUtils.getRandomId());
contactId = new ContactId(234);
groupId = new GroupId(TestUtils.getRandomId()); groupId = new GroupId(TestUtils.getRandomId());
group = new Group(groupId, "Group name", null);
authorId = new AuthorId(TestUtils.getRandomId());
author = new Author(authorId, "Alice", new byte[60]);
messageId = new MessageId(TestUtils.getRandomId()); messageId = new MessageId(TestUtils.getRandomId());
messageId1 = new MessageId(TestUtils.getRandomId()); messageId1 = new MessageId(TestUtils.getRandomId());
contactName = "Alice";
subject = "Foo"; subject = "Foo";
timestamp = System.currentTimeMillis(); timestamp = System.currentTimeMillis();
size = 1234; size = 1234;
raw = new byte[size]; raw = new byte[size];
contact = new Contact(contactId, contactName, timestamp); message = new TestMessage(messageId, null, group, author, subject,
message = new TestMessage(messageId, null, groupId, authorId, subject,
timestamp, raw); timestamp, raw);
privateMessage = new TestMessage(messageId, null, null, null, subject, privateMessage = new TestMessage(messageId, null, null, null, subject,
timestamp, raw); timestamp, raw);
group = new Group(groupId, "The really exciting group", null);
transportId = new TransportId(TestUtils.getRandomId()); transportId = new TransportId(TestUtils.getRandomId());
transportProperties = new TransportProperties( transportProperties = new TransportProperties(Collections.singletonMap(
Collections.singletonMap("foo", "bar")); "foo", "bar"));
contactId = new ContactId(234);
contactName = "Alice";
contact = new Contact(contactId, contactName, timestamp);
endpoint = new Endpoint(contactId, transportId, 123, 234, 345, true); endpoint = new Endpoint(contactId, transportId, 123, 234, 345, true);
temporarySecret = new TemporarySecret(contactId, transportId, 1, 2, temporarySecret = new TemporarySecret(contactId, transportId, 1, 2,
3, false, 4, new byte[32], 5, 6, new byte[4]); 3, false, 4, new byte[32], 5, 6, new byte[4]);

View File

@@ -28,7 +28,8 @@ import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportProperties; import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.clock.SystemClock; import net.sf.briar.api.clock.SystemClock;
import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.DbException;
import net.sf.briar.api.db.MessageHeader; import net.sf.briar.api.db.GroupMessageHeader;
import net.sf.briar.api.messaging.Author;
import net.sf.briar.api.messaging.AuthorId; import net.sf.briar.api.messaging.AuthorId;
import net.sf.briar.api.messaging.Group; import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.GroupId; import net.sf.briar.api.messaging.GroupId;
@@ -50,37 +51,40 @@ public class H2DatabaseTest extends BriarTestCase {
private final File testDir = TestUtils.getTestDirectory(); private final File testDir = TestUtils.getTestDirectory();
private final Random random = new Random(); private final Random random = new Random();
private final GroupId groupId;
private final Group group; private final Group group;
private final AuthorId authorId; private final AuthorId authorId;
private final ContactId contactId; private final Author author;
private final GroupId groupId;
private final MessageId messageId, messageId1; private final MessageId messageId, messageId1;
private final String contactName, subject; private final String subject;
private final long timestamp; private final long timestamp;
private final int size; private final int size;
private final byte[] raw; private final byte[] raw;
private final Message message, privateMessage; private final Message message, privateMessage;
private final TransportId transportId; private final TransportId transportId;
private final ContactId contactId;
private final String contactName;
public H2DatabaseTest() throws Exception { public H2DatabaseTest() throws Exception {
super(); super();
authorId = new AuthorId(TestUtils.getRandomId());
contactId = new ContactId(1);
groupId = new GroupId(TestUtils.getRandomId()); groupId = new GroupId(TestUtils.getRandomId());
group = new Group(groupId, "Group name", null);
authorId = new AuthorId(TestUtils.getRandomId());
author = new Author(authorId, "Alice", new byte[60]);
messageId = new MessageId(TestUtils.getRandomId()); messageId = new MessageId(TestUtils.getRandomId());
messageId1 = new MessageId(TestUtils.getRandomId()); messageId1 = new MessageId(TestUtils.getRandomId());
group = new Group(groupId, "Foo", null);
contactName = "Alice";
subject = "Foo"; subject = "Foo";
timestamp = System.currentTimeMillis(); timestamp = System.currentTimeMillis();
size = 1234; size = 1234;
raw = new byte[size]; raw = new byte[size];
random.nextBytes(raw); random.nextBytes(raw);
message = new TestMessage(messageId, null, groupId, authorId, subject, message = new TestMessage(messageId, null, group, author, subject,
timestamp, raw); timestamp, raw);
privateMessage = new TestMessage(messageId1, null, null, null, privateMessage = new TestMessage(messageId1, null, null, null,
subject, timestamp, raw); subject, timestamp, raw);
transportId = new TransportId(TestUtils.getRandomId()); transportId = new TransportId(TestUtils.getRandomId());
contactId = new ContactId(1);
contactName = "Alice";
} }
@Before @Before
@@ -545,8 +549,9 @@ public class H2DatabaseTest extends BriarTestCase {
@Test @Test
public void testGetMessagesByAuthor() throws Exception { public void testGetMessagesByAuthor() throws Exception {
AuthorId authorId1 = new AuthorId(TestUtils.getRandomId()); AuthorId authorId1 = new AuthorId(TestUtils.getRandomId());
Author author1 = new Author(authorId1, "Bob", new byte[60]);
MessageId messageId1 = new MessageId(TestUtils.getRandomId()); MessageId messageId1 = new MessageId(TestUtils.getRandomId());
Message message1 = new TestMessage(messageId1, null, groupId, authorId1, Message message1 = new TestMessage(messageId1, null, group, author1,
subject, timestamp, raw); subject, timestamp, raw);
Database<Connection> db = open(false); Database<Connection> db = open(false);
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
@@ -577,15 +582,14 @@ public class H2DatabaseTest extends BriarTestCase {
MessageId childId2 = new MessageId(TestUtils.getRandomId()); MessageId childId2 = new MessageId(TestUtils.getRandomId());
MessageId childId3 = new MessageId(TestUtils.getRandomId()); MessageId childId3 = new MessageId(TestUtils.getRandomId());
GroupId groupId1 = new GroupId(TestUtils.getRandomId()); GroupId groupId1 = new GroupId(TestUtils.getRandomId());
Group group1 = new Group(groupId1, "Another group name", Group group1 = new Group(groupId1, "Group name", null);
null); Message child1 = new TestMessage(childId1, messageId, group, author,
Message child1 = new TestMessage(childId1, messageId, groupId, subject, timestamp, raw);
authorId, subject, timestamp, raw); Message child2 = new TestMessage(childId2, messageId, group, author,
Message child2 = new TestMessage(childId2, messageId, groupId, subject, timestamp, raw);
authorId, subject, timestamp, raw);
// The third child is in a different group // The third child is in a different group
Message child3 = new TestMessage(childId3, messageId, groupId1, Message child3 = new TestMessage(childId3, messageId, group1, author,
authorId, subject, timestamp, raw); subject, timestamp, raw);
Database<Connection> db = open(false); Database<Connection> db = open(false);
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
@@ -615,7 +619,7 @@ public class H2DatabaseTest extends BriarTestCase {
@Test @Test
public void testGetOldMessages() throws Exception { public void testGetOldMessages() throws Exception {
MessageId messageId1 = new MessageId(TestUtils.getRandomId()); MessageId messageId1 = new MessageId(TestUtils.getRandomId());
Message message1 = new TestMessage(messageId1, null, groupId, authorId, Message message1 = new TestMessage(messageId1, null, group, author,
subject, timestamp + 1000, raw); subject, timestamp + 1000, raw);
Database<Connection> db = open(false); Database<Connection> db = open(false);
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
@@ -646,7 +650,7 @@ public class H2DatabaseTest extends BriarTestCase {
public void testGetFreeSpace() throws Exception { public void testGetFreeSpace() throws Exception {
byte[] largeBody = new byte[ONE_MEGABYTE]; byte[] largeBody = new byte[ONE_MEGABYTE];
for(int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i; for(int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i;
Message message1 = new TestMessage(messageId, null, groupId, authorId, Message message1 = new TestMessage(messageId, null, group, author,
subject, timestamp, largeBody); subject, timestamp, largeBody);
Database<Connection> db = open(false); Database<Connection> db = open(false);
@@ -1126,7 +1130,7 @@ public class H2DatabaseTest extends BriarTestCase {
// A message with no parent should return null // A message with no parent should return null
MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId childId = new MessageId(TestUtils.getRandomId());
Message child = new TestMessage(childId, null, groupId, null, subject, Message child = new TestMessage(childId, null, group, null, subject,
timestamp, raw); timestamp, raw);
db.addGroupMessage(txn, child); db.addGroupMessage(txn, child);
assertTrue(db.containsMessage(txn, childId)); assertTrue(db.containsMessage(txn, childId));
@@ -1147,7 +1151,7 @@ public class H2DatabaseTest extends BriarTestCase {
// A message with an absent parent should return null // A message with an absent parent should return null
MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId childId = new MessageId(TestUtils.getRandomId());
MessageId parentId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId());
Message child = new TestMessage(childId, parentId, groupId, null, Message child = new TestMessage(childId, parentId, group, null,
subject, timestamp, raw); subject, timestamp, raw);
db.addGroupMessage(txn, child); db.addGroupMessage(txn, child);
assertTrue(db.containsMessage(txn, childId)); assertTrue(db.containsMessage(txn, childId));
@@ -1173,9 +1177,9 @@ public class H2DatabaseTest extends BriarTestCase {
// A message with a parent in another group should return null // A message with a parent in another group should return null
MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId childId = new MessageId(TestUtils.getRandomId());
MessageId parentId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId());
Message child = new TestMessage(childId, parentId, groupId, null, Message child = new TestMessage(childId, parentId, group, null,
subject, timestamp, raw); subject, timestamp, raw);
Message parent = new TestMessage(parentId, null, groupId1, null, Message parent = new TestMessage(parentId, null, group1, null,
subject, timestamp, raw); subject, timestamp, raw);
db.addGroupMessage(txn, child); db.addGroupMessage(txn, child);
db.addGroupMessage(txn, parent); db.addGroupMessage(txn, parent);
@@ -1198,8 +1202,8 @@ public class H2DatabaseTest extends BriarTestCase {
// A message with a private parent should return null // A message with a private parent should return null
MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId childId = new MessageId(TestUtils.getRandomId());
Message child = new TestMessage(childId, messageId1, groupId, Message child = new TestMessage(childId, messageId1, group, null,
null, subject, timestamp, raw); subject, timestamp, raw);
db.addGroupMessage(txn, child); db.addGroupMessage(txn, child);
db.addPrivateMessage(txn, privateMessage, contactId); db.addPrivateMessage(txn, privateMessage, contactId);
assertTrue(db.containsMessage(txn, childId)); assertTrue(db.containsMessage(txn, childId));
@@ -1222,10 +1226,10 @@ public class H2DatabaseTest extends BriarTestCase {
// A message with a parent in the same group should return the parent // A message with a parent in the same group should return the parent
MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId childId = new MessageId(TestUtils.getRandomId());
MessageId parentId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId());
Message child = new TestMessage(childId, parentId, groupId, null, Message child = new TestMessage(childId, parentId, group, null,
subject, timestamp, raw);
Message parent = new TestMessage(parentId, null, groupId, null,
subject, timestamp, raw); subject, timestamp, raw);
Message parent = new TestMessage(parentId, null, group, null, subject,
timestamp, raw);
db.addGroupMessage(txn, child); db.addGroupMessage(txn, child);
db.addGroupMessage(txn, parent); db.addGroupMessage(txn, parent);
assertTrue(db.containsMessage(txn, childId)); assertTrue(db.containsMessage(txn, childId));
@@ -1247,7 +1251,7 @@ public class H2DatabaseTest extends BriarTestCase {
// Store a couple of messages // Store a couple of messages
int bodyLength = raw.length - 20; int bodyLength = raw.length - 20;
Message message1 = new TestMessage(messageId, null, groupId, null, Message message1 = new TestMessage(messageId, null, group, null,
subject, timestamp, raw, 5, bodyLength); subject, timestamp, raw, 5, bodyLength);
Message privateMessage1 = new TestMessage(messageId1, null, null, Message privateMessage1 = new TestMessage(messageId1, null, null,
null, subject, timestamp, raw, 10, bodyLength); null, subject, timestamp, raw, 10, bodyLength);
@@ -1289,19 +1293,20 @@ public class H2DatabaseTest extends BriarTestCase {
MessageId messageId1 = new MessageId(TestUtils.getRandomId()); MessageId messageId1 = new MessageId(TestUtils.getRandomId());
MessageId parentId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId());
long timestamp1 = System.currentTimeMillis(); long timestamp1 = System.currentTimeMillis();
Message message1 = new TestMessage(messageId1, parentId, groupId, Message message1 = new TestMessage(messageId1, parentId, group, author,
authorId, subject, timestamp1, raw); subject, timestamp1, raw);
db.addGroupMessage(txn, message1); db.addGroupMessage(txn, message1);
// Mark one of the messages read // Mark one of the messages read
assertFalse(db.setReadFlag(txn, messageId, true)); assertFalse(db.setReadFlag(txn, messageId, true));
// Retrieve the message headers // Retrieve the message headers
Collection<MessageHeader> headers = db.getMessageHeaders(txn, groupId); Collection<GroupMessageHeader> headers =
Iterator<MessageHeader> it = headers.iterator(); db.getMessageHeaders(txn, groupId);
Iterator<GroupMessageHeader> it = headers.iterator();
boolean messageFound = false, message1Found = false; boolean messageFound = false, message1Found = false;
// First header (order is undefined) // First header (order is undefined)
assertTrue(it.hasNext()); assertTrue(it.hasNext());
MessageHeader header = it.next(); GroupMessageHeader header = it.next();
if(messageId.equals(header.getId())) { if(messageId.equals(header.getId())) {
assertHeadersMatch(message, header); assertHeadersMatch(message, header);
assertTrue(header.getRead()); assertTrue(header.getRead());
@@ -1340,12 +1345,11 @@ public class H2DatabaseTest extends BriarTestCase {
db.close(); db.close();
} }
private void assertHeadersMatch(Message m, MessageHeader h) { private void assertHeadersMatch(Message m, GroupMessageHeader h) {
assertEquals(m.getId(), h.getId()); assertEquals(m.getId(), h.getId());
if(m.getParent() == null) assertNull(h.getParent()); if(m.getParent() == null) assertNull(h.getParent());
else assertEquals(m.getParent(), h.getParent()); else assertEquals(m.getParent(), h.getParent());
if(m.getGroup() == null) assertNull(h.getGroup()); assertEquals(m.getGroup().getId(), h.getGroupId());
else assertEquals(m.getGroup(), h.getGroup());
if(m.getAuthor() == null) assertNull(h.getAuthor()); if(m.getAuthor() == null) assertNull(h.getAuthor());
else assertEquals(m.getAuthor(), h.getAuthor()); else assertEquals(m.getAuthor(), h.getAuthor());
assertEquals(m.getSubject(), h.getSubject()); assertEquals(m.getSubject(), h.getSubject());
@@ -1412,20 +1416,20 @@ public class H2DatabaseTest extends BriarTestCase {
// Subscribe to a couple of groups // Subscribe to a couple of groups
db.addSubscription(txn, group); db.addSubscription(txn, group);
GroupId groupId1 = new GroupId(TestUtils.getRandomId()); GroupId groupId1 = new GroupId(TestUtils.getRandomId());
Group group1 = new Group(groupId1, "Another group", null); Group group1 = new Group(groupId1, "Group name", null);
db.addSubscription(txn, group1); db.addSubscription(txn, group1);
// Store two messages in the first group // Store two messages in the first group
db.addGroupMessage(txn, message); db.addGroupMessage(txn, message);
MessageId messageId1 = new MessageId(TestUtils.getRandomId()); MessageId messageId1 = new MessageId(TestUtils.getRandomId());
Message message1 = new TestMessage(messageId1, null, groupId, Message message1 = new TestMessage(messageId1, null, group, author,
authorId, subject, timestamp, raw); subject, timestamp, raw);
db.addGroupMessage(txn, message1); db.addGroupMessage(txn, message1);
// Store one message in the second group // Store one message in the second group
MessageId messageId2 = new MessageId(TestUtils.getRandomId()); MessageId messageId2 = new MessageId(TestUtils.getRandomId());
Message message2 = new TestMessage(messageId2, null, groupId1, Message message2 = new TestMessage(messageId2, null, group1, author,
authorId, subject, timestamp, raw); subject, timestamp, raw);
db.addGroupMessage(txn, message2); db.addGroupMessage(txn, message2);
// Mark one of the messages in the first group read // Mark one of the messages in the first group read