diff --git a/api/net/sf/briar/api/db/DatabaseComponent.java b/api/net/sf/briar/api/db/DatabaseComponent.java index 4bbbaec88..f8dda8592 100644 --- a/api/net/sf/briar/api/db/DatabaseComponent.java +++ b/api/net/sf/briar/api/db/DatabaseComponent.java @@ -14,8 +14,8 @@ import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; -import net.sf.briar.api.protocol.Subscriptions; -import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.protocol.SubscriptionUpdate; +import net.sf.briar.api.protocol.TransportUpdate; import net.sf.briar.api.protocol.writers.AckWriter; import net.sf.briar.api.protocol.writers.BatchWriter; import net.sf.briar.api.protocol.writers.OfferWriter; @@ -95,11 +95,11 @@ public interface DatabaseComponent { throws DbException, IOException; /** Generates a subscription update for the given contact. */ - void generateSubscriptions(ContactId c, SubscriptionWriter s) throws + void generateSubscriptionUpdate(ContactId c, SubscriptionWriter s) throws DbException, IOException; /** Generates a transport update for the given contact. */ - void generateTransports(ContactId c, TransportWriter t) throws + void generateTransportUpdate(ContactId c, TransportWriter t) throws DbException, IOException; /** Returns the IDs of all contacts. */ @@ -111,10 +111,13 @@ public interface DatabaseComponent { /** Returns the set of groups to which the user subscribes. */ Collection getSubscriptions() throws DbException; - /** Returns the local transport properties. */ + /** Returns the configuration for the transport with the given name. */ + Map getTransportConfig(String name) throws DbException; + + /** Returns all local transport properties. */ Map> getTransports() throws DbException; - /** Returns the transport properties for the given contact. */ + /** Returns all transport properties for the given contact. */ Map> getTransports(ContactId c) throws DbException; @@ -142,10 +145,12 @@ public interface DatabaseComponent { IOException; /** Processes a subscription update from the given contact. */ - void receiveSubscriptions(ContactId c, Subscriptions s) throws DbException; + void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate s) + throws DbException; /** Processes a transport update from the given contact. */ - void receiveTransports(ContactId c, Transports t) throws DbException; + void receiveTransportUpdate(ContactId c, TransportUpdate t) + throws DbException; /** Removes a contact (and all associated state) from the database. */ void removeContact(ContactId c) throws DbException; @@ -154,10 +159,17 @@ public interface DatabaseComponent { void setRating(AuthorId a, Rating r) throws DbException; /** - * Sets the local transport properties for the transport with the given - * name, replacing any existing properties for that transport. + * Sets the configuration for the transport with the given name, replacing + * any existing configuration for that transport. */ - void setTransports(String name, Map transports) + void setTransportConfig(String name, Map config) + throws DbException; + + /** + * Sets the transport properties for the transport with the given name, + * replacing any existing properties for that transport. + */ + void setTransportProperties(String name, Map properties) throws DbException; /** diff --git a/api/net/sf/briar/api/protocol/Subscriptions.java b/api/net/sf/briar/api/protocol/SubscriptionUpdate.java similarity index 82% rename from api/net/sf/briar/api/protocol/Subscriptions.java rename to api/net/sf/briar/api/protocol/SubscriptionUpdate.java index 28d670c08..cdbd2fa20 100644 --- a/api/net/sf/briar/api/protocol/Subscriptions.java +++ b/api/net/sf/briar/api/protocol/SubscriptionUpdate.java @@ -3,10 +3,10 @@ package net.sf.briar.api.protocol; import java.util.Collection; /** A packet updating the sender's subscriptions. */ -public interface Subscriptions { +public interface SubscriptionUpdate { /** - * The maximum size of a serialized subscriptions update, excluding + * The maximum size of a serialized subscription update, excluding * encryption and authentication. */ static final int MAX_SIZE = (1024 * 1024) - 100; diff --git a/api/net/sf/briar/api/protocol/Transports.java b/api/net/sf/briar/api/protocol/TransportUpdate.java similarity index 62% rename from api/net/sf/briar/api/protocol/Transports.java rename to api/net/sf/briar/api/protocol/TransportUpdate.java index 8af5d09ac..742ddaad2 100644 --- a/api/net/sf/briar/api/protocol/Transports.java +++ b/api/net/sf/briar/api/protocol/TransportUpdate.java @@ -2,16 +2,16 @@ package net.sf.briar.api.protocol; import java.util.Map; -/** A packet updating the sender's transports. */ -public interface Transports { +/** A packet updating the sender's transport properties. */ +public interface TransportUpdate { /** - * The maximum size of a serialised transports update, excluding + * The maximum size of a serialised transport update, excluding * encryption and authentication. */ static final int MAX_SIZE = (1024 * 1024) - 100; - /** Returns the transports contained in the update. */ + /** Returns the transport properties contained in the update. */ Map> getTransports(); /** diff --git a/api/net/sf/briar/api/protocol/writers/TransportWriter.java b/api/net/sf/briar/api/protocol/writers/TransportWriter.java index f835e0059..a8e7f9f76 100644 --- a/api/net/sf/briar/api/protocol/writers/TransportWriter.java +++ b/api/net/sf/briar/api/protocol/writers/TransportWriter.java @@ -3,7 +3,7 @@ package net.sf.briar.api.protocol.writers; import java.io.IOException; import java.util.Map; -/** An interface for creating a transports update. */ +/** An interface for creating a transport update. */ public interface TransportWriter { /** Writes the contents of the update. */ diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java index f60389303..f3f7a865a 100644 --- a/components/net/sf/briar/db/Database.java +++ b/components/net/sf/briar/db/Database.java @@ -268,14 +268,22 @@ interface Database { Collection getSubscriptions(T txn, ContactId c) throws DbException; /** - * Returns the local transport properties. + * Returns the configuration for the transport with the given name. + *

+ * Locking: transports read. + */ + Map getTransportConfig(T txn, String name) + throws DbException; + + /** + * Returns all local transport properties. *

* Locking: transports read. */ Map> getTransports(T txn) throws DbException; /** - * Returns the transport properties for the given contact. + * Returns all transport properties for the given contact. *

* Locking: contacts read, transports read. */ @@ -398,14 +406,23 @@ interface Database { long timestamp) throws DbException; /** - * Sets the local transport properties for the transport with the given - * name, replacing any existing properties for that transport. + * Sets the configuration for the transport with the given name, replacing + * any existing configuration for that transport. *

* Locking: transports write. */ - void setTransports(T txn, String name, Map transports) + void setTransportConfig(T txn, String name, Map config) throws DbException; + /** + * Sets the transport properties for the transport with the given name, + * replacing any existing properties for that transport. + *

+ * Locking: transports write. + */ + void setTransportProperties(T txn, String name, + Map properties) throws DbException; + /** * Sets the transport properties for the given contact, replacing any * existing properties unless the existing properties have a newer diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java index f31fefffd..6a4df751b 100644 --- a/components/net/sf/briar/db/JdbcDatabase.java +++ b/components/net/sf/briar/db/JdbcDatabase.java @@ -173,6 +173,13 @@ abstract class JdbcDatabase implements Database { + " value VARCHAR NOT NULL," + " PRIMARY KEY (transportName, key))"; + private static final String CREATE_TRANSPORT_CONFIG = + "CREATE TABLE transportConfig" + + " (transportName VARCHAR NOT NULL," + + " key VARCHAR NOT NULL," + + " value VARCHAR NOT NULL," + + " PRIMARY KEY (transportName, key))"; + private static final Logger LOG = Logger.getLogger(JdbcDatabase.class.getName()); @@ -255,6 +262,7 @@ abstract class JdbcDatabase implements Database { s.executeUpdate(INDEX_STATUSES_BY_CONTACT); s.executeUpdate(insertTypeNames(CREATE_CONTACT_TRANSPORTS)); s.executeUpdate(insertTypeNames(CREATE_TRANSPORTS)); + s.executeUpdate(insertTypeNames(CREATE_TRANSPORT_CONFIG)); s.close(); } catch(SQLException e) { tryToClose(s); @@ -1096,6 +1104,115 @@ abstract class JdbcDatabase implements Database { } } + public Map getTransportConfig(Connection txn, + String name) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT key, value FROM transportConfig" + + " WHERE transportName = ?"; + ps = txn.prepareStatement(sql); + ps.setString(1, name); + rs = ps.executeQuery(); + Map config = new TreeMap(); + while(rs.next()) config.put(rs.getString(1), rs.getString(2)); + rs.close(); + ps.close(); + return config; + } catch(SQLException e) { + tryToClose(rs); + tryToClose(ps); + throw new DbException(e); + } + } + + public Map> getTransports(Connection txn) + throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT transportName, key, value" + + " FROM transports" + + " ORDER BY transportName"; + ps = txn.prepareStatement(sql); + rs = ps.executeQuery(); + Map> transports = + new TreeMap>(); + Map properties = null; + String lastName = null; + while(rs.next()) { + String name = rs.getString(1); + if(!name.equals(lastName)) { + properties = new TreeMap(); + transports.put(name, properties); + } + properties.put(rs.getString(2), rs.getString(3)); + } + rs.close(); + ps.close(); + return transports; + } catch(SQLException e) { + tryToClose(rs); + tryToClose(ps); + throw new DbException(e); + } + } + + public Map> getTransports(Connection txn, + ContactId c) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT transportName, key, value" + + " FROM contactTransports" + + " WHERE contactId = ?" + + " ORDER BY transportName"; + ps = txn.prepareStatement(sql); + ps.setInt(1, c.getInt()); + rs = ps.executeQuery(); + Map> transports = + new TreeMap>(); + Map properties = null; + String lastName = null; + while(rs.next()) { + String name = rs.getString(1); + if(!name.equals(lastName)) { + properties = new TreeMap(); + transports.put(name, properties); + } + properties.put(rs.getString(2), rs.getString(3)); + } + rs.close(); + ps.close(); + return transports; + } catch(SQLException e) { + tryToClose(rs); + tryToClose(ps); + throw new DbException(e); + } + } + + public Collection getVisibility(Connection txn, GroupId g) + throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT contactId FROM visibilities WHERE groupId = ?"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, g.getBytes()); + rs = ps.executeQuery(); + Collection visible = new ArrayList(); + while(rs.next()) visible.add(new ContactId(rs.getInt(1))); + rs.close(); + ps.close(); + return visible; + } catch(SQLException e) { + tryToClose(rs); + tryToClose(ps); + throw new DbException(e); + } + } + public Collection getVisibleSubscriptions(Connection txn, ContactId c) throws DbException { PreparedStatement ps = null; @@ -1125,93 +1242,6 @@ abstract class JdbcDatabase implements Database { } } - public Map> getTransports(Connection txn) - throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT transportName, key, value" - + " FROM transports" - + " ORDER BY transportName"; - ps = txn.prepareStatement(sql); - rs = ps.executeQuery(); - Map> outer = - new TreeMap>(); - Map inner = null; - String lastName = null; - while(rs.next()) { - String name = rs.getString(1); - if(!name.equals(lastName)) { - inner = new TreeMap(); - outer.put(name, inner); - } - inner.put(rs.getString(2), rs.getString(3)); - } - rs.close(); - ps.close(); - return outer; - } catch(SQLException e) { - tryToClose(rs); - tryToClose(ps); - throw new DbException(e); - } - } - - public Map> getTransports(Connection txn, - ContactId c) throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT transportName, key, value" - + " FROM contactTransports" - + " WHERE contactId = ?" - + " ORDER BY transportName"; - ps = txn.prepareStatement(sql); - ps.setInt(1, c.getInt()); - rs = ps.executeQuery(); - Map> outer = - new TreeMap>(); - Map inner = null; - String lastName = null; - while(rs.next()) { - String name = rs.getString(1); - if(!name.equals(lastName)) { - inner = new TreeMap(); - outer.put(name, inner); - } - inner.put(rs.getString(2), rs.getString(3)); - } - rs.close(); - ps.close(); - return outer; - } catch(SQLException e) { - tryToClose(rs); - tryToClose(ps); - throw new DbException(e); - } - } - - public Collection getVisibility(Connection txn, GroupId g) - throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT contactId FROM visibilities WHERE groupId = ?"; - ps = txn.prepareStatement(sql); - ps.setBytes(1, g.getBytes()); - rs = ps.executeQuery(); - Collection visible = new ArrayList(); - while(rs.next()) visible.add(new ContactId(rs.getInt(1))); - rs.close(); - ps.close(); - return visible; - } catch(SQLException e) { - tryToClose(rs); - tryToClose(ps); - throw new DbException(e); - } - } - public boolean hasSendableMessages(Connection txn, ContactId c) throws DbException { PreparedStatement ps = null; @@ -1609,28 +1639,33 @@ abstract class JdbcDatabase implements Database { } } - public void setTransports(Connection txn, String name, - Map transports) throws DbException { + public void setTransportConfig(Connection txn, String name, + Map config) throws DbException { + setTransportDetails(txn, name, config, "transportConfig"); + } + + private void setTransportDetails(Connection txn, String name, + Map details, String table) throws DbException { PreparedStatement ps = null; try { - // Delete any existing properties for the named transport - String sql = "DELETE FROM transports WHERE transportName = ?"; + // Delete any existing details for the named transport + String sql = "DELETE FROM " + table + " WHERE transportName = ?"; ps = txn.prepareStatement(sql); ps.setString(1, name); ps.executeUpdate(); ps.close(); - // Store the new properties - sql = "INSERT INTO transports (transportName, key, value)" + // Store the new details + sql = "INSERT INTO " + table + " (transportName, key, value)" + " VALUES (?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setString(1, name); - for(Entry e : transports.entrySet()) { + for(Entry e : details.entrySet()) { ps.setString(2, e.getKey()); ps.setString(3, e.getValue()); ps.addBatch(); } int[] batchAffected = ps.executeBatch(); - if(batchAffected.length != transports.size()) + if(batchAffected.length != details.size()) throw new DbStateException(); for(int i = 0; i < batchAffected.length; i++) { if(batchAffected[i] != 1) throw new DbStateException(); @@ -1642,6 +1677,11 @@ abstract class JdbcDatabase implements Database { } } + public void setTransportProperties(Connection txn, String name, + Map properties) throws DbException { + setTransportDetails(txn, name, properties, "transports"); + } + public void setTransports(Connection txn, ContactId c, Map> transports, long timestamp) throws DbException { diff --git a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java index 9d85dbe78..2221390f4 100644 --- a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java +++ b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java @@ -24,8 +24,8 @@ import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; -import net.sf.briar.api.protocol.Subscriptions; -import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.protocol.SubscriptionUpdate; +import net.sf.briar.api.protocol.TransportUpdate; import net.sf.briar.api.protocol.writers.AckWriter; import net.sf.briar.api.protocol.writers.BatchWriter; import net.sf.briar.api.protocol.writers.OfferWriter; @@ -107,7 +107,12 @@ class ReadWriteLockDatabaseComponent extends DatabaseComponentImpl { try { subscriptionLock.writeLock().lock(); try { - db.close(); + transportLock.writeLock().lock(); + try { + db.close(); + } finally { + transportLock.writeLock().unlock(); + } } finally { subscriptionLock.writeLock().unlock(); } @@ -459,7 +464,7 @@ class ReadWriteLockDatabaseComponent extends DatabaseComponentImpl { } } - public void generateSubscriptions(ContactId c, SubscriptionWriter s) + public void generateSubscriptionUpdate(ContactId c, SubscriptionWriter s) throws DbException, IOException { contactLock.readLock().lock(); try { @@ -488,7 +493,7 @@ class ReadWriteLockDatabaseComponent extends DatabaseComponentImpl { } } - public void generateTransports(ContactId c, TransportWriter t) + public void generateTransportUpdate(ContactId c, TransportWriter t) throws DbException, IOException { contactLock.readLock().lock(); try { @@ -569,6 +574,24 @@ class ReadWriteLockDatabaseComponent extends DatabaseComponentImpl { } } + public Map getTransportConfig(String name) + throws DbException { + transportLock.readLock().lock(); + try { + Txn txn = db.startTransaction(); + try { + Map config = db.getTransportConfig(txn, name); + db.commitTransaction(txn); + return config; + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } finally { + transportLock.readLock().unlock(); + } + } + public Map> getTransports() throws DbException { transportLock.readLock().lock(); try { @@ -793,7 +816,7 @@ class ReadWriteLockDatabaseComponent extends DatabaseComponentImpl { } } - public void receiveSubscriptions(ContactId c, Subscriptions s) + public void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate s) throws DbException { // Update the contact's subscriptions contactLock.writeLock().lock(); @@ -820,7 +843,7 @@ class ReadWriteLockDatabaseComponent extends DatabaseComponentImpl { } } - public void receiveTransports(ContactId c, Transports t) + public void receiveTransportUpdate(ContactId c, TransportUpdate t) throws DbException { // Update the contact's transport properties contactLock.writeLock().lock(); @@ -907,15 +930,40 @@ class ReadWriteLockDatabaseComponent extends DatabaseComponentImpl { } } - public void setTransports(String name, Map transports) - throws DbException { + public void setTransportConfig(String name, + Map config) throws DbException { boolean changed = false; transportLock.writeLock().lock(); try { Txn txn = db.startTransaction(); try { - if(!transports.equals(db.getTransports(txn).get(name))) { - db.setTransports(txn, name, transports); + Map old = db.getTransportConfig(txn, name); + if(!config.equals(old)) { + db.setTransportConfig(txn, name, config); + changed = true; + } + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } finally { + transportLock.writeLock().unlock(); + } + // Call the listeners outside the lock + if(changed) callListeners(DatabaseListener.Event.TRANSPORTS_UPDATED); + } + + public void setTransportProperties(String name, + Map properties) throws DbException { + boolean changed = false; + transportLock.writeLock().lock(); + try { + Txn txn = db.startTransaction(); + try { + Map old = db.getTransports(txn).get(name); + if(!properties.equals(old)) { + db.setTransportProperties(txn, name, properties); changed = true; } db.commitTransaction(txn); diff --git a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java index 1d7a48350..381dda60f 100644 --- a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java +++ b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java @@ -23,8 +23,8 @@ import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; -import net.sf.briar.api.protocol.Subscriptions; -import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.protocol.SubscriptionUpdate; +import net.sf.briar.api.protocol.TransportUpdate; import net.sf.briar.api.protocol.writers.AckWriter; import net.sf.briar.api.protocol.writers.BatchWriter; import net.sf.briar.api.protocol.writers.OfferWriter; @@ -336,7 +336,7 @@ class SynchronizedDatabaseComponent extends DatabaseComponentImpl { } } - public void generateSubscriptions(ContactId c, SubscriptionWriter s) + public void generateSubscriptionUpdate(ContactId c, SubscriptionWriter s) throws DbException, IOException { synchronized(contactLock) { if(!containsContact(c)) throw new NoSuchContactException(); @@ -359,7 +359,7 @@ class SynchronizedDatabaseComponent extends DatabaseComponentImpl { } } - public void generateTransports(ContactId c, TransportWriter t) + public void generateTransportUpdate(ContactId c, TransportWriter t) throws DbException, IOException { synchronized(contactLock) { if(!containsContact(c)) throw new NoSuchContactException(); @@ -425,6 +425,21 @@ class SynchronizedDatabaseComponent extends DatabaseComponentImpl { } } + public Map getTransportConfig(String name) + throws DbException { + synchronized(transportLock) { + Txn txn = db.startTransaction(); + try { + Map config = db.getTransportConfig(txn, name); + db.commitTransaction(txn); + return config; + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } + } + public Map> getTransports() throws DbException { synchronized(transportLock) { Txn txn = db.startTransaction(); @@ -589,7 +604,7 @@ class SynchronizedDatabaseComponent extends DatabaseComponentImpl { } } - public void receiveSubscriptions(ContactId c, Subscriptions s) + public void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate s) throws DbException { // Update the contact's subscriptions synchronized(contactLock) { @@ -610,7 +625,7 @@ class SynchronizedDatabaseComponent extends DatabaseComponentImpl { } } - public void receiveTransports(ContactId c, Transports t) + public void receiveTransportUpdate(ContactId c, TransportUpdate t) throws DbException { // Update the contact's transport properties synchronized(contactLock) { @@ -673,14 +688,36 @@ class SynchronizedDatabaseComponent extends DatabaseComponentImpl { } } - public void setTransports(String name, Map transports) - throws DbException { + public void setTransportConfig(String name, + Map config) throws DbException { boolean changed = false; synchronized(transportLock) { Txn txn = db.startTransaction(); try { - if(!transports.equals(db.getTransports(txn).get(name))) { - db.setTransports(txn, name, transports); + Map old = db.getTransportConfig(txn, name); + if(!config.equals(old)) { + db.setTransportConfig(txn, name, config); + changed = true; + } + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } + // Call the listeners outside the lock + if(changed) callListeners(DatabaseListener.Event.TRANSPORTS_UPDATED); + } + + public void setTransportProperties(String name, + Map properties) throws DbException { + boolean changed = false; + synchronized(transportLock) { + Txn txn = db.startTransaction(); + try { + Map old = db.getTransports(txn).get(name); + if(!properties.equals(old)) { + db.setTransportProperties(txn, name, properties); changed = true; } db.commitTransaction(txn); diff --git a/components/net/sf/briar/protocol/SubscriptionFactory.java b/components/net/sf/briar/protocol/SubscriptionFactory.java index d6be2b293..136bcffea 100644 --- a/components/net/sf/briar/protocol/SubscriptionFactory.java +++ b/components/net/sf/briar/protocol/SubscriptionFactory.java @@ -3,9 +3,9 @@ package net.sf.briar.protocol; import java.util.Collection; import net.sf.briar.api.protocol.Group; -import net.sf.briar.api.protocol.Subscriptions; +import net.sf.briar.api.protocol.SubscriptionUpdate; interface SubscriptionFactory { - Subscriptions createSubscriptions(Collection subs, long timestamp); + SubscriptionUpdate createSubscriptions(Collection subs, long timestamp); } diff --git a/components/net/sf/briar/protocol/SubscriptionFactoryImpl.java b/components/net/sf/briar/protocol/SubscriptionFactoryImpl.java index 53c21e50c..0d3391ebe 100644 --- a/components/net/sf/briar/protocol/SubscriptionFactoryImpl.java +++ b/components/net/sf/briar/protocol/SubscriptionFactoryImpl.java @@ -3,11 +3,11 @@ package net.sf.briar.protocol; import java.util.Collection; import net.sf.briar.api.protocol.Group; -import net.sf.briar.api.protocol.Subscriptions; +import net.sf.briar.api.protocol.SubscriptionUpdate; class SubscriptionFactoryImpl implements SubscriptionFactory { - public Subscriptions createSubscriptions(Collection subs, + public SubscriptionUpdate createSubscriptions(Collection subs, long timestamp) { return new SubscriptionsImpl(subs, timestamp); } diff --git a/components/net/sf/briar/protocol/SubscriptionReader.java b/components/net/sf/briar/protocol/SubscriptionReader.java index b3c68b9b6..c13125d6a 100644 --- a/components/net/sf/briar/protocol/SubscriptionReader.java +++ b/components/net/sf/briar/protocol/SubscriptionReader.java @@ -4,7 +4,7 @@ import java.io.IOException; import java.util.Collection; import net.sf.briar.api.protocol.Group; -import net.sf.briar.api.protocol.Subscriptions; +import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.serial.Consumer; import net.sf.briar.api.serial.ObjectReader; @@ -12,7 +12,7 @@ import net.sf.briar.api.serial.Reader; import com.google.inject.Inject; -class SubscriptionReader implements ObjectReader { +class SubscriptionReader implements ObjectReader { private final ObjectReader groupReader; private final SubscriptionFactory subscriptionFactory; @@ -24,9 +24,9 @@ class SubscriptionReader implements ObjectReader { this.subscriptionFactory = subscriptionFactory; } - public Subscriptions readObject(Reader r) throws IOException { + public SubscriptionUpdate readObject(Reader r) throws IOException { // Initialise the consumer - Consumer counting = new CountingConsumer(Subscriptions.MAX_SIZE); + Consumer counting = new CountingConsumer(SubscriptionUpdate.MAX_SIZE); // Read the data r.addConsumer(counting); r.readUserDefinedTag(Tags.SUBSCRIPTIONS); @@ -35,7 +35,7 @@ class SubscriptionReader implements ObjectReader { r.removeObjectReader(Tags.GROUP); long timestamp = r.readInt64(); r.removeConsumer(counting); - // Build and return the subscriptions update + // Build and return the subscription update return subscriptionFactory.createSubscriptions(subs, timestamp); } } diff --git a/components/net/sf/briar/protocol/SubscriptionsImpl.java b/components/net/sf/briar/protocol/SubscriptionsImpl.java index c3967cfc8..43be09e70 100644 --- a/components/net/sf/briar/protocol/SubscriptionsImpl.java +++ b/components/net/sf/briar/protocol/SubscriptionsImpl.java @@ -3,9 +3,9 @@ package net.sf.briar.protocol; import java.util.Collection; import net.sf.briar.api.protocol.Group; -import net.sf.briar.api.protocol.Subscriptions; +import net.sf.briar.api.protocol.SubscriptionUpdate; -class SubscriptionsImpl implements Subscriptions { +class SubscriptionsImpl implements SubscriptionUpdate { private final Collection subs; private final long timestamp; diff --git a/components/net/sf/briar/protocol/TransportFactory.java b/components/net/sf/briar/protocol/TransportFactory.java index d56c0c582..d784e7aa3 100644 --- a/components/net/sf/briar/protocol/TransportFactory.java +++ b/components/net/sf/briar/protocol/TransportFactory.java @@ -2,10 +2,10 @@ package net.sf.briar.protocol; import java.util.Map; -import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.protocol.TransportUpdate; interface TransportFactory { - Transports createTransports(Map> transports, + TransportUpdate createTransports(Map> transports, long timestamp); } diff --git a/components/net/sf/briar/protocol/TransportFactoryImpl.java b/components/net/sf/briar/protocol/TransportFactoryImpl.java index 1cabeed06..376653a3a 100644 --- a/components/net/sf/briar/protocol/TransportFactoryImpl.java +++ b/components/net/sf/briar/protocol/TransportFactoryImpl.java @@ -2,11 +2,11 @@ package net.sf.briar.protocol; import java.util.Map; -import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.protocol.TransportUpdate; class TransportFactoryImpl implements TransportFactory { - public Transports createTransports(Map> transports, + public TransportUpdate createTransports(Map> transports, long timestamp) { return new TransportsImpl(transports, timestamp); } diff --git a/components/net/sf/briar/protocol/TransportReader.java b/components/net/sf/briar/protocol/TransportReader.java index b945c1b65..92a2a4790 100644 --- a/components/net/sf/briar/protocol/TransportReader.java +++ b/components/net/sf/briar/protocol/TransportReader.java @@ -5,14 +5,14 @@ import java.util.Map; import java.util.TreeMap; import net.sf.briar.api.protocol.Tags; -import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.protocol.TransportUpdate; import net.sf.briar.api.serial.Consumer; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; import com.google.inject.Inject; -class TransportReader implements ObjectReader { +class TransportReader implements ObjectReader { private final TransportFactory transportFactory; @@ -21,32 +21,32 @@ class TransportReader implements ObjectReader { this.transportFactory = transportFactory; } - public Transports readObject(Reader r) throws IOException { + public TransportUpdate readObject(Reader r) throws IOException { // Initialise the consumer - Consumer counting = new CountingConsumer(Transports.MAX_SIZE); + Consumer counting = new CountingConsumer(TransportUpdate.MAX_SIZE); // Read the data r.addConsumer(counting); r.readUserDefinedTag(Tags.TRANSPORTS); // Transport maps are always written in delimited form - Map> outer = + Map> transports = new TreeMap>(); r.readMapStart(); while(!r.hasMapEnd()) { - String name = r.readString(Transports.MAX_SIZE); - Map inner = new TreeMap(); + String name = r.readString(TransportUpdate.MAX_SIZE); + Map properties = new TreeMap(); r.readMapStart(); while(!r.hasMapEnd()) { - String key = r.readString(Transports.MAX_SIZE); - String value = r.readString(Transports.MAX_SIZE); - inner.put(key, value); + String key = r.readString(TransportUpdate.MAX_SIZE); + String value = r.readString(TransportUpdate.MAX_SIZE); + properties.put(key, value); } r.readMapEnd(); - outer.put(name, inner); + transports.put(name, properties); } r.readMapEnd(); long timestamp = r.readInt64(); r.removeConsumer(counting); - // Build and return the transports update - return transportFactory.createTransports(outer, timestamp); + // Build and return the transport update + return transportFactory.createTransports(transports, timestamp); } } diff --git a/components/net/sf/briar/protocol/TransportsImpl.java b/components/net/sf/briar/protocol/TransportsImpl.java index 157b1d2af..988c071fa 100644 --- a/components/net/sf/briar/protocol/TransportsImpl.java +++ b/components/net/sf/briar/protocol/TransportsImpl.java @@ -2,9 +2,9 @@ package net.sf.briar.protocol; import java.util.Map; -import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.protocol.TransportUpdate; -class TransportsImpl implements Transports { +class TransportsImpl implements TransportUpdate { private final Map> transports; private final long timestamp; diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index cf8db1128..6ef02cdc9 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -24,8 +24,8 @@ import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; -import net.sf.briar.api.protocol.Subscriptions; -import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.protocol.SubscriptionUpdate; +import net.sf.briar.api.protocol.TransportUpdate; import net.sf.briar.api.protocol.writers.AckWriter; import net.sf.briar.api.protocol.writers.BatchWriter; import net.sf.briar.api.protocol.writers.OfferWriter; @@ -456,9 +456,9 @@ public abstract class DatabaseComponentTest extends TestCase { final Batch batch = context.mock(Batch.class); final Offer offer = context.mock(Offer.class); final RequestWriter requestWriter = context.mock(RequestWriter.class); - final Subscriptions subscriptionsUpdate = - context.mock(Subscriptions.class); - final Transports transportsUpdate = context.mock(Transports.class); + final SubscriptionUpdate subscriptionsUpdate = + context.mock(SubscriptionUpdate.class); + final TransportUpdate transportsUpdate = context.mock(TransportUpdate.class); context.checking(new Expectations() {{ // Check whether the contact is still in the DB - which it's not exactly(12).of(database).startTransaction(); @@ -491,12 +491,12 @@ public abstract class DatabaseComponentTest extends TestCase { } catch(NoSuchContactException expected) {} try { - db.generateSubscriptions(contactId, subscriptionWriter); + db.generateSubscriptionUpdate(contactId, subscriptionWriter); fail(); } catch(NoSuchContactException expected) {} try { - db.generateTransports(contactId, transportWriter); + db.generateTransportUpdate(contactId, transportWriter); fail(); } catch(NoSuchContactException expected) {} @@ -521,12 +521,12 @@ public abstract class DatabaseComponentTest extends TestCase { } catch(NoSuchContactException expected) {} try { - db.receiveSubscriptions(contactId, subscriptionsUpdate); + db.receiveSubscriptionUpdate(contactId, subscriptionsUpdate); fail(); } catch(NoSuchContactException expected) {} try { - db.receiveTransports(contactId, transportsUpdate); + db.receiveTransportUpdate(contactId, transportsUpdate); fail(); } catch(NoSuchContactException expected) {} @@ -696,7 +696,7 @@ public abstract class DatabaseComponentTest extends TestCase { } @Test - public void testGenerateSubscriptions() throws Exception { + public void testGenerateSubscriptionUpdate() throws Exception { final MessageId messageId1 = new MessageId(TestUtils.getRandomId()); final Collection sendable = new ArrayList(); sendable.add(messageId); @@ -722,13 +722,13 @@ public abstract class DatabaseComponentTest extends TestCase { }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); - db.generateSubscriptions(contactId, subscriptionWriter); + db.generateSubscriptionUpdate(contactId, subscriptionWriter); context.assertIsSatisfied(); } @Test - public void testGenerateTransports() throws Exception { + public void testGenerateTransportUpdate() throws Exception { final MessageId messageId1 = new MessageId(TestUtils.getRandomId()); final Collection sendable = new ArrayList(); sendable.add(messageId); @@ -753,7 +753,7 @@ public abstract class DatabaseComponentTest extends TestCase { }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); - db.generateTransports(contactId, transportWriter); + db.generateTransportUpdate(contactId, transportWriter); context.assertIsSatisfied(); } @@ -982,14 +982,14 @@ public abstract class DatabaseComponentTest extends TestCase { } @Test - public void testReceiveSubscriptions() throws Exception { + public void testReceiveSubscriptionUpdate() throws Exception { final long timestamp = 1234L; Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); - final Subscriptions subscriptionsUpdate = - context.mock(Subscriptions.class); + final SubscriptionUpdate subscriptionUpdate = + context.mock(SubscriptionUpdate.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); @@ -997,28 +997,29 @@ public abstract class DatabaseComponentTest extends TestCase { allowing(database).containsContact(txn, contactId); will(returnValue(true)); // Get the contents of the update - oneOf(subscriptionsUpdate).getSubscriptions(); + oneOf(subscriptionUpdate).getSubscriptions(); will(returnValue(Collections.singletonList(group))); - oneOf(subscriptionsUpdate).getTimestamp(); + oneOf(subscriptionUpdate).getTimestamp(); will(returnValue(timestamp)); oneOf(database).setSubscriptions(txn, contactId, Collections.singletonList(group), timestamp); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); - db.receiveSubscriptions(contactId, subscriptionsUpdate); + db.receiveSubscriptionUpdate(contactId, subscriptionUpdate); context.assertIsSatisfied(); } @Test - public void testReceiveTransports() throws Exception { + public void testReceiveTransportUpdate() throws Exception { final long timestamp = 1234L; Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); - final Transports transportsUpdate = context.mock(Transports.class); + final TransportUpdate transportUpdate = + context.mock(TransportUpdate.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); @@ -1026,16 +1027,16 @@ public abstract class DatabaseComponentTest extends TestCase { allowing(database).containsContact(txn, contactId); will(returnValue(true)); // Get the contents of the update - oneOf(transportsUpdate).getTransports(); + oneOf(transportUpdate).getTransports(); will(returnValue(transports)); - oneOf(transportsUpdate).getTimestamp(); + oneOf(transportUpdate).getTimestamp(); will(returnValue(timestamp)); oneOf(database).setTransports(txn, contactId, transports, timestamp); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); - db.receiveTransports(contactId, transportsUpdate); + db.receiveTransportUpdate(contactId, transportUpdate); context.assertIsSatisfied(); } @@ -1103,7 +1104,12 @@ public abstract class DatabaseComponentTest extends TestCase { } @Test - public void testTransportsChangedCallsListeners() throws Exception { + public void testTransportPropertiesChangedCallsListeners() + throws Exception { + final Map properties = + Collections.singletonMap("bar", "baz"); + final Map properties1 = + Collections.singletonMap("baz", "bam"); Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database database = context.mock(Database.class); @@ -1113,9 +1119,8 @@ public abstract class DatabaseComponentTest extends TestCase { oneOf(database).startTransaction(); will(returnValue(txn)); oneOf(database).getTransports(txn); - will(returnValue(transports)); - oneOf(database).setTransports(txn, "bar", - Collections.singletonMap("baz", "bam")); + will(returnValue(Collections.singletonMap("foo", properties))); + oneOf(database).setTransportProperties(txn, "foo", properties1); oneOf(database).commitTransaction(txn); oneOf(listener).eventOccurred( DatabaseListener.Event.TRANSPORTS_UPDATED); @@ -1123,13 +1128,16 @@ public abstract class DatabaseComponentTest extends TestCase { DatabaseComponent db = createDatabaseComponent(database, cleaner); db.addListener(listener); - db.setTransports("bar", Collections.singletonMap("baz", "bam")); + db.setTransportProperties("foo", properties1); context.assertIsSatisfied(); } @Test - public void testTransportsUnchangedDoesNotCallListeners() throws Exception { + public void testTransportPropertiesUnchangedDoesNotCallListeners() + throws Exception { + final Map properties = + Collections.singletonMap("bar", "baz"); Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database database = context.mock(Database.class); @@ -1139,13 +1147,67 @@ public abstract class DatabaseComponentTest extends TestCase { oneOf(database).startTransaction(); will(returnValue(txn)); oneOf(database).getTransports(txn); - will(returnValue(transports)); + will(returnValue(Collections.singletonMap("foo", properties))); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); db.addListener(listener); - db.setTransports("foo", transports.get("foo")); + db.setTransportProperties("foo", properties); + + context.assertIsSatisfied(); + } + + @Test + public void testTransportConfigChangedCallsListeners() throws Exception { + final Map config = + Collections.singletonMap("bar", "baz"); + final Map config1 = + Collections.singletonMap("baz", "bam"); + Mockery context = new Mockery(); + @SuppressWarnings("unchecked") + final Database database = context.mock(Database.class); + final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); + final DatabaseListener listener = context.mock(DatabaseListener.class); + context.checking(new Expectations() {{ + oneOf(database).startTransaction(); + will(returnValue(txn)); + oneOf(database).getTransportConfig(txn, "foo"); + will(returnValue(config)); + oneOf(database).setTransportConfig(txn, "foo", config1); + oneOf(database).commitTransaction(txn); + oneOf(listener).eventOccurred( + DatabaseListener.Event.TRANSPORTS_UPDATED); + }}); + DatabaseComponent db = createDatabaseComponent(database, cleaner); + + db.addListener(listener); + db.setTransportConfig("foo", config1); + + context.assertIsSatisfied(); + } + + @Test + public void testTransportConfigUnchangedDoesNotCallListeners() + throws Exception { + final Map config = + Collections.singletonMap("bar", "baz"); + Mockery context = new Mockery(); + @SuppressWarnings("unchecked") + final Database database = context.mock(Database.class); + final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); + final DatabaseListener listener = context.mock(DatabaseListener.class); + context.checking(new Expectations() {{ + oneOf(database).startTransaction(); + will(returnValue(txn)); + oneOf(database).getTransportConfig(txn, "foo"); + will(returnValue(config)); + oneOf(database).commitTransaction(txn); + }}); + DatabaseComponent db = createDatabaseComponent(database, cleaner); + + db.addListener(listener); + db.setTransportConfig("foo", config); context.assertIsSatisfied(); } diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java index 7de9d7953..ef82cfc49 100644 --- a/test/net/sf/briar/db/H2DatabaseTest.java +++ b/test/net/sf/briar/db/H2DatabaseTest.java @@ -780,7 +780,7 @@ public class H2DatabaseTest extends TestCase { } @Test - public void testUpdateTransports() throws DbException { + public void testUpdateTransportPropertiess() throws DbException { Database db = open(false); Connection txn = db.startTransaction(); @@ -799,13 +799,14 @@ public class H2DatabaseTest extends TestCase { Collections.>emptyMap(), 2); assertEquals(Collections.emptyMap(), db.getTransports(txn, contactId)); // Set the local transport properties - for(String s : transports.keySet()) { - db.setTransports(txn, s, transports.get(s)); + for(String name : transports.keySet()) { + db.setTransportProperties(txn, name, transports.get(name)); } assertEquals(transports, db.getTransports(txn)); // Remove the local transport properties - for(String s : transports.keySet()) { - db.setTransports(txn, s, Collections.emptyMap()); + for(String name : transports.keySet()) { + db.setTransportProperties(txn, name, + Collections.emptyMap()); } assertEquals(Collections.emptyMap(), db.getTransports(txn)); @@ -813,6 +814,29 @@ public class H2DatabaseTest extends TestCase { db.close(); } + + @Test + public void testUpdateTransportConfig() throws DbException { + Map config = Collections.singletonMap("bar", "baz"); + Map config1 = Collections.singletonMap("baz", "bam"); + Database db = open(false); + Connection txn = db.startTransaction(); + + // Set the transport config + db.setTransportConfig(txn, "foo", config); + assertEquals(config, db.getTransportConfig(txn, "foo")); + // Update the transport config + db.setTransportConfig(txn, "foo", config1); + assertEquals(config1, db.getTransportConfig(txn, "foo")); + // Remove the transport config + db.setTransportConfig(txn, "foo", + Collections.emptyMap()); + assertEquals(Collections.emptyMap(), db.getTransportConfig(txn, "foo")); + + db.commitTransaction(txn); + db.close(); + } + @Test public void testTransportsNotUpdatedIfTimestampIsOld() throws DbException { Database db = open(false); diff --git a/test/net/sf/briar/protocol/FileReadWriteTest.java b/test/net/sf/briar/protocol/FileReadWriteTest.java index 52516a380..808a630e3 100644 --- a/test/net/sf/briar/protocol/FileReadWriteTest.java +++ b/test/net/sf/briar/protocol/FileReadWriteTest.java @@ -27,9 +27,9 @@ 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.Request; -import net.sf.briar.api.protocol.Subscriptions; +import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.Tags; -import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.protocol.TransportUpdate; import net.sf.briar.api.protocol.UniqueId; import net.sf.briar.api.protocol.writers.AckWriter; import net.sf.briar.api.protocol.writers.BatchWriter; @@ -217,10 +217,10 @@ public class FileReadWriteTest extends TestCase { // If there are any padding bits, they should all be zero assertEquals(2, requested.cardinality()); - // Read the subscriptions update + // Read the subscription update assertTrue(reader.hasUserDefined(Tags.SUBSCRIPTIONS)); - Subscriptions s = reader.readUserDefined(Tags.SUBSCRIPTIONS, - Subscriptions.class); + SubscriptionUpdate s = reader.readUserDefined(Tags.SUBSCRIPTIONS, + SubscriptionUpdate.class); Collection subs = s.getSubscriptions(); assertEquals(2, subs.size()); Iterator it2 = subs.iterator(); @@ -229,10 +229,10 @@ public class FileReadWriteTest extends TestCase { assertTrue(s.getTimestamp() > start); assertTrue(s.getTimestamp() <= System.currentTimeMillis()); - // Read the transports update + // Read the transport update assertTrue(reader.hasUserDefined(Tags.TRANSPORTS)); - Transports t = reader.readUserDefined(Tags.TRANSPORTS, - Transports.class); + TransportUpdate t = reader.readUserDefined(Tags.TRANSPORTS, + TransportUpdate.class); assertEquals(transports, t.getTransports()); assertTrue(t.getTimestamp() > start); assertTrue(t.getTimestamp() <= System.currentTimeMillis());