diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java index 0bf6e058b0eeeeb5386109709930f5706523352c..2d9015362cf38748c6ba34926222d72925b438cd 100644 --- a/components/net/sf/briar/db/Database.java +++ b/components/net/sf/briar/db/Database.java @@ -92,7 +92,7 @@ interface Database<T> { * <p> * Locking: messages write. */ - boolean addMessage(T txn, Message m) throws DbException; + boolean addGroupMessage(T txn, Message m) throws DbException; /** * Records a sent batch as needing to be acknowledged. @@ -102,6 +102,14 @@ interface Database<T> { void addOutstandingBatch(T txn, ContactId c, BatchId b, Collection<MessageId> sent) throws DbException; + /** + * Returns false if the given message is already in the database. Otherwise + * stores the message and returns true. + * <p> + * Locking: contacts read, messages write. + */ + boolean addPrivateMessage(T txn, Message m, ContactId c) throws DbException; + /** * Subscribes to the given group. * <p> @@ -360,8 +368,8 @@ interface Database<T> { /** * Removes a contact (and all associated state) from the database. * <p> - * Locking: contacts write, messageStatuses write, subscriptions write, - * transports write. + * Locking: contacts write, messages write, messageStatuses write, + * subscriptions write, transports write. */ void removeContact(T txn, ContactId c) throws DbException; diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java index 6d251245d74eea6e7e99b976e9bb4092a016ff84..55ca48a4bfc811e162f518b9550815be2f6dabd9 100644 --- a/components/net/sf/briar/db/DatabaseComponentImpl.java +++ b/components/net/sf/briar/db/DatabaseComponentImpl.java @@ -179,7 +179,7 @@ DatabaseCleaner.Callback { protected boolean storeGroupMessage(Txn txn, Message m, ContactId sender) throws DbException { if(m.getGroup() == null) throw new IllegalArgumentException(); - boolean stored = db.addMessage(txn, m); + boolean stored = db.addGroupMessage(txn, m); // Mark the message as seen by the sender MessageId id = m.getId(); if(sender != null) db.setStatus(txn, sender, id, Status.SEEN); @@ -229,7 +229,7 @@ DatabaseCleaner.Callback { protected boolean storePrivateMessage(Txn txn, Message m, ContactId c, boolean incoming) throws DbException { if(m.getGroup() != null) throw new IllegalArgumentException(); - if(!db.addMessage(txn, m)) return false; + if(!db.addPrivateMessage(txn, m, c)) return false; MessageId id = m.getId(); if(incoming) db.setStatus(txn, c, id, Status.SEEN); else db.setStatus(txn, c, id, Status.NEW); diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java index 099ac144f462ff199769d3785bc3936850a8e176..2ff792ff9f65c2e1537f26c0334313478773e2be 100644 --- a/components/net/sf/briar/db/JdbcDatabase.java +++ b/components/net/sf/briar/db/JdbcDatabase.java @@ -49,6 +49,12 @@ abstract class JdbcDatabase implements Database<Connection> { + " start BIGINT NOT NULL," + " PRIMARY KEY (groupId))"; + private static final String CREATE_CONTACTS = + "CREATE TABLE contacts" + + " (contactId INT NOT NULL," + + " secret BINARY NOT NULL," + + " PRIMARY KEY (contactId))"; + private static final String CREATE_MESSAGES = "CREATE TABLE messages" + " (messageId HASH NOT NULL," @@ -58,9 +64,12 @@ abstract class JdbcDatabase implements Database<Connection> { + " timestamp BIGINT NOT NULL," + " size INT NOT NULL," + " raw BLOB NOT NULL," - + " sendability INT NOT NULL," + + " sendability INT," + + " contactId INT," + " PRIMARY KEY (messageId)," + " FOREIGN KEY (groupId) REFERENCES subscriptions (groupId)" + + " ON DELETE CASCADE," + + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; private static final String INDEX_MESSAGES_BY_PARENT = @@ -75,12 +84,6 @@ abstract class JdbcDatabase implements Database<Connection> { private static final String INDEX_MESSAGES_BY_SENDABILITY = "CREATE INDEX messagesBySendability ON messages (sendability)"; - private static final String CREATE_CONTACTS = - "CREATE TABLE contacts" - + " (contactId INT NOT NULL," - + " secret BINARY NOT NULL," - + " PRIMARY KEY (contactId))"; - private static final String CREATE_VISIBILITIES = "CREATE TABLE visibilities" + " (groupId HASH NOT NULL," @@ -278,12 +281,12 @@ abstract class JdbcDatabase implements Database<Connection> { try { s = txn.createStatement(); s.executeUpdate(insertTypeNames(CREATE_SUBSCRIPTIONS)); + s.executeUpdate(insertTypeNames(CREATE_CONTACTS)); s.executeUpdate(insertTypeNames(CREATE_MESSAGES)); s.executeUpdate(INDEX_MESSAGES_BY_PARENT); s.executeUpdate(INDEX_MESSAGES_BY_AUTHOR); s.executeUpdate(INDEX_MESSAGES_BY_BIGINT); s.executeUpdate(INDEX_MESSAGES_BY_SENDABILITY); - s.executeUpdate(insertTypeNames(CREATE_CONTACTS)); s.executeUpdate(insertTypeNames(CREATE_VISIBILITIES)); s.executeUpdate(INDEX_VISIBILITIES_BY_GROUP); s.executeUpdate(insertTypeNames(CREATE_BATCHES_TO_ACK)); @@ -527,14 +530,16 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public boolean addMessage(Connection txn, Message m) throws DbException { + public boolean addGroupMessage(Connection txn, Message m) + throws DbException { + assert m.getGroup() != null; if(containsMessage(txn, m.getId())) return false; PreparedStatement ps = null; try { String sql = "INSERT INTO messages" + " (messageId, parentId, groupId, authorId, timestamp, size," + " raw, sendability)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + + " VALUES (?, ?, ?, ?, ?, ?, ?, ZERO())"; ps = txn.prepareStatement(sql); ps.setBytes(1, m.getId().getBytes()); if(m.getParent() == null) ps.setNull(2, Types.BINARY); @@ -546,7 +551,6 @@ abstract class JdbcDatabase implements Database<Connection> { ps.setInt(6, m.getSize()); byte[] raw = m.getBytes(); ps.setBinaryStream(7, new ByteArrayInputStream(raw), raw.length); - ps.setInt(8, 0); int affected = ps.executeUpdate(); if(affected != 1) throw new DbStateException(); ps.close(); @@ -616,6 +620,34 @@ abstract class JdbcDatabase implements Database<Connection> { } } + public boolean addPrivateMessage(Connection txn, Message m, ContactId c) + throws DbException { + assert m.getGroup() == null; + if(containsMessage(txn, m.getId())) return false; + PreparedStatement ps = null; + try { + String sql = "INSERT INTO messages" + + " (messageId, parentId, timestamp, size, raw, contactId)" + + " VALUES (?, ?, ?, ?, ?, ?)"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, m.getId().getBytes()); + if(m.getParent() == null) ps.setNull(2, Types.BINARY); + else ps.setBytes(2, m.getParent().getBytes()); + ps.setLong(3, m.getTimestamp()); + ps.setInt(4, m.getSize()); + byte[] raw = m.getBytes(); + ps.setBinaryStream(5, new ByteArrayInputStream(raw), raw.length); + ps.setInt(6, c.getInt()); + int affected = ps.executeUpdate(); + if(affected != 1) throw new DbStateException(); + ps.close(); + return true; + } catch(SQLException e) { + tryToClose(ps); + throw new DbException(e); + } + } + public void addSubscription(Connection txn, Group g) throws DbException { PreparedStatement ps = null; try { diff --git a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java index b4b3bfeeb9b312b89403c3b4a09090c80d91390c..f7c50d561935120326e6bca2044fdf38ee9d03ea 100644 --- a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java +++ b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java @@ -909,28 +909,33 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { if(LOG.isLoggable(Level.FINE)) LOG.fine("Removing contact " + c); contactLock.writeLock().lock(); try { - messageStatusLock.writeLock().lock(); + messageLock.writeLock().lock(); try { - subscriptionLock.writeLock().lock(); + messageStatusLock.writeLock().lock(); try { - transportLock.writeLock().lock(); + subscriptionLock.writeLock().lock(); try { - Txn txn = db.startTransaction(); + transportLock.writeLock().lock(); try { - db.removeContact(txn, c); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; + Txn txn = db.startTransaction(); + try { + db.removeContact(txn, c); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } finally { + transportLock.writeLock().unlock(); } } finally { - transportLock.writeLock().unlock(); + subscriptionLock.writeLock().unlock(); } } finally { - subscriptionLock.writeLock().unlock(); + messageStatusLock.writeLock().unlock(); } } finally { - messageStatusLock.writeLock().unlock(); + messageLock.writeLock().unlock(); } } finally { contactLock.writeLock().unlock(); diff --git a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java index 4c7728f021db87acbfad11bfa8fa2ff6cb918550..df3fccd33df8d19d139e6b2fe1280db5ba0a8fe9 100644 --- a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java +++ b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java @@ -689,16 +689,18 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { public void removeContact(ContactId c) throws DbException { if(LOG.isLoggable(Level.FINE)) LOG.fine("Removing contact " + c); synchronized(contactLock) { - synchronized(messageStatusLock) { - synchronized(subscriptionLock) { - synchronized(transportLock) { - Txn txn = db.startTransaction(); - try { - db.removeContact(txn, c); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; + synchronized(messageLock) { + synchronized(messageStatusLock) { + synchronized(subscriptionLock) { + synchronized(transportLock) { + Txn txn = db.startTransaction(); + try { + db.removeContact(txn, c); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } } } } diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index ef0cc020fb708c4cd9fb7d12cca969d2c27fe885..a90b64e5b958a6439d7fc453eeeb1fba6b6a397a 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -367,7 +367,7 @@ public abstract class DatabaseComponentTest extends TestCase { final Database<Object> database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); context.checking(new Expectations() {{ - // addLocallyGeneratedMessage(message) + // addLocalGroupMessage(message) oneOf(database).startTransaction(); will(returnValue(txn)); oneOf(database).containsSubscription(txn, groupId, timestamp); @@ -388,12 +388,12 @@ public abstract class DatabaseComponentTest extends TestCase { final Database<Object> database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); context.checking(new Expectations() {{ - // addLocallyGeneratedMessage(message) + // addLocalGroupMessage(message) oneOf(database).startTransaction(); will(returnValue(txn)); oneOf(database).containsSubscription(txn, groupId, timestamp); will(returnValue(true)); - oneOf(database).addMessage(txn, message); + oneOf(database).addGroupMessage(txn, message); will(returnValue(false)); oneOf(database).commitTransaction(txn); }}); @@ -405,18 +405,18 @@ public abstract class DatabaseComponentTest extends TestCase { } @Test - public void testAddLocallyGeneratedMessage() throws DbException { + public void testAddLocalGroupMessage() throws DbException { Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database<Object> database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); context.checking(new Expectations() {{ - // addLocallyGeneratedMessage(message) + // addLocalGroupMessage(message) oneOf(database).startTransaction(); will(returnValue(txn)); oneOf(database).containsSubscription(txn, groupId, timestamp); will(returnValue(true)); - oneOf(database).addMessage(txn, message); + oneOf(database).addGroupMessage(txn, message); will(returnValue(true)); oneOf(database).getContacts(txn); will(returnValue(Collections.singletonList(contactId))); @@ -444,12 +444,12 @@ public abstract class DatabaseComponentTest extends TestCase { final Database<Object> database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); context.checking(new Expectations() {{ - // addLocallyGeneratedMessage(message) + // addLocalGroupMessage(message) oneOf(database).startTransaction(); will(returnValue(txn)); oneOf(database).containsSubscription(txn, groupId, timestamp); will(returnValue(true)); - oneOf(database).addMessage(txn, message); + oneOf(database).addGroupMessage(txn, message); will(returnValue(true)); oneOf(database).getContacts(txn); will(returnValue(Collections.singletonList(contactId))); @@ -896,7 +896,7 @@ public abstract class DatabaseComponentTest extends TestCase { contactId, timestamp); will(returnValue(true)); // The message is stored, but it's a duplicate - oneOf(database).addMessage(txn, message); + oneOf(database).addGroupMessage(txn, message); will(returnValue(false)); oneOf(database).setStatus(txn, contactId, messageId, Status.SEEN); // The batch needs to be acknowledged @@ -931,7 +931,7 @@ public abstract class DatabaseComponentTest extends TestCase { contactId, timestamp); will(returnValue(true)); // The message is stored, and it's not a duplicate - oneOf(database).addMessage(txn, message); + oneOf(database).addGroupMessage(txn, message); will(returnValue(true)); oneOf(database).setStatus(txn, contactId, messageId, Status.SEEN); // Set the status to NEW for all other contacts (there are none) @@ -975,7 +975,7 @@ public abstract class DatabaseComponentTest extends TestCase { contactId, timestamp); will(returnValue(true)); // The message is stored, and it's not a duplicate - oneOf(database).addMessage(txn, message); + oneOf(database).addGroupMessage(txn, message); will(returnValue(true)); oneOf(database).setStatus(txn, contactId, messageId, Status.SEEN); // Set the status to NEW for all other contacts (there are none) @@ -1110,12 +1110,12 @@ public abstract class DatabaseComponentTest extends TestCase { final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final DatabaseListener listener = context.mock(DatabaseListener.class); context.checking(new Expectations() {{ - // addLocallyGeneratedMessage(message) + // addLocalGroupMessage(message) oneOf(database).startTransaction(); will(returnValue(txn)); oneOf(database).containsSubscription(txn, groupId, timestamp); will(returnValue(true)); - oneOf(database).addMessage(txn, message); + oneOf(database).addGroupMessage(txn, message); will(returnValue(true)); oneOf(database).getContacts(txn); will(returnValue(Collections.singletonList(contactId))); @@ -1145,12 +1145,12 @@ public abstract class DatabaseComponentTest extends TestCase { final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final DatabaseListener listener = context.mock(DatabaseListener.class); context.checking(new Expectations() {{ - // addLocallyGeneratedMessage(message) + // addLocalGroupMessage(message) oneOf(database).startTransaction(); will(returnValue(txn)); oneOf(database).containsSubscription(txn, groupId, timestamp); will(returnValue(true)); - oneOf(database).addMessage(txn, message); + oneOf(database).addGroupMessage(txn, message); will(returnValue(false)); oneOf(database).commitTransaction(txn); // The message was not added, so the listener should not be called diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java index 0698f8e1375725f586a49465f1b910754fd95b8d..09e8c52f3efc75a8554b70a3faadc77b0cf9ad7c 100644 --- a/test/net/sf/briar/db/H2DatabaseTest.java +++ b/test/net/sf/briar/db/H2DatabaseTest.java @@ -110,7 +110,7 @@ public class H2DatabaseTest extends TestCase { db.addSubscription(txn, group); assertTrue(db.containsSubscription(txn, groupId)); assertFalse(db.containsMessage(txn, messageId)); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); assertTrue(db.containsMessage(txn, messageId)); db.commitTransaction(txn); db.close(); @@ -195,7 +195,7 @@ public class H2DatabaseTest extends TestCase { // Subscribe to a group and store a message db.addSubscription(txn, group); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); // Unsubscribing from the group should delete the message assertTrue(db.containsMessage(txn, messageId)); @@ -216,7 +216,7 @@ public class H2DatabaseTest extends TestCase { db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setStatus(txn, contactId, messageId, Status.NEW); // The message should not be sendable @@ -254,7 +254,7 @@ public class H2DatabaseTest extends TestCase { db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setSendability(txn, messageId, 1); // The message has no status yet, so it should not be sendable @@ -295,7 +295,7 @@ public class H2DatabaseTest extends TestCase { assertEquals(contactId, db.addContact(txn, transports, secret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setSendability(txn, messageId, 1); db.setStatus(txn, contactId, messageId, Status.NEW); @@ -334,7 +334,7 @@ public class H2DatabaseTest extends TestCase { assertEquals(contactId, db.addContact(txn, transports, secret)); db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setSendability(txn, messageId, 1); db.setStatus(txn, contactId, messageId, Status.NEW); @@ -370,7 +370,7 @@ public class H2DatabaseTest extends TestCase { db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setSendability(txn, messageId, 1); db.setStatus(txn, contactId, messageId, Status.NEW); @@ -400,7 +400,7 @@ public class H2DatabaseTest extends TestCase { assertEquals(contactId, db.addContact(txn, transports, secret)); db.addSubscription(txn, group); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setSendability(txn, messageId, 1); db.setStatus(txn, contactId, messageId, Status.NEW); @@ -485,7 +485,7 @@ public class H2DatabaseTest extends TestCase { // Add a contact, subscribe to a group and store a message assertEquals(contactId, db.addContact(txn, transports, secret)); db.addSubscription(txn, group); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); // Add an outstanding batch db.addOutstandingBatch(txn, contactId, batchId, @@ -511,7 +511,7 @@ public class H2DatabaseTest extends TestCase { assertEquals(contactId, db.addContact(txn, transports, secret)); ContactId contactId1 = db.addContact(txn, transports, secret); db.addSubscription(txn, group); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); // Add an outstanding batch for the first contact db.addOutstandingBatch(txn, contactId, batchId, @@ -535,7 +535,7 @@ public class H2DatabaseTest extends TestCase { db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setSendability(txn, messageId, 1); db.setStatus(txn, contactId, messageId, Status.NEW); @@ -572,7 +572,7 @@ public class H2DatabaseTest extends TestCase { db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setSendability(txn, messageId, 1); db.setStatus(txn, contactId, messageId, Status.NEW); @@ -682,8 +682,8 @@ public class H2DatabaseTest extends TestCase { // Subscribe to a group and store two messages db.addSubscription(txn, group); - db.addMessage(txn, message); - db.addMessage(txn, message1); + db.addGroupMessage(txn, message); + db.addGroupMessage(txn, message1); // Check that each message is retrievable via its author Iterator<MessageId> it = @@ -721,10 +721,10 @@ public class H2DatabaseTest extends TestCase { // Subscribe to the groups and store the messages db.addSubscription(txn, group); db.addSubscription(txn, group1); - db.addMessage(txn, message); - db.addMessage(txn, child1); - db.addMessage(txn, child2); - db.addMessage(txn, child3); + db.addGroupMessage(txn, message); + db.addGroupMessage(txn, child1); + db.addGroupMessage(txn, child2); + db.addGroupMessage(txn, child3); // Make all the children sendable db.setSendability(txn, childId1, 1); db.setSendability(txn, childId2, 5); @@ -751,8 +751,8 @@ public class H2DatabaseTest extends TestCase { // Subscribe to a group and store two messages db.addSubscription(txn, group); - db.addMessage(txn, message); - db.addMessage(txn, message1); + db.addGroupMessage(txn, message); + db.addGroupMessage(txn, message1); // Allowing enough capacity for one message should return the older one Iterator<MessageId> it = db.getOldMessages(txn, size).iterator(); @@ -789,7 +789,7 @@ public class H2DatabaseTest extends TestCase { // Storing a message should reduce the free space Connection txn = db.startTransaction(); db.addSubscription(txn, group); - db.addMessage(txn, message1); + db.addGroupMessage(txn, message1); db.commitTransaction(txn); assertTrue(db.getFreeSpace() < free); @@ -1036,7 +1036,7 @@ public class H2DatabaseTest extends TestCase { assertEquals(contactId, db.addContact(txn, transports, secret)); db.addSubscription(txn, group); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); // Set the sendability to > 0 db.setSendability(txn, messageId, 1); // Set the status to SEEN @@ -1059,7 +1059,7 @@ public class H2DatabaseTest extends TestCase { assertEquals(contactId, db.addContact(txn, transports, secret)); db.addSubscription(txn, group); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); // Set the sendability to 0 db.setSendability(txn, messageId, 0); // Set the status to NEW @@ -1084,7 +1084,7 @@ public class H2DatabaseTest extends TestCase { // The message is older than the contact's subscription Map<Group, Long> subs = Collections.singletonMap(group, timestamp + 1); db.setSubscriptions(txn, contactId, subs, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); // Set the sendability to > 0 db.setSendability(txn, messageId, 1); // Set the status to NEW @@ -1107,7 +1107,7 @@ public class H2DatabaseTest extends TestCase { db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); // Set the sendability to > 0 db.setSendability(txn, messageId, 1); // Set the status to NEW @@ -1166,7 +1166,7 @@ public class H2DatabaseTest extends TestCase { // Add a contact, subscribe to a group and store a message assertEquals(contactId, db.addContact(txn, transports, secret)); db.addSubscription(txn, group); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setStatus(txn, contactId, messageId, Status.NEW); // There's no contact subscription for the group @@ -1185,7 +1185,7 @@ public class H2DatabaseTest extends TestCase { // Add a contact, subscribe to a group and store a message assertEquals(contactId, db.addContact(txn, transports, secret)); db.addSubscription(txn, group); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); db.setSubscriptions(txn, contactId, subscriptions, 1); db.setStatus(txn, contactId, messageId, Status.NEW); @@ -1207,7 +1207,7 @@ public class H2DatabaseTest extends TestCase { db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); // The message has already been seen by the contact db.setStatus(txn, contactId, messageId, Status.SEEN); @@ -1228,7 +1228,7 @@ public class H2DatabaseTest extends TestCase { db.addSubscription(txn, group); db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setSubscriptions(txn, contactId, subscriptions, 1); - db.addMessage(txn, message); + db.addGroupMessage(txn, message); // The message has not been seen by the contact db.setStatus(txn, contactId, messageId, Status.NEW);