diff --git a/api/net/sf/briar/api/protocol/AuthorId.java b/api/net/sf/briar/api/protocol/AuthorId.java index c34d32c05452cb11470bb622fb1ae26b482d2123..b5136c222ff5ede7e84913e29859b6048b9d07c2 100644 --- a/api/net/sf/briar/api/protocol/AuthorId.java +++ b/api/net/sf/briar/api/protocol/AuthorId.java @@ -8,9 +8,6 @@ import net.sf.briar.api.serial.Writer; /** Type-safe wrapper for a byte array that uniquely identifies an author. */ public class AuthorId extends UniqueId { - /** Used to indicate that a message is anonymous. */ - public static final AuthorId NONE = new AuthorId(new byte[UniqueId.LENGTH]); - public AuthorId(byte[] id) { super(id); } diff --git a/api/net/sf/briar/api/protocol/MessageId.java b/api/net/sf/briar/api/protocol/MessageId.java index e70a44f76240f84b3255e16b5501e76d5a244488..e559be69de8fcedec16208fdf49e3882a61f04e4 100644 --- a/api/net/sf/briar/api/protocol/MessageId.java +++ b/api/net/sf/briar/api/protocol/MessageId.java @@ -8,10 +8,6 @@ import net.sf.briar.api.serial.Writer; /** Type-safe wrapper for a byte array that uniquely identifies a message. */ public class MessageId extends UniqueId { - /** Used to indicate that the first message in a thread has no parent. */ - public static final MessageId NONE = - new MessageId(new byte[UniqueId.LENGTH]); - public MessageId(byte[] id) { super(id); } diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java index c2f186e7170ef2a59b2fc80a1b88ac00080e0397..0bf6e058b0eeeeb5386109709930f5706523352c 100644 --- a/components/net/sf/briar/db/Database.java +++ b/components/net/sf/briar/db/Database.java @@ -241,7 +241,8 @@ interface Database<T> { Collection<MessageId> getOldMessages(T txn, int size) throws DbException; /** - * Returns the parent of the given message. + * Returns the parent of the given message, or null if the message has + * no parent. * <p> * Locking: messages read. */ diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java index c7c10d577fd95dfe7e974bdb912fb3551277eb04..677864257cb3642e1706cd898b55969b4f2b1701 100644 --- a/components/net/sf/briar/db/DatabaseComponentImpl.java +++ b/components/net/sf/briar/db/DatabaseComponentImpl.java @@ -213,7 +213,7 @@ DatabaseCleaner.Callback { boolean changed = true; while(changed) { MessageId parent = db.getParent(txn, m); - if(parent.equals(MessageId.NONE)) break; + if(parent == null) break; if(!db.containsMessage(txn, parent)) break; if(!db.getGroup(txn, m).equals(db.getGroup(txn, parent))) break; Integer parentSendability = db.getSendability(txn, parent); diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java index c242372f6ed571d9547a14cddf9105d9bc071f34..d4891e7e70584ea908d7aa95a75fac334b687f02 100644 --- a/components/net/sf/briar/db/JdbcDatabase.java +++ b/components/net/sf/briar/db/JdbcDatabase.java @@ -8,6 +8,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.sql.Types; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -51,9 +52,9 @@ abstract class JdbcDatabase implements Database<Connection> { private static final String CREATE_MESSAGES = "CREATE TABLE messages" + " (messageId HASH NOT NULL," - + " parentId HASH NOT NULL," + + " parentId HASH," + " groupId HASH NOT NULL," - + " authorId HASH NOT NULL," + + " authorId HASH," + " timestamp BIGINT NOT NULL," + " size INT NOT NULL," + " raw BLOB NOT NULL," @@ -536,9 +537,11 @@ abstract class JdbcDatabase implements Database<Connection> { + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, m.getId().getBytes()); - ps.setBytes(2, m.getParent().getBytes()); + if(m.getParent() == null) ps.setNull(2, Types.BINARY); + else ps.setBytes(2, m.getParent().getBytes()); ps.setBytes(3, m.getGroup().getBytes()); - ps.setBytes(4, m.getAuthor().getBytes()); + if(m.getAuthor() == null) ps.setNull(4, Types.BINARY); + else ps.setBytes(4, m.getAuthor().getBytes()); ps.setLong(5, m.getTimestamp()); ps.setInt(6, m.getSize()); byte[] raw = m.getBytes(); diff --git a/components/net/sf/briar/protocol/MessageEncoderImpl.java b/components/net/sf/briar/protocol/MessageEncoderImpl.java index af8f7b902bd1da5e51705ec2bc8ee1762b988d36..0a5b92a0a7ad00247d02b119b2030e3d3a5562ec 100644 --- a/components/net/sf/briar/protocol/MessageEncoderImpl.java +++ b/components/net/sf/briar/protocol/MessageEncoderImpl.java @@ -66,7 +66,8 @@ class MessageEncoderImpl implements MessageEncoder { Writer w = writerFactory.createWriter(out); // Write the message w.writeUserDefinedTag(Types.MESSAGE); - parent.writeTo(w); + if(parent == null) w.writeNull(); + else parent.writeTo(w); group.writeTo(w); if(author == null) w.writeNull(); else author.writeTo(w); @@ -99,7 +100,7 @@ class MessageEncoderImpl implements MessageEncoder { messageDigest.reset(); messageDigest.update(raw); MessageId id = new MessageId(messageDigest.digest()); - AuthorId authorId = author == null ? AuthorId.NONE : author.getId(); + AuthorId authorId = author == null ? null : author.getId(); return new MessageImpl(id, parent, group.getId(), authorId, timestamp, raw); } diff --git a/components/net/sf/briar/protocol/MessageReader.java b/components/net/sf/briar/protocol/MessageReader.java index 669fa38051ec5f5e702696e6c62c31fc250f3a13..688056e01930a56c45d2ed1e496ed0bc86594203 100644 --- a/components/net/sf/briar/protocol/MessageReader.java +++ b/components/net/sf/briar/protocol/MessageReader.java @@ -48,20 +48,28 @@ class MessageReader implements ObjectReader<Message> { r.addConsumer(counting); // Read the initial tag r.readUserDefinedId(Types.MESSAGE); - // Read the parent's message ID - r.addObjectReader(Types.MESSAGE_ID, messageIdReader); - MessageId parent = r.readUserDefined(Types.MESSAGE_ID, MessageId.class); - r.removeObjectReader(Types.MESSAGE_ID); + // Read the parent's message ID, if there is one + MessageId parent = null; + if(r.hasNull()) { + r.readNull(); + } else { + r.addObjectReader(Types.MESSAGE_ID, messageIdReader); + parent = r.readUserDefined(Types.MESSAGE_ID, MessageId.class); + r.removeObjectReader(Types.MESSAGE_ID); + } // Read the group r.addObjectReader(Types.GROUP, groupReader); Group group = r.readUserDefined(Types.GROUP, Group.class); r.removeObjectReader(Types.GROUP); // Read the author, if there is one - r.addObjectReader(Types.AUTHOR, authorReader); Author author = null; - if(r.hasNull()) r.readNull(); - else author = r.readUserDefined(Types.AUTHOR, Author.class); - r.removeObjectReader(Types.AUTHOR); + if(r.hasNull()) { + r.readNull(); + } else { + r.addObjectReader(Types.AUTHOR, authorReader); + author = r.readUserDefined(Types.AUTHOR, Author.class); + r.removeObjectReader(Types.AUTHOR); + } // Read the timestamp long timestamp = r.readInt64(); if(timestamp < 0L) throw new FormatException(); @@ -109,7 +117,7 @@ class MessageReader implements ObjectReader<Message> { messageDigest.reset(); messageDigest.update(raw); MessageId id = new MessageId(messageDigest.digest()); - AuthorId authorId = author == null ? AuthorId.NONE : author.getId(); + AuthorId authorId = author == null ? null : author.getId(); return new MessageImpl(id, parent, group.getId(), authorId, timestamp, raw); } diff --git a/test/net/sf/briar/FileReadWriteTest.java b/test/net/sf/briar/FileReadWriteTest.java index de0dfd619b61d48bbc77e93d136be7eeb4f3a2bb..c50f1d4535d27aab3d8e555d2b772f796b4311bd 100644 --- a/test/net/sf/briar/FileReadWriteTest.java +++ b/test/net/sf/briar/FileReadWriteTest.java @@ -109,13 +109,13 @@ public class FileReadWriteTest extends TestCase { authorKeyPair.getPublic().getEncoded()); // Create two messages to each group: one anonymous, one pseudonymous MessageEncoder messageEncoder = i.getInstance(MessageEncoder.class); - message = messageEncoder.encodeMessage(MessageId.NONE, group, + message = messageEncoder.encodeMessage(null, group, messageBody.getBytes("UTF-8")); - message1 = messageEncoder.encodeMessage(MessageId.NONE, group1, + message1 = messageEncoder.encodeMessage(null, group1, groupKeyPair.getPrivate(), messageBody.getBytes("UTF-8")); - message2 = messageEncoder.encodeMessage(MessageId.NONE, group, author, + message2 = messageEncoder.encodeMessage(null, group, author, authorKeyPair.getPrivate(), messageBody.getBytes("UTF-8")); - message3 = messageEncoder.encodeMessage(MessageId.NONE, group1, + message3 = messageEncoder.encodeMessage(null, group1, groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(), messageBody.getBytes("UTF-8")); transports = Collections.singletonMap("foo", diff --git a/test/net/sf/briar/db/DatabaseComponentImplTest.java b/test/net/sf/briar/db/DatabaseComponentImplTest.java index 98e39c1bc67da8cea668620f08a11ebcfde2a2af..8e114c46f30a8f52d1bdb1388f03274bec70b67c 100644 --- a/test/net/sf/briar/db/DatabaseComponentImplTest.java +++ b/test/net/sf/briar/db/DatabaseComponentImplTest.java @@ -6,7 +6,6 @@ import static net.sf.briar.api.db.DatabaseComponent.MIN_FREE_SPACE; import java.util.Collections; import net.sf.briar.api.db.DbException; -import net.sf.briar.api.protocol.MessageId; import net.sf.briar.db.DatabaseCleaner.Callback; import org.jmock.Expectations; @@ -109,7 +108,7 @@ public abstract class DatabaseComponentImplTest extends DatabaseComponentTest { oneOf(database).getSendability(txn, messageId); will(returnValue(1)); oneOf(database).getParent(txn, messageId); - will(returnValue(MessageId.NONE)); + will(returnValue(null)); oneOf(database).removeMessage(txn, messageId); oneOf(database).commitTransaction(txn); oneOf(database).getFreeSpace(); diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index 04297083df6d9fdefafcbc5ab65094d67d6f5f98..0fb571e1685cf101b737487c6f6b2e7002245a02 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -68,8 +68,8 @@ public abstract class DatabaseComponentTest extends TestCase { timestamp = System.currentTimeMillis(); size = 1234; raw = new byte[size]; - message = new TestMessage(messageId, MessageId.NONE, groupId, authorId, - timestamp, raw); + message = + new TestMessage(messageId, null, groupId, authorId, timestamp, raw); group = new TestGroup(groupId, "The really exciting group", null); transports = Collections.singletonMap("foo", Collections.singletonMap("bar", "baz")); @@ -198,7 +198,7 @@ public abstract class DatabaseComponentTest extends TestCase { oneOf(database).setSendability(txn, messageId, 1); // Backward inclusion stops when the message has no parent oneOf(database).getParent(txn, messageId); - will(returnValue(MessageId.NONE)); + will(returnValue(null)); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); @@ -349,7 +349,7 @@ public abstract class DatabaseComponentTest extends TestCase { will(returnValue(0)); oneOf(database).setSendability(txn, parentId, 1); oneOf(database).getParent(txn, parentId); - will(returnValue(MessageId.NONE)); + will(returnValue(null)); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); @@ -462,7 +462,7 @@ public abstract class DatabaseComponentTest extends TestCase { oneOf(database).setSendability(txn, messageId, 3); // The sendability of the message's ancestors should be updated oneOf(database).getParent(txn, messageId); - will(returnValue(MessageId.NONE)); + will(returnValue(null)); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); @@ -988,7 +988,7 @@ public abstract class DatabaseComponentTest extends TestCase { will(returnValue(1)); oneOf(database).setSendability(txn, messageId, 2); oneOf(database).getParent(txn, messageId); - will(returnValue(MessageId.NONE)); + will(returnValue(null)); // The batch needs to be acknowledged oneOf(batch).getId(); will(returnValue(batchId)); diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java index ba5ecd7f3b3a23ffb3349ca5802aee49e5ae71a6..0698f8e1375725f586a49465f1b910754fd95b8d 100644 --- a/test/net/sf/briar/db/H2DatabaseTest.java +++ b/test/net/sf/briar/db/H2DatabaseTest.java @@ -84,8 +84,8 @@ public class H2DatabaseTest extends TestCase { size = 1234; raw = new byte[size]; random.nextBytes(raw); - message = new TestMessage(messageId, MessageId.NONE, groupId, authorId, - timestamp, raw); + message = + new TestMessage(messageId, null, groupId, authorId, timestamp, raw); group = groupFactory.createGroup(groupId, "Group name", null); transports = Collections.singletonMap("foo", Collections.singletonMap("bar", "baz")); @@ -675,8 +675,8 @@ public class H2DatabaseTest extends TestCase { public void testGetMessagesByAuthor() throws DbException { AuthorId authorId1 = new AuthorId(TestUtils.getRandomId()); MessageId messageId1 = new MessageId(TestUtils.getRandomId()); - Message message1 = new TestMessage(messageId1, MessageId.NONE, groupId, - authorId1, timestamp, raw); + Message message1 = new TestMessage(messageId1, null, groupId, authorId1, + timestamp, raw); Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -744,8 +744,8 @@ public class H2DatabaseTest extends TestCase { @Test public void testGetOldMessages() throws DbException { MessageId messageId1 = new MessageId(TestUtils.getRandomId()); - Message message1 = new TestMessage(messageId1, MessageId.NONE, groupId, - authorId, timestamp + 1000, raw); + Message message1 = new TestMessage(messageId1, null, groupId, authorId, + timestamp + 1000, raw); Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -775,8 +775,8 @@ public class H2DatabaseTest extends TestCase { public void testGetFreeSpace() throws Exception { byte[] largeBody = new byte[ONE_MEGABYTE]; for(int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i; - Message message1 = new TestMessage(messageId, MessageId.NONE, groupId, - authorId, timestamp, largeBody); + Message message1 = new TestMessage(messageId, null, groupId, authorId, + timestamp, largeBody); Database<Connection> db = open(false); // Sanity check: there should be enough space on disk for this test diff --git a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java index 393a86816fff98df3f9b8c426b96fdb9dbfdf555..ad5a7981c0909d483af335444f1fd310919179e7 100644 --- a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java +++ b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java @@ -15,7 +15,6 @@ import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupFactory; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageEncoder; -import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; import net.sf.briar.api.protocol.ProtocolReader; import net.sf.briar.api.protocol.ProtocolReaderFactory; @@ -61,7 +60,7 @@ public class ProtocolReadWriteTest extends TestCase { GroupFactory groupFactory = i.getInstance(GroupFactory.class); group = groupFactory.createGroup("Unrestricted group", null); MessageEncoder messageEncoder = i.getInstance(MessageEncoder.class); - message = messageEncoder.encodeMessage(MessageId.NONE, group, + message = messageEncoder.encodeMessage(null, group, messageBody.getBytes("UTF-8")); bitSet = new BitSet(); bitSet.set(3); diff --git a/test/net/sf/briar/protocol/writers/ConstantsTest.java b/test/net/sf/briar/protocol/writers/ConstantsTest.java index 45b08284dd12802a6bb9930a9136922979e79935..6d3781433758f81effc5cf3f5f3b3f1b7f5ee9ce 100644 --- a/test/net/sf/briar/protocol/writers/ConstantsTest.java +++ b/test/net/sf/briar/protocol/writers/ConstantsTest.java @@ -87,7 +87,7 @@ public class ConstantsTest extends TestCase { PrivateKey groupPrivate = crypto.generateKeyPair().getPrivate(); PrivateKey authorPrivate = crypto.generateKeyPair().getPrivate(); byte[] body = new byte[Message.MAX_BODY_LENGTH]; - Message message = messageEncoder.encodeMessage(MessageId.NONE, group, + Message message = messageEncoder.encodeMessage(null, group, groupPrivate, author, authorPrivate, body); // Add the message to a batch ByteArrayOutputStream out = new ByteArrayOutputStream(