mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 21:29:54 +01:00
Added columns to the DB to support retrieval of message headers.
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
31
briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java
Normal file
31
briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
31
briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java
Normal file
31
briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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 {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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]);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user