mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 12:49:55 +01:00
Metadata for groups. #221
This commit is contained in:
@@ -27,8 +27,6 @@ import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
// FIXME: Document the preconditions for calling each method
|
||||
|
||||
/**
|
||||
* A low-level interface to the database (DatabaseComponent provides a
|
||||
* high-level interface). Most operations take a transaction argument, which is
|
||||
@@ -275,6 +273,13 @@ interface Database<T> {
|
||||
*/
|
||||
Group getGroup(T txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the metadata for the given group.
|
||||
* <p>
|
||||
* Locking: read.
|
||||
*/
|
||||
Metadata getGroupMetadata(T txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all groups belonging to the given client to which the user
|
||||
* subscribes.
|
||||
@@ -515,6 +520,15 @@ interface Database<T> {
|
||||
void lowerRequestedFlag(T txn, ContactId c, Collection<MessageId> requested)
|
||||
throws DbException;
|
||||
|
||||
/*
|
||||
* Merges the given metadata with the existing metadata for the given
|
||||
* group.
|
||||
* <p>
|
||||
* Locking: write.
|
||||
*/
|
||||
void mergeGroupMetadata(T txn, GroupId g, Metadata meta)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Merges the given properties with the existing local properties for the
|
||||
* given transport.
|
||||
|
||||
@@ -607,6 +607,25 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public Metadata getGroupMetadata(GroupId g) throws DbException {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if (!db.containsGroup(txn, g))
|
||||
throw new NoSuchSubscriptionException();
|
||||
Metadata metadata = db.getGroupMetadata(txn, g);
|
||||
db.commitTransaction(txn);
|
||||
return metadata;
|
||||
} catch (DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Group> getGroups(ClientId c) throws DbException {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
@@ -954,6 +973,25 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeGroupMetadata(GroupId g, Metadata meta)
|
||||
throws DbException {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if (!db.containsGroup(txn, g))
|
||||
throw new NoSuchSubscriptionException();
|
||||
db.mergeGroupMetadata(txn, g, meta);
|
||||
db.commitTransaction(txn);
|
||||
} catch (DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeLocalProperties(TransportId t, TransportProperties p)
|
||||
throws DbException {
|
||||
boolean changed = false;
|
||||
|
||||
@@ -65,8 +65,8 @@ import static org.briarproject.db.ExponentialBackoff.calculateExpiry;
|
||||
*/
|
||||
abstract class JdbcDatabase implements Database<Connection> {
|
||||
|
||||
private static final int SCHEMA_VERSION = 16;
|
||||
private static final int MIN_SCHEMA_VERSION = 16;
|
||||
private static final int SCHEMA_VERSION = 17;
|
||||
private static final int MIN_SCHEMA_VERSION = 17;
|
||||
|
||||
private static final String CREATE_SETTINGS =
|
||||
"CREATE TABLE settings"
|
||||
@@ -107,6 +107,16 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
+ " visibleToAll BOOLEAN NOT NULL,"
|
||||
+ " PRIMARY KEY (groupId))";
|
||||
|
||||
private static final String CREATE_GROUP_METADATA =
|
||||
"CREATE TABLE groupMetadata"
|
||||
+ " (groupId HASH NOT NULL,"
|
||||
+ " key VARCHAR NOT NULL,"
|
||||
+ " value BINARY NOT NULL,"
|
||||
+ " PRIMARY KEY (groupId, key),"
|
||||
+ " FOREIGN KEY (groupId)"
|
||||
+ " REFERENCES groups (groupId)"
|
||||
+ " ON DELETE CASCADE)";
|
||||
|
||||
private static final String CREATE_GROUP_VISIBILITIES =
|
||||
"CREATE TABLE groupVisibilities"
|
||||
+ " (contactId INT NOT NULL,"
|
||||
@@ -386,6 +396,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
s.executeUpdate(insertTypeNames(CREATE_LOCAL_AUTHORS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_CONTACTS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_GROUPS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_GROUP_METADATA));
|
||||
s.executeUpdate(insertTypeNames(CREATE_GROUP_VISIBILITIES));
|
||||
s.executeUpdate(insertTypeNames(CREATE_CONTACT_GROUPS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_GROUP_VERSIONS));
|
||||
@@ -1496,16 +1507,25 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public Metadata getGroupMetadata(Connection txn, GroupId g)
|
||||
throws DbException {
|
||||
return getMetadata(txn, g.getBytes(), "groupMetadata", "groupId");
|
||||
}
|
||||
|
||||
public Metadata getMessageMetadata(Connection txn, MessageId m)
|
||||
throws DbException {
|
||||
return getMetadata(txn, m.getBytes(), "messageMetadata", "messageId");
|
||||
}
|
||||
|
||||
private Metadata getMetadata(Connection txn, byte[] id, String tableName,
|
||||
String columnName) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT key, value"
|
||||
+ " FROM messageMetadata"
|
||||
+ " WHERE messageId = ?";
|
||||
String sql = "SELECT key, value FROM " + tableName
|
||||
+ " WHERE " + columnName + " = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
ps.setBytes(1, id);
|
||||
rs = ps.executeQuery();
|
||||
Metadata metadata = new Metadata();
|
||||
while (rs.next()) metadata.put(rs.getString(1), rs.getBytes(2));
|
||||
@@ -2329,8 +2349,18 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeGroupMetadata(Connection txn, GroupId g, Metadata meta)
|
||||
throws DbException {
|
||||
mergeMetadata(txn, g.getBytes(), meta, "groupMetadata", "groupId");
|
||||
}
|
||||
|
||||
public void mergeMessageMetadata(Connection txn, MessageId m, Metadata meta)
|
||||
throws DbException {
|
||||
mergeMetadata(txn, m.getBytes(), meta, "messageMetadata", "messageId");
|
||||
}
|
||||
|
||||
private void mergeMetadata(Connection txn, byte[] id, Metadata meta,
|
||||
String tableName, String columnName) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
// Determine which keys are being removed
|
||||
@@ -2342,10 +2372,10 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
// Delete any keys that are being removed
|
||||
if (!removed.isEmpty()) {
|
||||
String sql = "DELETE FROM messageMetadata"
|
||||
+ " WHERE messageId = ? AND key = ?";
|
||||
String sql = "DELETE FROM " + tableName
|
||||
+ " WHERE " + columnName + " = ? AND key = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
ps.setBytes(1, id);
|
||||
for (String key : removed) {
|
||||
ps.setString(2, key);
|
||||
ps.addBatch();
|
||||
@@ -2361,10 +2391,10 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
if (retained.isEmpty()) return;
|
||||
// Update any keys that already exist
|
||||
String sql = "UPDATE messageMetadata SET value = ?"
|
||||
+ " WHERE messageId = ? AND key = ?";
|
||||
String sql = "UPDATE " + tableName + " SET value = ?"
|
||||
+ " WHERE " + columnName + " = ? AND key = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(2, m.getBytes());
|
||||
ps.setBytes(2, id);
|
||||
for (Entry<String, byte[]> e : retained.entrySet()) {
|
||||
ps.setBytes(1, e.getValue());
|
||||
ps.setString(3, e.getKey());
|
||||
@@ -2378,10 +2408,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
if (batchAffected[i] > 1) throw new DbStateException();
|
||||
}
|
||||
// Insert any keys that don't already exist
|
||||
sql = "INSERT INTO messageMetadata (messageId, key, value)"
|
||||
sql = "INSERT INTO " + tableName
|
||||
+ " (" + columnName + ", key, value)"
|
||||
+ " VALUES (?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, m.getBytes());
|
||||
ps.setBytes(1, id);
|
||||
int updateIndex = 0, inserted = 0;
|
||||
for (Entry<String, byte[]> e : retained.entrySet()) {
|
||||
if (batchAffected[updateIndex] == 0) {
|
||||
|
||||
@@ -83,8 +83,14 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
|
||||
db.addGroup(g);
|
||||
db.addContactGroup(c, g);
|
||||
db.setVisibility(g.getId(), Collections.singletonList(c));
|
||||
// Attach the contact ID to the group
|
||||
BdfDictionary d = new BdfDictionary();
|
||||
d.put("contactId", c.getInt());
|
||||
db.mergeGroupMetadata(g.getId(), metadataEncoder.encode(d));
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
} catch (FormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,18 +147,20 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
|
||||
Metadata meta = metadataEncoder.encode(d);
|
||||
db.addLocalMessage(m.getMessage(), CLIENT_ID, meta);
|
||||
} catch (FormatException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactId getContactId(GroupId g) throws DbException {
|
||||
// TODO: Use metadata to attach the contact ID to the group
|
||||
for (Contact c : db.getContacts()) {
|
||||
Group conversation = getConversationGroup(c);
|
||||
if (conversation.getId().equals(g)) return c.getId();
|
||||
try {
|
||||
BdfDictionary d = metadataParser.parse(db.getGroupMetadata(g));
|
||||
long id = d.getInteger("contactId");
|
||||
return new ContactId((int) id);
|
||||
} catch (FormatException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
throw new NoSuchContactException();
|
||||
}
|
||||
throw new NoSuchContactException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user