Changed the format of transport properties from (key, value) pairs to

(transport name, key, value) triples. This makes it possible for each
transport plugin to update its locally stored properties atomically.
This commit is contained in:
akwizgran
2011-08-04 11:07:28 +01:00
parent 5be9d953ee
commit ec29c4d1d3
16 changed files with 264 additions and 172 deletions

View File

@@ -58,7 +58,8 @@ public interface DatabaseComponent {
* Adds a new contact to the database with the given transport properties * Adds a new contact to the database with the given transport properties
* and returns an ID for the contact. * and returns an ID for the contact.
*/ */
ContactId addContact(Map<String, String> transports) throws DbException; ContactId addContact(Map<String, Map<String, String>> transports)
throws DbException;
/** Adds a locally generated message to the database. */ /** Adds a locally generated message to the database. */
void addLocallyGeneratedMessage(Message m) throws DbException; void addLocallyGeneratedMessage(Message m) throws DbException;
@@ -111,10 +112,11 @@ public interface DatabaseComponent {
Collection<Group> getSubscriptions() throws DbException; Collection<Group> getSubscriptions() throws DbException;
/** Returns the local transport properties. */ /** Returns the local transport properties. */
Map<String, String> getTransports() throws DbException; Map<String, Map<String, String>> getTransports() throws DbException;
/** Returns the transport properties for the given contact. */ /** Returns the transport properties for the given contact. */
Map<String, String> getTransports(ContactId c) throws DbException; Map<String, Map<String, String>> getTransports(ContactId c)
throws DbException;
/** Returns the contacts to which the given group is visible. */ /** Returns the contacts to which the given group is visible. */
Collection<ContactId> getVisibility(GroupId g) throws DbException; Collection<ContactId> getVisibility(GroupId g) throws DbException;
@@ -152,9 +154,11 @@ public interface DatabaseComponent {
void setRating(AuthorId a, Rating r) throws DbException; void setRating(AuthorId a, Rating r) throws DbException;
/** /**
* Sets the local transport properties, replacing any existing properties. * Sets the local transport properties for the transport with the given
* name, replacing any existing properties for that transport.
*/ */
void setTransports(Map<String, String> transports) throws DbException; void setTransports(String name, Map<String, String> transports)
throws DbException;
/** /**
* Makes the given group visible to the given set of contacts and invisible * Makes the given group visible to the given set of contacts and invisible

View File

@@ -12,7 +12,7 @@ public interface Transports {
static final int MAX_SIZE = (1024 * 1024) - 100; static final int MAX_SIZE = (1024 * 1024) - 100;
/** Returns the transports contained in the update. */ /** Returns the transports contained in the update. */
Map<String, String> getTransports(); Map<String, Map<String, String>> getTransports();
/** /**
* Returns the update's timestamp. Updates that are older than the newest * Returns the update's timestamp. Updates that are older than the newest

View File

@@ -7,5 +7,6 @@ import java.util.Map;
public interface TransportWriter { public interface TransportWriter {
/** Writes the contents of the update. */ /** Writes the contents of the update. */
void writeTransports(Map<String, String> transports) throws IOException; void writeTransports(Map<String, Map<String, String>> transports)
throws IOException;
} }

View File

@@ -82,7 +82,7 @@ interface Database<T> {
* <p> * <p>
* Locking: contacts write, transports write. * Locking: contacts write, transports write.
*/ */
ContactId addContact(T txn, Map<String, String> transports) ContactId addContact(T txn, Map<String, Map<String, String>> transports)
throws DbException; throws DbException;
/** /**
@@ -272,14 +272,15 @@ interface Database<T> {
* <p> * <p>
* Locking: transports read. * Locking: transports read.
*/ */
Map<String, String> getTransports(T txn) throws DbException; Map<String, Map<String, String>> getTransports(T txn) throws DbException;
/** /**
* Returns the transport properties for the given contact. * Returns the transport properties for the given contact.
* <p> * <p>
* Locking: contacts read, transports read. * Locking: contacts read, transports read.
*/ */
Map<String, String> getTransports(T txn, ContactId c) throws DbException; Map<String, Map<String, String>> getTransports(T txn, ContactId c)
throws DbException;
/** /**
* Returns the contacts to which the given group is visible. * Returns the contacts to which the given group is visible.
@@ -397,11 +398,12 @@ interface Database<T> {
long timestamp) throws DbException; long timestamp) throws DbException;
/** /**
* Sets the local transport properties, replacing any existing properties. * Sets the local transport properties for the transport with the given
* name, replacing any existing properties for that transport.
* <p> * <p>
* Locking: transports write. * Locking: transports write.
*/ */
void setTransports(T txn, Map<String, String> transports) void setTransports(T txn, String name, Map<String, String> transports)
throws DbException; throws DbException;
/** /**
@@ -411,8 +413,9 @@ interface Database<T> {
* <p> * <p>
* Locking: contacts write, transports write. * Locking: contacts write, transports write.
*/ */
void setTransports(T txn, ContactId c, Map<String, String> transports, void setTransports(T txn, ContactId c,
long timestamp) throws DbException; Map<String, Map<String, String>> transports, long timestamp)
throws DbException;
/** /**
* Makes the given group visible to the given set of contacts and invisible * Makes the given group visible to the given set of contacts and invisible

View File

@@ -159,17 +159,19 @@ abstract class JdbcDatabase implements Database<Connection> {
private static final String CREATE_CONTACT_TRANSPORTS = private static final String CREATE_CONTACT_TRANSPORTS =
"CREATE TABLE contactTransports" "CREATE TABLE contactTransports"
+ " (contactId INT NOT NULL," + " (contactId INT NOT NULL,"
+ " transportName VARCHAR NOT NULL,"
+ " key VARCHAR NOT NULL," + " key VARCHAR NOT NULL,"
+ " value VARCHAR NOT NULL," + " value VARCHAR NOT NULL,"
+ " PRIMARY KEY (contactId, key)," + " PRIMARY KEY (contactId, transportName, key),"
+ " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)"
+ " ON DELETE CASCADE)"; + " ON DELETE CASCADE)";
private static final String CREATE_LOCAL_TRANSPORTS = private static final String CREATE_TRANSPORTS =
"CREATE TABLE localTransports" "CREATE TABLE transports"
+ " (key VARCHAR NOT NULL," + " (transportName VARCHAR NOT NULL,"
+ " key VARCHAR NOT NULL,"
+ " value VARCHAR NOT NULL," + " value VARCHAR NOT NULL,"
+ " PRIMARY KEY (key))"; + " PRIMARY KEY (transportName, key))";
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(JdbcDatabase.class.getName()); Logger.getLogger(JdbcDatabase.class.getName());
@@ -252,7 +254,7 @@ abstract class JdbcDatabase implements Database<Connection> {
s.executeUpdate(INDEX_STATUSES_BY_MESSAGE); s.executeUpdate(INDEX_STATUSES_BY_MESSAGE);
s.executeUpdate(INDEX_STATUSES_BY_CONTACT); s.executeUpdate(INDEX_STATUSES_BY_CONTACT);
s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORTS)); s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORTS));
s.executeUpdate(insertTypeNames(CREATE_LOCAL_TRANSPORTS)); s.executeUpdate(insertTypeNames(CREATE_TRANSPORTS));
s.close(); s.close();
} catch(SQLException e) { } catch(SQLException e) {
tryToClose(s); tryToClose(s);
@@ -406,7 +408,8 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public ContactId addContact(Connection txn, Map<String, String> transports) public ContactId addContact(Connection txn,
Map<String, Map<String, String>> transports)
throws DbException { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
@@ -434,24 +437,27 @@ abstract class JdbcDatabase implements Database<Connection> {
if(affected != 1) throw new DbStateException(); if(affected != 1) throw new DbStateException();
ps.close(); ps.close();
// Store the contact's transport properties // Store the contact's transport properties
if(transports != null) { sql = "INSERT INTO contactTransports"
sql = "INSERT INTO contactTransports (contactId, key, value)" + " (contactId, transportName, key, value)"
+ " VALUES (?, ?, ?)"; + " VALUES (?, ?, ?, ?)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setInt(1, c.getInt());
for(Entry<String, String> e : transports.entrySet()) { int batchSize = 0;
ps.setString(2, e.getKey()); for(Entry<String, Map<String, String>> e : transports.entrySet()) {
ps.setString(3, e.getValue()); ps.setString(2, e.getKey());
for(Entry<String, String> e1 : e.getValue().entrySet()) {
ps.setString(3, e1.getKey());
ps.setString(4, e1.getValue());
ps.addBatch(); ps.addBatch();
batchSize++;
} }
int[] batchAffected = ps.executeBatch();
if(batchAffected.length != transports.size())
throw new DbStateException();
for(int i = 0; i < batchAffected.length; i++) {
if(batchAffected[i] != 1) throw new DbStateException();
}
ps.close();
} }
int[] batchAffected = ps.executeBatch();
if(batchAffected.length != batchSize) throw new DbStateException();
for(int i = 0; i < batchAffected.length; i++) {
if(batchAffected[i] != 1) throw new DbStateException();
}
ps.close();
return c; return c;
} catch(SQLException e) { } catch(SQLException e) {
tryToClose(ps); tryToClose(ps);
@@ -1119,19 +1125,31 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public Map<String, String> getTransports(Connection txn) public Map<String, Map<String, String>> getTransports(Connection txn)
throws DbException { throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT key, value FROM localTransports"; String sql = "SELECT transportName, key, value"
+ " FROM transports"
+ " ORDER BY transportName";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
rs = ps.executeQuery(); rs = ps.executeQuery();
Map<String, String> transports = new TreeMap<String, String>(); Map<String, Map<String, String>> outer =
while(rs.next()) transports.put(rs.getString(1), rs.getString(2)); new TreeMap<String, Map<String, String>>();
Map<String, String> inner = null;
String lastName = null;
while(rs.next()) {
String name = rs.getString(1);
if(!name.equals(lastName)) {
inner = new TreeMap<String, String>();
outer.put(name, inner);
}
inner.put(rs.getString(2), rs.getString(3));
}
rs.close(); rs.close();
ps.close(); ps.close();
return transports; return outer;
} catch(SQLException e) { } catch(SQLException e) {
tryToClose(rs); tryToClose(rs);
tryToClose(ps); tryToClose(ps);
@@ -1139,21 +1157,33 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public Map<String, String> getTransports(Connection txn, ContactId c) public Map<String, Map<String, String>> getTransports(Connection txn,
throws DbException { ContactId c) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT key, value FROM contactTransports" String sql = "SELECT transportName, key, value"
+ " WHERE contactId = ?"; + " FROM contactTransports"
+ " WHERE contactId = ?"
+ " ORDER BY transportName";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setInt(1, c.getInt());
rs = ps.executeQuery(); rs = ps.executeQuery();
Map<String, String> transports = new TreeMap<String, String>(); Map<String, Map<String, String>> outer =
while(rs.next()) transports.put(rs.getString(1), rs.getString(2)); new TreeMap<String, Map<String, String>>();
Map<String, String> inner = null;
String lastName = null;
while(rs.next()) {
String name = rs.getString(1);
if(!name.equals(lastName)) {
inner = new TreeMap<String, String>();
outer.put(name, inner);
}
inner.put(rs.getString(2), rs.getString(3));
}
rs.close(); rs.close();
ps.close(); ps.close();
return transports; return outer;
} catch(SQLException e) { } catch(SQLException e) {
tryToClose(rs); tryToClose(rs);
tryToClose(ps); tryToClose(ps);
@@ -1579,33 +1609,33 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
public void setTransports(Connection txn, Map<String, String> transports) public void setTransports(Connection txn, String name,
throws DbException { Map<String, String> transports) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
// Delete any existing transports // Delete any existing properties for the named transport
String sql = "DELETE FROM localTransports"; String sql = "DELETE FROM transports WHERE transportName = ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setString(1, name);
ps.executeUpdate(); ps.executeUpdate();
ps.close(); ps.close();
// Store the new transports // Store the new properties
if(!transports.isEmpty()) { sql = "INSERT INTO transports (transportName, key, value)"
sql = "INSERT INTO localTransports (key, value)" + " VALUES (?, ?, ?)";
+ " VALUES (?, ?)"; ps = txn.prepareStatement(sql);
ps = txn.prepareStatement(sql); ps.setString(1, name);
for(Entry<String, String> e : transports.entrySet()) { for(Entry<String, String> e : transports.entrySet()) {
ps.setString(1, e.getKey()); ps.setString(2, e.getKey());
ps.setString(2, e.getValue()); ps.setString(3, e.getValue());
ps.addBatch(); ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
if(batchAffected.length != transports.size())
throw new DbStateException();
for(int i = 0; i < batchAffected.length; i++) {
if(batchAffected[i] != 1) throw new DbStateException();
}
ps.close();
} }
int[] batchAffected = ps.executeBatch();
if(batchAffected.length != transports.size())
throw new DbStateException();
for(int i = 0; i < batchAffected.length; i++) {
if(batchAffected[i] != 1) throw new DbStateException();
}
ps.close();
} catch(SQLException e) { } catch(SQLException e) {
tryToClose(ps); tryToClose(ps);
throw new DbException(e); throw new DbException(e);
@@ -1613,7 +1643,8 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
public void setTransports(Connection txn, ContactId c, public void setTransports(Connection txn, ContactId c,
Map<String, String> transports, long timestamp) throws DbException { Map<String, Map<String, String>> transports, long timestamp)
throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
@@ -1636,24 +1667,27 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.executeUpdate(); ps.executeUpdate();
ps.close(); ps.close();
// Store the new transports // Store the new transports
if(transports != null) { sql = "INSERT INTO contactTransports"
sql = "INSERT INTO contactTransports (contactId, key, value)" + " (contactId, transportName, key, value)"
+ " VALUES (?, ?, ?)"; + " VALUES (?, ?, ?, ?)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setInt(1, c.getInt());
for(Entry<String, String> e : transports.entrySet()) { int batchSize = 0;
ps.setString(2, e.getKey()); for(Entry<String, Map<String, String>> e : transports.entrySet()) {
ps.setString(3, e.getValue()); ps.setString(2, e.getKey());
for(Entry<String, String> e1 : e.getValue().entrySet()) {
ps.setString(3, e1.getKey());
ps.setString(4, e1.getValue());
ps.addBatch(); ps.addBatch();
batchSize++;
} }
int[] batchAffected = ps.executeBatch();
if(batchAffected.length != transports.size())
throw new DbStateException();
for(int i = 0; i < batchAffected.length; i++) {
if(batchAffected[i] != 1) throw new DbStateException();
}
ps.close();
} }
int[] batchAffected = ps.executeBatch();
if(batchAffected.length != batchSize) throw new DbStateException();
for(int i = 0; i < batchAffected.length; i++) {
if(batchAffected[i] != 1) throw new DbStateException();
}
ps.close();
// Update the timestamp // Update the timestamp
sql = "UPDATE contacts SET transportsTimestamp = ?" sql = "UPDATE contacts SET transportsTimestamp = ?"
+ " WHERE contactId = ?"; + " WHERE contactId = ?";

View File

@@ -125,7 +125,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
} }
} }
public ContactId addContact(Map<String, String> transports) public ContactId addContact(Map<String, Map<String, String>> transports)
throws DbException { throws DbException {
if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact"); if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact");
contactLock.writeLock().lock(); contactLock.writeLock().lock();
@@ -497,7 +497,8 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
try { try {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
Map<String, String> transports = db.getTransports(txn); Map<String, Map<String, String>> transports =
db.getTransports(txn);
t.writeTransports(transports); t.writeTransports(transports);
if(LOG.isLoggable(Level.FINE)) if(LOG.isLoggable(Level.FINE))
LOG.fine("Added " + transports.size() + " transports"); LOG.fine("Added " + transports.size() + " transports");
@@ -568,12 +569,13 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
} }
} }
public Map<String, String> getTransports() throws DbException { public Map<String, Map<String, String>> getTransports() throws DbException {
transportLock.readLock().lock(); transportLock.readLock().lock();
try { try {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
Map<String, String> transports = db.getTransports(txn); Map<String, Map<String, String>> transports =
db.getTransports(txn);
db.commitTransaction(txn); db.commitTransaction(txn);
return transports; return transports;
} catch(DbException e) { } catch(DbException e) {
@@ -585,7 +587,8 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
} }
} }
public Map<String, String> getTransports(ContactId c) throws DbException { public Map<String, Map<String, String>> getTransports(ContactId c)
throws DbException {
contactLock.readLock().lock(); contactLock.readLock().lock();
try { try {
if(!containsContact(c)) throw new NoSuchContactException(); if(!containsContact(c)) throw new NoSuchContactException();
@@ -593,7 +596,8 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
try { try {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
Map<String, String> transports = db.getTransports(txn, c); Map<String, Map<String, String>> transports =
db.getTransports(txn, c);
db.commitTransaction(txn); db.commitTransaction(txn);
return transports; return transports;
} catch(DbException e) { } catch(DbException e) {
@@ -826,7 +830,8 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
try { try {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
Map<String, String> transports = t.getTransports(); Map<String, Map<String, String>> transports =
t.getTransports();
db.setTransports(txn, c, transports, t.getTimestamp()); db.setTransports(txn, c, transports, t.getTimestamp());
if(LOG.isLoggable(Level.FINE)) if(LOG.isLoggable(Level.FINE))
LOG.fine("Received " + transports.size() LOG.fine("Received " + transports.size()
@@ -902,15 +907,15 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
} }
} }
public void setTransports(Map<String, String> transports) public void setTransports(String name, Map<String, String> transports)
throws DbException { throws DbException {
boolean changed = false; boolean changed = false;
transportLock.writeLock().lock(); transportLock.writeLock().lock();
try { try {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
if(!transports.equals(db.getTransports(txn))) { if(!transports.equals(db.getTransports(txn).get(name))) {
db.setTransports(txn, transports); db.setTransports(txn, name, transports);
changed = true; changed = true;
} }
db.commitTransaction(txn); db.commitTransaction(txn);

View File

@@ -96,7 +96,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
} }
} }
public ContactId addContact(Map<String, String> transports) public ContactId addContact(Map<String, Map<String, String>> transports)
throws DbException { throws DbException {
if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact"); if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact");
synchronized(contactLock) { synchronized(contactLock) {
@@ -366,7 +366,8 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
synchronized(transportLock) { synchronized(transportLock) {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
Map<String, String> transports = db.getTransports(txn); Map<String, Map<String, String>> transports =
db.getTransports(txn);
t.writeTransports(transports); t.writeTransports(transports);
if(LOG.isLoggable(Level.FINE)) if(LOG.isLoggable(Level.FINE))
LOG.fine("Added " + transports.size() + " transports"); LOG.fine("Added " + transports.size() + " transports");
@@ -424,11 +425,12 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
} }
} }
public Map<String, String> getTransports() throws DbException { public Map<String, Map<String, String>> getTransports() throws DbException {
synchronized(transportLock) { synchronized(transportLock) {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
Map<String, String> transports = db.getTransports(txn); Map<String, Map<String, String>> transports =
db.getTransports(txn);
db.commitTransaction(txn); db.commitTransaction(txn);
return transports; return transports;
} catch(DbException e) { } catch(DbException e) {
@@ -438,13 +440,15 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
} }
} }
public Map<String, String> getTransports(ContactId c) throws DbException { public Map<String, Map<String, String>> getTransports(ContactId c)
throws DbException {
synchronized(contactLock) { synchronized(contactLock) {
if(!containsContact(c)) throw new NoSuchContactException(); if(!containsContact(c)) throw new NoSuchContactException();
synchronized(transportLock) { synchronized(transportLock) {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
Map<String, String> transports = db.getTransports(txn, c); Map<String, Map<String, String>> transports =
db.getTransports(txn, c);
db.commitTransaction(txn); db.commitTransaction(txn);
return transports; return transports;
} catch(DbException e) { } catch(DbException e) {
@@ -614,7 +618,8 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
synchronized(transportLock) { synchronized(transportLock) {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
Map<String, String> transports = t.getTransports(); Map<String, Map<String, String>> transports =
t.getTransports();
db.setTransports(txn, c, transports, t.getTimestamp()); db.setTransports(txn, c, transports, t.getTimestamp());
if(LOG.isLoggable(Level.FINE)) if(LOG.isLoggable(Level.FINE))
LOG.fine("Received " + transports.size() LOG.fine("Received " + transports.size()
@@ -668,14 +673,14 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
} }
} }
public void setTransports(Map<String, String> transports) public void setTransports(String name, Map<String, String> transports)
throws DbException { throws DbException {
boolean changed = false; boolean changed = false;
synchronized(transportLock) { synchronized(transportLock) {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
if(!transports.equals(db.getTransports(txn))) { if(!transports.equals(db.getTransports(txn).get(name))) {
db.setTransports(txn, transports); db.setTransports(txn, name, transports);
changed = true; changed = true;
} }
db.commitTransaction(txn); db.commitTransaction(txn);

View File

@@ -71,7 +71,7 @@ class InvitationWorker implements Runnable {
File invitationDat = new File(dir, "invitation.dat"); File invitationDat = new File(dir, "invitation.dat");
callback.encryptingFile(invitationDat); callback.encryptingFile(invitationDat);
// FIXME: Create a real invitation // FIXME: Create a real invitation
Map<String, String> transports; Map<String, Map<String, String>> transports;
try { try {
transports = databaseComponent.getTransports(); transports = databaseComponent.getTransports();
} catch(DbException e) { } catch(DbException e) {

View File

@@ -6,5 +6,6 @@ import net.sf.briar.api.protocol.Transports;
interface TransportFactory { interface TransportFactory {
Transports createTransports(Map<String, String> transports, long timestamp); Transports createTransports(Map<String, Map<String, String>> transports,
long timestamp);
} }

View File

@@ -6,7 +6,7 @@ import net.sf.briar.api.protocol.Transports;
class TransportFactoryImpl implements TransportFactory { class TransportFactoryImpl implements TransportFactory {
public Transports createTransports(Map<String, String> transports, public Transports createTransports(Map<String, Map<String, String>> transports,
long timestamp) { long timestamp) {
return new TransportsImpl(transports, timestamp); return new TransportsImpl(transports, timestamp);
} }

View File

@@ -2,6 +2,7 @@ package net.sf.briar.protocol;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.protocol.Tags;
import net.sf.briar.api.protocol.Transports; import net.sf.briar.api.protocol.Transports;
@@ -26,10 +27,26 @@ class TransportReader implements ObjectReader<Transports> {
// Read the data // Read the data
r.addConsumer(counting); r.addConsumer(counting);
r.readUserDefinedTag(Tags.TRANSPORTS); r.readUserDefinedTag(Tags.TRANSPORTS);
Map<String, String> transports = r.readMap(String.class, String.class); // Transport maps are always written in delimited form
Map<String, Map<String, String>> outer =
new TreeMap<String, Map<String, String>>();
r.readMapStart();
while(!r.hasMapEnd()) {
String name = r.readString(Transports.MAX_SIZE);
Map<String, String> inner = new TreeMap<String, String>();
r.readMapStart();
while(!r.hasMapEnd()) {
String key = r.readString(Transports.MAX_SIZE);
String value = r.readString(Transports.MAX_SIZE);
inner.put(key, value);
}
r.readMapEnd();
outer.put(name, inner);
}
r.readMapEnd();
long timestamp = r.readInt64(); long timestamp = r.readInt64();
r.removeConsumer(counting); r.removeConsumer(counting);
// Build and return the transports update // Build and return the transports update
return transportFactory.createTransports(transports, timestamp); return transportFactory.createTransports(outer, timestamp);
} }
} }

View File

@@ -6,15 +6,16 @@ import net.sf.briar.api.protocol.Transports;
class TransportsImpl implements Transports { class TransportsImpl implements Transports {
private final Map<String, String> transports; private final Map<String, Map<String, String>> transports;
private final long timestamp; private final long timestamp;
TransportsImpl(Map<String, String> transports, long timestamp) { TransportsImpl(Map<String, Map<String, String>> transports,
long timestamp) {
this.transports = transports; this.transports = transports;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public Map<String, String> getTransports() { public Map<String, Map<String, String>> getTransports() {
return transports; return transports;
} }

View File

@@ -3,6 +3,7 @@ package net.sf.briar.protocol.writers;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.protocol.Tags;
import net.sf.briar.api.protocol.writers.TransportWriter; import net.sf.briar.api.protocol.writers.TransportWriter;
@@ -19,10 +20,21 @@ class TransportWriterImpl implements TransportWriter {
w = writerFactory.createWriter(out); w = writerFactory.createWriter(out);
} }
public void writeTransports(Map<String, String> transports) public void writeTransports(Map<String, Map<String, String>> transports)
throws IOException { throws IOException {
w.writeUserDefinedTag(Tags.TRANSPORTS); w.writeUserDefinedTag(Tags.TRANSPORTS);
w.writeMap(transports); // Transport maps are always written in delimited form
w.writeMapStart();
for(Entry<String, Map<String, String>> e : transports.entrySet()) {
w.writeString(e.getKey());
w.writeMapStart();
for(Entry<String, String> e1 : e.getValue().entrySet()) {
w.writeString(e1.getKey());
w.writeString(e1.getValue());
}
w.writeMapEnd();
}
w.writeMapEnd();
w.writeInt64(System.currentTimeMillis()); w.writeInt64(System.currentTimeMillis());
out.flush(); out.flush();
} }

View File

@@ -52,7 +52,7 @@ public abstract class DatabaseComponentTest extends TestCase {
private final byte[] raw; private final byte[] raw;
private final Message message; private final Message message;
private final Group group; private final Group group;
private final Map<String, String> transports; private final Map<String, Map<String, String>> transports;
public DatabaseComponentTest() { public DatabaseComponentTest() {
super(); super();
@@ -68,7 +68,8 @@ public abstract class DatabaseComponentTest extends TestCase {
message = new TestMessage(messageId, MessageId.NONE, groupId, authorId, message = new TestMessage(messageId, MessageId.NONE, groupId, authorId,
timestamp, raw); timestamp, raw);
group = new TestGroup(groupId, "The really exciting group", null); group = new TestGroup(groupId, "The really exciting group", null);
transports = Collections.singletonMap("foo", "bar"); transports = Collections.singletonMap("foo",
Collections.singletonMap("bar", "baz"));
} }
protected abstract <T> DatabaseComponent createDatabaseComponent( protected abstract <T> DatabaseComponent createDatabaseComponent(
@@ -1112,9 +1113,9 @@ public abstract class DatabaseComponentTest extends TestCase {
oneOf(database).startTransaction(); oneOf(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
oneOf(database).getTransports(txn); oneOf(database).getTransports(txn);
will(returnValue(Collections.singletonMap("foo", "bar"))); will(returnValue(transports));
oneOf(database).setTransports(txn, oneOf(database).setTransports(txn, "bar",
Collections.singletonMap("bar", "baz")); Collections.singletonMap("baz", "bam"));
oneOf(database).commitTransaction(txn); oneOf(database).commitTransaction(txn);
oneOf(listener).eventOccurred( oneOf(listener).eventOccurred(
DatabaseListener.Event.TRANSPORTS_UPDATED); DatabaseListener.Event.TRANSPORTS_UPDATED);
@@ -1122,7 +1123,7 @@ public abstract class DatabaseComponentTest extends TestCase {
DatabaseComponent db = createDatabaseComponent(database, cleaner); DatabaseComponent db = createDatabaseComponent(database, cleaner);
db.addListener(listener); db.addListener(listener);
db.setTransports(Collections.singletonMap("bar", "baz")); db.setTransports("bar", Collections.singletonMap("baz", "bam"));
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
@@ -1138,13 +1139,13 @@ public abstract class DatabaseComponentTest extends TestCase {
oneOf(database).startTransaction(); oneOf(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
oneOf(database).getTransports(txn); oneOf(database).getTransports(txn);
will(returnValue(Collections.singletonMap("bar", "baz"))); will(returnValue(transports));
oneOf(database).commitTransaction(txn); oneOf(database).commitTransaction(txn);
}}); }});
DatabaseComponent db = createDatabaseComponent(database, cleaner); DatabaseComponent db = createDatabaseComponent(database, cleaner);
db.addListener(listener); db.addListener(listener);
db.setTransports(Collections.singletonMap("bar", "baz")); db.setTransports("foo", transports.get("foo"));
context.assertIsSatisfied(); context.assertIsSatisfied();
} }

View File

@@ -60,6 +60,7 @@ public class H2DatabaseTest extends TestCase {
private final byte[] raw; private final byte[] raw;
private final Message message; private final Message message;
private final Group group; private final Group group;
private final Map<String, Map<String, String>> transports;
public H2DatabaseTest() throws Exception { public H2DatabaseTest() throws Exception {
super(); super();
@@ -78,6 +79,8 @@ public class H2DatabaseTest extends TestCase {
message = new TestMessage(messageId, MessageId.NONE, groupId, authorId, message = new TestMessage(messageId, MessageId.NONE, groupId, authorId,
timestamp, raw); timestamp, raw);
group = groupFactory.createGroup(groupId, "Group name", null); group = groupFactory.createGroup(groupId, "Group name", null);
transports = Collections.singletonMap("foo",
Collections.singletonMap("bar", "baz"));
} }
@Before @Before
@@ -91,7 +94,6 @@ public class H2DatabaseTest extends TestCase {
Database<Connection> db = open(false); Database<Connection> db = open(false);
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
assertFalse(db.containsContact(txn, contactId)); assertFalse(db.containsContact(txn, contactId));
Map<String, String> transports = Collections.singletonMap("foo", "bar");
assertEquals(contactId, db.addContact(txn, transports)); assertEquals(contactId, db.addContact(txn, transports));
assertTrue(db.containsContact(txn, contactId)); assertTrue(db.containsContact(txn, contactId));
assertFalse(db.containsSubscription(txn, groupId)); assertFalse(db.containsSubscription(txn, groupId));
@@ -107,8 +109,7 @@ public class H2DatabaseTest extends TestCase {
db = open(true); db = open(true);
txn = db.startTransaction(); txn = db.startTransaction();
assertTrue(db.containsContact(txn, contactId)); assertTrue(db.containsContact(txn, contactId));
transports = db.getTransports(txn, contactId); assertEquals(transports, db.getTransports(txn, contactId));
assertEquals(Collections.singletonMap("foo", "bar"), transports);
assertTrue(db.containsSubscription(txn, groupId)); assertTrue(db.containsSubscription(txn, groupId));
assertTrue(db.containsMessage(txn, messageId)); assertTrue(db.containsMessage(txn, messageId));
byte[] raw1 = db.getMessage(txn, messageId); byte[] raw1 = db.getMessage(txn, messageId);
@@ -141,20 +142,20 @@ public class H2DatabaseTest extends TestCase {
// Create three contacts // Create three contacts
assertFalse(db.containsContact(txn, contactId)); assertFalse(db.containsContact(txn, contactId));
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
assertTrue(db.containsContact(txn, contactId)); assertTrue(db.containsContact(txn, contactId));
assertFalse(db.containsContact(txn, contactId1)); assertFalse(db.containsContact(txn, contactId1));
assertEquals(contactId1, db.addContact(txn, null)); assertEquals(contactId1, db.addContact(txn, transports));
assertTrue(db.containsContact(txn, contactId1)); assertTrue(db.containsContact(txn, contactId1));
assertFalse(db.containsContact(txn, contactId2)); assertFalse(db.containsContact(txn, contactId2));
assertEquals(contactId2, db.addContact(txn, null)); assertEquals(contactId2, db.addContact(txn, transports));
assertTrue(db.containsContact(txn, contactId2)); assertTrue(db.containsContact(txn, contactId2));
// Delete one of the contacts // Delete one of the contacts
db.removeContact(txn, contactId1); db.removeContact(txn, contactId1);
assertFalse(db.containsContact(txn, contactId1)); assertFalse(db.containsContact(txn, contactId1));
// Add another contact - a new ID should be created // Add another contact - a new ID should be created
assertFalse(db.containsContact(txn, contactId3)); assertFalse(db.containsContact(txn, contactId3));
assertEquals(contactId3, db.addContact(txn, null)); assertEquals(contactId3, db.addContact(txn, transports));
assertTrue(db.containsContact(txn, contactId3)); assertTrue(db.containsContact(txn, contactId3));
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -201,7 +202,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -239,7 +240,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -281,7 +282,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.addMessage(txn, message); db.addMessage(txn, message);
@@ -318,7 +319,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -349,7 +350,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
db.addMessage(txn, message); db.addMessage(txn, message);
@@ -382,7 +383,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and some batches to ack // Add a contact and some batches to ack
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addBatchToAck(txn, contactId, batchId); db.addBatchToAck(txn, contactId, batchId);
db.addBatchToAck(txn, contactId, batchId1); db.addBatchToAck(txn, contactId, batchId1);
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -410,7 +411,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and receive the same batch twice // Add a contact and receive the same batch twice
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addBatchToAck(txn, contactId, batchId); db.addBatchToAck(txn, contactId, batchId);
db.addBatchToAck(txn, contactId, batchId); db.addBatchToAck(txn, contactId, batchId);
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -437,7 +438,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -474,7 +475,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -517,7 +518,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact // Add a contact
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
// Add some outstanding batches, a few ms apart // Add some outstanding batches, a few ms apart
for(int i = 0; i < ids.length; i++) { for(int i = 0; i < ids.length; i++) {
db.addOutstandingBatch(txn, contactId, ids[i], db.addOutstandingBatch(txn, contactId, ids[i],
@@ -556,7 +557,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact // Add a contact
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
// Add some outstanding batches, a few ms apart // Add some outstanding batches, a few ms apart
for(int i = 0; i < ids.length; i++) { for(int i = 0; i < ids.length; i++) {
db.addOutstandingBatch(txn, contactId, ids[i], db.addOutstandingBatch(txn, contactId, ids[i],
@@ -784,24 +785,28 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact with some transport properties // Add a contact with some transport properties
Map<String, String> transports = Collections.singletonMap("foo", "bar");
assertEquals(contactId, db.addContact(txn, transports)); assertEquals(contactId, db.addContact(txn, transports));
assertEquals(transports, db.getTransports(txn, contactId)); assertEquals(transports, db.getTransports(txn, contactId));
// Replace the transport properties // Replace the transport properties
transports = new TreeMap<String, String>(); Map<String, Map<String, String>> transports1 =
transports.put("foo", "bar baz"); new TreeMap<String, Map<String, String>>();
transports.put("bar", "baz quux"); transports1.put("foo", Collections.singletonMap("bar", "baz"));
db.setTransports(txn, contactId, transports, 1); transports1.put("bar", Collections.singletonMap("baz", "quux"));
assertEquals(transports, db.getTransports(txn, contactId)); db.setTransports(txn, contactId, transports1, 1);
assertEquals(transports1, db.getTransports(txn, contactId));
// Remove the transport properties // Remove the transport properties
db.setTransports(txn, contactId, db.setTransports(txn, contactId,
Collections.<String, String>emptyMap(), 2); Collections.<String, Map<String, String>>emptyMap(), 2);
assertEquals(Collections.emptyMap(), db.getTransports(txn, contactId)); assertEquals(Collections.emptyMap(), db.getTransports(txn, contactId));
// Set the local transport properties // Set the local transport properties
db.setTransports(txn, transports); for(String s : transports.keySet()) {
db.setTransports(txn, s, transports.get(s));
}
assertEquals(transports, db.getTransports(txn)); assertEquals(transports, db.getTransports(txn));
// Remove the local transport properties // Remove the local transport properties
db.setTransports(txn, Collections.<String, String>emptyMap()); for(String s : transports.keySet()) {
db.setTransports(txn, s, Collections.<String, String>emptyMap());
}
assertEquals(Collections.emptyMap(), db.getTransports(txn)); assertEquals(Collections.emptyMap(), db.getTransports(txn));
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -814,19 +819,20 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact with some transport properties // Add a contact with some transport properties
Map<String, String> transports = Collections.singletonMap("foo", "bar");
assertEquals(contactId, db.addContact(txn, transports)); assertEquals(contactId, db.addContact(txn, transports));
assertEquals(transports, db.getTransports(txn, contactId)); assertEquals(transports, db.getTransports(txn, contactId));
// Replace the transport properties using a timestamp of 2 // Replace the transport properties using a timestamp of 2
Map<String, String> transports1 = new TreeMap<String, String>(); Map<String, Map<String, String>> transports1 =
transports1.put("foo", "bar baz"); new TreeMap<String, Map<String, String>>();
transports1.put("bar", "baz quux"); transports1.put("foo", Collections.singletonMap("bar", "baz"));
transports1.put("bar", Collections.singletonMap("baz", "quux"));
db.setTransports(txn, contactId, transports1, 2); db.setTransports(txn, contactId, transports1, 2);
assertEquals(transports1, db.getTransports(txn, contactId)); assertEquals(transports1, db.getTransports(txn, contactId));
// Try to replace the transport properties using a timestamp of 1 // Try to replace the transport properties using a timestamp of 1
Map<String, String> transports2 = new TreeMap<String, String>(); Map<String, Map<String, String>> transports2 =
transports2.put("bar", "baz"); new TreeMap<String, Map<String, String>>();
transports2.put("quux", "fnord"); transports2.put("bar", Collections.singletonMap("baz", "quux"));
transports2.put("baz", Collections.singletonMap("quux", "fnord"));
db.setTransports(txn, contactId, transports2, 1); db.setTransports(txn, contactId, transports2, 1);
// The old properties should still be there // The old properties should still be there
assertEquals(transports1, db.getTransports(txn, contactId)); assertEquals(transports1, db.getTransports(txn, contactId));
@@ -844,7 +850,6 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact // Add a contact
Map<String, String> transports = Collections.emptyMap();
assertEquals(contactId, db.addContact(txn, transports)); assertEquals(contactId, db.addContact(txn, transports));
// Add some subscriptions // Add some subscriptions
Collection<Group> subs = Collections.singletonList(group); Collection<Group> subs = Collections.singletonList(group);
@@ -869,7 +874,6 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact // Add a contact
Map<String, String> transports = Collections.emptyMap();
assertEquals(contactId, db.addContact(txn, transports)); assertEquals(contactId, db.addContact(txn, transports));
// Add some subscriptions // Add some subscriptions
Collection<Group> subs = Collections.singletonList(group); Collection<Group> subs = Collections.singletonList(group);
@@ -892,7 +896,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and subscribe to a group // Add a contact and subscribe to a group
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -910,7 +914,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
db.addMessage(txn, message); db.addMessage(txn, message);
@@ -933,7 +937,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
db.addMessage(txn, message); db.addMessage(txn, message);
@@ -955,7 +959,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -980,7 +984,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and subscribe to a group // Add a contact and subscribe to a group
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -999,7 +1003,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and a neighbour subscription // Add a contact and a neighbour subscription
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
// There's no local subscription for the group // There's no local subscription for the group
@@ -1016,7 +1020,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.addMessage(txn, message); db.addMessage(txn, message);
db.setStatus(txn, contactId, messageId, Status.NEW); db.setStatus(txn, contactId, messageId, Status.NEW);
@@ -1035,7 +1039,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.addMessage(txn, message); db.addMessage(txn, message);
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -1055,7 +1059,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -1076,7 +1080,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact, subscribe to a group and store a message // Add a contact, subscribe to a group and store a message
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
db.setVisibility(txn, groupId, Collections.singleton(contactId)); db.setVisibility(txn, groupId, Collections.singleton(contactId));
db.setSubscriptions(txn, contactId, Collections.singleton(group), 1); db.setSubscriptions(txn, contactId, Collections.singleton(group), 1);
@@ -1096,7 +1100,7 @@ public class H2DatabaseTest extends TestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
// Add a contact and subscribe to a group // Add a contact and subscribe to a group
assertEquals(contactId, db.addContact(txn, null)); assertEquals(contactId, db.addContact(txn, transports));
db.addSubscription(txn, group); db.addSubscription(txn, group);
// The group should not be visible to the contact // The group should not be visible to the contact

View File

@@ -10,6 +10,7 @@ import java.util.BitSet;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import junit.framework.TestCase; import junit.framework.TestCase;
import net.sf.briar.TestUtils; import net.sf.briar.TestUtils;
@@ -72,6 +73,7 @@ public class FileReadWriteTest extends TestCase {
private final Message message, message1, message2, message3; private final Message message, message1, message2, message3;
private final String authorName = "Alice"; private final String authorName = "Alice";
private final String messageBody = "Hello world"; private final String messageBody = "Hello world";
private final Map<String, Map<String, String>> transports;
public FileReadWriteTest() throws Exception { public FileReadWriteTest() throws Exception {
super(); super();
@@ -111,6 +113,8 @@ public class FileReadWriteTest extends TestCase {
message3 = messageEncoder.encodeMessage(MessageId.NONE, group1, message3 = messageEncoder.encodeMessage(MessageId.NONE, group1,
groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(), groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(),
messageBody.getBytes("UTF-8")); messageBody.getBytes("UTF-8"));
transports = Collections.singletonMap("foo",
Collections.singletonMap("bar", "baz"));
} }
@Before @Before
@@ -154,7 +158,7 @@ public class FileReadWriteTest extends TestCase {
s.writeSubscriptions(subs); s.writeSubscriptions(subs);
TransportWriter t = packetWriterFactory.createTransportWriter(out); TransportWriter t = packetWriterFactory.createTransportWriter(out);
t.writeTransports(Collections.singletonMap("foo", "bar")); t.writeTransports(transports);
out.close(); out.close();
assertTrue(file.exists()); assertTrue(file.exists());
@@ -229,7 +233,7 @@ public class FileReadWriteTest extends TestCase {
assertTrue(reader.hasUserDefined(Tags.TRANSPORTS)); assertTrue(reader.hasUserDefined(Tags.TRANSPORTS));
Transports t = reader.readUserDefined(Tags.TRANSPORTS, Transports t = reader.readUserDefined(Tags.TRANSPORTS,
Transports.class); Transports.class);
assertEquals(Collections.singletonMap("foo", "bar"), t.getTransports()); assertEquals(transports, t.getTransports());
assertTrue(t.getTimestamp() > start); assertTrue(t.getTimestamp() > start);
assertTrue(t.getTimestamp() <= System.currentTimeMillis()); assertTrue(t.getTimestamp() <= System.currentTimeMillis());