From b91fe66461f18ef5ee642c48ba5b58d2aa41193f Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jul 2020 11:38:55 +0100 Subject: [PATCH 1/5] Broadcast an event when remote transport properties are updated. --- .../TransportPropertyConstants.java | 11 +++ ...RemoteTransportPropertiesUpdatedEvent.java | 35 +++++++++ .../TransportPropertyManagerImpl.java | 47 +++++++++++- .../TransportPropertyManagerImplTest.java | 75 ++++++++++++++++++- 4 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/properties/event/RemoteTransportPropertiesUpdatedEvent.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java index 99f2fa798..3e6fe3865 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java @@ -35,4 +35,15 @@ public interface TransportPropertyConstants { * contact, as a BDF dictionary. */ String GROUP_KEY_DISCOVERED = "discovered"; + + /** + * Group metadata key for the contact's ID as a BDF long. + */ + String GROUP_KEY_CONTACT_ID = "contactId"; + + /** + * Group metadata key for the local group, indicating that contact IDs have + * been stored in the group metadata of contact groups. + */ + String GROUP_KEY_CONTACT_IDS_STORED = "contactIdsStored"; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/event/RemoteTransportPropertiesUpdatedEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/event/RemoteTransportPropertiesUpdatedEvent.java new file mode 100644 index 000000000..9d5c41954 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/event/RemoteTransportPropertiesUpdatedEvent.java @@ -0,0 +1,35 @@ +package org.briarproject.bramble.api.properties.event; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.properties.TransportProperties; + +import javax.annotation.concurrent.Immutable; + +/** + * An event that is broadcast when {@link TransportProperties} are received + * from a contact. + */ +@Immutable +@NotNullByDefault +public class RemoteTransportPropertiesUpdatedEvent extends Event { + + private final ContactId contactId; + private final TransportId transportId; + + public RemoteTransportPropertiesUpdatedEvent(ContactId contactId, + TransportId transportId) { + this.contactId = contactId; + this.transportId = transportId; + } + + public ContactId getContactId() { + return contactId; + } + + public TransportId getTransportId() { + return transportId; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java index f0bcde0e6..3ef9236fa 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java @@ -18,6 +18,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportPropertyManager; +import org.briarproject.bramble.api.properties.event.RemoteTransportPropertiesUpdatedEvent; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.Group.Visibility; import org.briarproject.bramble.api.sync.GroupId; @@ -37,6 +38,8 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_CONTACT_IDS_STORED; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_DISCOVERED; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_LOCAL; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_TRANSPORT_ID; @@ -74,7 +77,10 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, @Override public void onDatabaseOpened(Transaction txn) throws DbException { - if (db.containsGroup(txn, localGroup.getId())) return; + if (db.containsGroup(txn, localGroup.getId())) { + storeContactIdsForContactGroups(txn); + return; + } db.addGroup(txn, localGroup); // Set things up for any pre-existing contacts for (Contact c : db.getContacts(txn)) addingContact(txn, c); @@ -89,6 +95,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, Visibility client = clientVersioningManager.getClientVisibility(txn, c.getId(), CLIENT_ID, MAJOR_VERSION); db.setGroupVisibility(txn, c.getId(), g.getId(), client); + // Attach the contact ID to the group + storeContactId(txn, c, g); // Copy the latest local properties into the group Map local = getLocalProperties(txn); for (Entry e : local.entrySet()) { @@ -127,8 +135,11 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, // We've already received a newer update - delete this one db.deleteMessage(txn, m.getId()); db.deleteMessageMetadata(txn, m.getId()); + return false; } } + ContactId c = getContactId(txn, m.getGroupId()); + txn.attach(new RemoteTransportPropertiesUpdatedEvent(c, t)); } catch (FormatException e) { throw new InvalidMessageException(e); } @@ -224,6 +235,40 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, }); } + private void storeContactIdsForContactGroups(Transaction txn) + throws DbException { + try { + BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, + localGroup.getId()); + if (meta.containsKey(GROUP_KEY_CONTACT_IDS_STORED)) return; + for (Contact c : db.getContacts(txn)) { + storeContactId(txn, c, getContactGroup(c)); + } + meta.put(GROUP_KEY_CONTACT_IDS_STORED, true); + clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta); + } catch (FormatException e) { + throw new DbException(e); + } + } + + private void storeContactId(Transaction txn, Contact c, Group contactGroup) + throws DbException { + BdfDictionary meta = new BdfDictionary(); + meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); + try { + clientHelper.mergeGroupMetadata(txn, contactGroup.getId(), meta); + } catch (FormatException e) { + throw new AssertionError(e); + } + } + + private ContactId getContactId(Transaction txn, GroupId contactGroupId) + throws DbException, FormatException { + BdfDictionary meta = + clientHelper.getGroupMetadataAsDictionary(txn, contactGroupId); + return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); + } + private TransportProperties getRemoteProperties(Transaction txn, Contact c, TransportId t) throws DbException { Group g = getContactGroup(c); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java index 6b11df71e..4d3831fdc 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java @@ -32,6 +32,8 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_CONTACT_IDS_STORED; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_DISCOVERED; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_LOCAL; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_TRANSPORT_ID; @@ -94,6 +96,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); Contact contact = getContact(); Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + BdfDictionary contactGroupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) + ); context.checking(new Expectations() {{ oneOf(db).containsGroup(txn, localGroup.getId()); @@ -110,6 +115,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { will(returnValue(SHARED)); oneOf(db).setGroupVisibility(txn, contact.getId(), contactGroup.getId(), SHARED); + oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), + contactGroupMeta); }}); // Copy the latest local properties into the group expectGetLocalProperties(txn); @@ -123,13 +130,57 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { } @Test - public void testDoesNotCreateGroupsAtStartupIfAlreadyCreated() + public void testAddsContactIdsToGroupsAtStartupIfAlreadyCreated() throws Exception { Transaction txn = new Transaction(null, false); + Contact contact = getContact(); + Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + BdfDictionary contactGroupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) + ); + BdfDictionary localGroupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_IDS_STORED, true) + ); context.checking(new Expectations() {{ oneOf(db).containsGroup(txn, localGroup.getId()); will(returnValue(true)); + // Contact IDs have not been added to contact groups + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + localGroup.getId()); + will(returnValue(new BdfDictionary())); + // Add contact IDs to contact groups + oneOf(db).getContacts(txn); + will(returnValue(singletonList(contact))); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, + MAJOR_VERSION, contact); + will(returnValue(contactGroup)); + oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), + contactGroupMeta); + // Remember that contact IDs have been added + oneOf(clientHelper).mergeGroupMetadata(txn, localGroup.getId(), + localGroupMeta); + }}); + + TransportPropertyManagerImpl t = createInstance(); + t.onDatabaseOpened(txn); + } + + @Test + public void testDoesNotAddContactIdsToGroupsAtStartupIfAlreadyAdded() + throws Exception { + Transaction txn = new Transaction(null, false); + BdfDictionary localGroupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_IDS_STORED, true) + ); + + context.checking(new Expectations() {{ + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(true)); + // Contact IDs have already been added to contact groups + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + localGroup.getId()); + will(returnValue(localGroupMeta)); }}); TransportPropertyManagerImpl t = createInstance(); @@ -141,6 +192,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); Contact contact = getContact(); Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + BdfDictionary contactGroupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) + ); context.checking(new Expectations() {{ // Create the group and share it with the contact @@ -153,6 +207,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { will(returnValue(SHARED)); oneOf(db).setGroupVisibility(txn, contact.getId(), contactGroup.getId(), SHARED); + oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), + contactGroupMeta); }}); // Copy the latest local properties into the group expectGetLocalProperties(txn); @@ -186,7 +242,11 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { public void testDoesNotDeleteAnythingWhenFirstUpdateIsDelivered() throws Exception { Transaction txn = new Transaction(null, false); + Contact contact = getContact(); GroupId contactGroupId = new GroupId(getRandomId()); + BdfDictionary contactGroupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) + ); Message message = getMessage(contactGroupId); Metadata meta = new Metadata(); BdfDictionary metaDictionary = BdfDictionary.of( @@ -217,6 +277,10 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroupId); will(returnValue(messageMetadata)); + // Look up the contact ID to broadcast an event + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroupId); + will(returnValue(contactGroupMeta)); }}); TransportPropertyManagerImpl t = createInstance(); @@ -227,7 +291,11 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { public void testDeletesOlderUpdatesWhenUpdateIsDelivered() throws Exception { Transaction txn = new Transaction(null, false); + Contact contact = getContact(); GroupId contactGroupId = new GroupId(getRandomId()); + BdfDictionary contactGroupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) + ); Message message = getMessage(contactGroupId); Metadata meta = new Metadata(); // Version 4 is being delivered @@ -255,6 +323,10 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { // The previous update (version 3) should be deleted oneOf(db).deleteMessage(txn, fooVersion3); oneOf(db).deleteMessageMetadata(txn, fooVersion3); + // Look up the contact ID to broadcast an event + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroupId); + will(returnValue(contactGroupMeta)); }}); TransportPropertyManagerImpl t = createInstance(); @@ -292,6 +364,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { // The update being delivered (version 3) should be deleted oneOf(db).deleteMessage(txn, message.getId()); oneOf(db).deleteMessageMetadata(txn, message.getId()); + // No event should be broadcast }}); TransportPropertyManagerImpl t = createInstance(); From 90e91221d98ae60132602fe81959a675b47e53dd Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jul 2020 14:25:43 +0100 Subject: [PATCH 2/5] Reflect discovered properties back to the remote peer. --- .../TransportPropertyConstants.java | 5 + .../TransportPropertyManagerImpl.java | 81 ++++++++-- .../TransportPropertyManagerImplTest.java | 149 ++++++++++++++++-- 3 files changed, 207 insertions(+), 28 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java index 3e6fe3865..8fc77fae0 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java @@ -12,6 +12,11 @@ public interface TransportPropertyConstants { */ int MAX_PROPERTY_LENGTH = 100; + /** + * Prefix for keys that represent reflected properties. + */ + String REFLECTED_PROPERTY_PREFIX = "u:"; + /** * Message metadata key for the transport ID of a local or remote update, * as a BDF string. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java index 3ef9236fa..44f48911a 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java @@ -44,6 +44,7 @@ import static org.briarproject.bramble.api.properties.TransportPropertyConstants import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_LOCAL; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_TRANSPORT_ID; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_VERSION; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.REFLECTED_PROPERTY_PREFIX; @Immutable @NotNullByDefault @@ -162,15 +163,27 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, if (props.isEmpty()) return; try { db.transaction(false, txn -> { - Group g = getContactGroup(db.getContact(txn, c)); + Contact contact = db.getContact(txn, c); + Group g = getContactGroup(contact); BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary( txn, g.getId()); BdfDictionary discovered = meta.getOptionalDictionary(GROUP_KEY_DISCOVERED); - if (discovered == null) discovered = new BdfDictionary(); - discovered.putAll(props); - meta.put(GROUP_KEY_DISCOVERED, discovered); - clientHelper.mergeGroupMetadata(txn, g.getId(), meta); + BdfDictionary merged; + boolean changed; + if (discovered == null) { + merged = new BdfDictionary(props); + changed = true; + } else { + merged = new BdfDictionary(discovered); + merged.putAll(props); + changed = !merged.equals(discovered); + } + if (changed) { + meta.put(GROUP_KEY_DISCOVERED, merged); + clientHelper.mergeGroupMetadata(txn, g.getId(), meta); + updateLocalProperties(txn, contact, t); + } }); } catch (FormatException e) { throw new DbException(e); @@ -235,6 +248,24 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, }); } + private void updateLocalProperties(Transaction txn, Contact c, + TransportId t) throws DbException { + try { + TransportProperties local; + LatestUpdate latest = findLatest(txn, localGroup.getId(), t, true); + if (latest == null) { + local = new TransportProperties(); + } else { + BdfList message = clientHelper.getMessageAsList(txn, + latest.messageId); + local = parseProperties(message); + } + storeLocalProperties(txn, c, t, local); + } catch (FormatException e) { + throw new DbException(e); + } + } + private void storeContactIdsForContactGroups(Transaction txn) throws DbException { try { @@ -333,18 +364,10 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, storeMessage(txn, localGroup.getId(), t, merged, version, true, false); // Delete the previous update, if any - if (latest != null) - db.removeMessage(txn, latest.messageId); + if (latest != null) db.removeMessage(txn, latest.messageId); // Store the merged properties in each contact's group for (Contact c : db.getContacts(txn)) { - Group g = getContactGroup(c); - latest = findLatest(txn, g.getId(), t, true); - version = latest == null ? 1 : latest.version + 1; - storeMessage(txn, g.getId(), t, merged, version, - true, true); - // Delete the previous update, if any - if (latest != null) - db.removeMessage(txn, latest.messageId); + storeLocalProperties(txn, c, t, merged); } } }); @@ -353,6 +376,34 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, } } + private void storeLocalProperties(Transaction txn, Contact c, + TransportId t, TransportProperties p) + throws DbException, FormatException { + Group g = getContactGroup(c); + LatestUpdate latest = findLatest(txn, g.getId(), t, true); + long version = latest == null ? 1 : latest.version + 1; + // Reflect any remote properties we've discovered + BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, + g.getId()); + BdfDictionary discovered = + meta.getOptionalDictionary(GROUP_KEY_DISCOVERED); + TransportProperties combined; + if (discovered == null) { + combined = p; + } else { + combined = new TransportProperties(p); + TransportProperties d = clientHelper + .parseAndValidateTransportProperties(discovered); + for (Entry e : d.entrySet()) { + String key = REFLECTED_PROPERTY_PREFIX + e.getKey(); + combined.put(key, e.getValue()); + } + } + storeMessage(txn, g.getId(), t, combined, version, true, true); + // Delete the previous update, if any + if (latest != null) db.removeMessage(txn, latest.messageId); + } + private Group getContactGroup(Contact c) { return contactGroupFactory.createContactGroup(CLIENT_ID, MAJOR_VERSION, c); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java index 4d3831fdc..3a3e1c420 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java @@ -61,23 +61,28 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { private final Clock clock = context.mock(Clock.class); private final Group localGroup = getGroup(CLIENT_ID, MAJOR_VERSION); - private final BdfDictionary fooPropertiesDict = BdfDictionary.of( - new BdfEntry("fooKey1", "fooValue1"), - new BdfEntry("fooKey2", "fooValue2") - ); - private final BdfDictionary barPropertiesDict = BdfDictionary.of( - new BdfEntry("barKey1", "barValue1"), - new BdfEntry("barKey2", "barValue2") - ); + private final BdfDictionary fooPropertiesDict, barPropertiesDict; + private final BdfDictionary discoveredPropertiesDict, mergedPropertiesDict; private final TransportProperties fooProperties, barProperties; + private final TransportProperties discoveredProperties; - public TransportPropertyManagerImplTest() throws Exception { + public TransportPropertyManagerImplTest() { fooProperties = new TransportProperties(); - for (String key : fooPropertiesDict.keySet()) - fooProperties.put(key, fooPropertiesDict.getString(key)); + fooProperties.put("fooKey1", "fooValue1"); + fooProperties.put("fooKey2", "fooValue2"); + fooPropertiesDict = new BdfDictionary(fooProperties); + barProperties = new TransportProperties(); - for (String key : barPropertiesDict.keySet()) - barProperties.put(key, barPropertiesDict.getString(key)); + barProperties.put("barKey1", "barValue1"); + barProperties.put("barKey2", "barValue2"); + barPropertiesDict = new BdfDictionary(barProperties); + + discoveredProperties = new TransportProperties(); + discoveredProperties.put("fooKey3", "fooValue3"); + discoveredPropertiesDict = new BdfDictionary(discoveredProperties); + + mergedPropertiesDict = new BdfDictionary(fooProperties); + mergedPropertiesDict.put("u:fooKey3", "fooValue3"); } private TransportPropertyManagerImpl createInstance() { @@ -657,6 +662,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(emptyMap())); + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(new BdfDictionary())); expectStoreMessage(txn, contactGroup.getId(), "foo", fooPropertiesDict, 1, true, true); }}); @@ -665,6 +673,49 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { t.mergeLocalProperties(new TransportId("foo"), fooProperties); } + @Test + public void testMergingNewPropertiesCreatesUpdateWithReflectedProperties() + throws Exception { + Transaction txn = new Transaction(null, false); + Contact contact = getContact(); + Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + BdfDictionary contactGroupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_DISCOVERED, discoveredPropertiesDict) + ); + + context.checking(new DbExpectations() {{ + oneOf(db).transaction(with(false), withDbRunnable(txn)); + // There are no existing properties to merge with + oneOf(clientHelper).getMessageMetadataAsDictionary(txn, + localGroup.getId()); + will(returnValue(emptyMap())); + // Store the new properties in the local group, version 1 + expectStoreMessage(txn, localGroup.getId(), "foo", + fooPropertiesDict, 1, true, false); + // Store the new properties in each contact's group, version 1 + oneOf(db).getContacts(txn); + will(returnValue(singletonList(contact))); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, + MAJOR_VERSION, contact); + will(returnValue(contactGroup)); + oneOf(clientHelper).getMessageMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(emptyMap())); + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(contactGroupMeta)); + // Reflect discovered properties + oneOf(clientHelper).parseAndValidateTransportProperties( + discoveredPropertiesDict); + will(returnValue(discoveredProperties)); + expectStoreMessage(txn, contactGroup.getId(), "foo", + mergedPropertiesDict, 1, true, true); + }}); + + TransportPropertyManagerImpl t = createInstance(); + t.mergeLocalProperties(new TransportId("foo"), fooProperties); + } + @Test public void testMergingUpdatedPropertiesCreatesUpdate() throws Exception { Transaction txn = new Transaction(null, false); @@ -713,6 +764,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(contactGroupMessageMetadata)); + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(new BdfDictionary())); expectStoreMessage(txn, contactGroup.getId(), "foo", fooPropertiesDict, 2, true, true); // Delete the previous update @@ -723,6 +777,75 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { t.mergeLocalProperties(new TransportId("foo"), fooProperties); } + @Test + public void testMergingUpdatedPropertiesCreatesUpdateWithReflectedProperties() + throws Exception { + Transaction txn = new Transaction(null, false); + Contact contact = getContact(); + Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + BdfDictionary contactGroupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_DISCOVERED, discoveredPropertiesDict) + ); + BdfDictionary oldMetadata = BdfDictionary.of( + new BdfEntry(MSG_KEY_TRANSPORT_ID, "foo"), + new BdfEntry(MSG_KEY_VERSION, 1), + new BdfEntry(MSG_KEY_LOCAL, true) + ); + MessageId localGroupUpdateId = new MessageId(getRandomId()); + Map localGroupMessageMetadata = + singletonMap(localGroupUpdateId, oldMetadata); + MessageId contactGroupUpdateId = new MessageId(getRandomId()); + Map contactGroupMessageMetadata = + singletonMap(contactGroupUpdateId, oldMetadata); + TransportProperties oldProperties = new TransportProperties(); + oldProperties.put("fooKey1", "oldFooValue1"); + BdfDictionary oldPropertiesDict = BdfDictionary.of( + new BdfEntry("fooKey1", "oldFooValue1") + ); + BdfList oldUpdate = BdfList.of("foo", 1, oldPropertiesDict); + + context.checking(new DbExpectations() {{ + oneOf(db).transaction(with(false), withDbRunnable(txn)); + // Merge the new properties with the existing properties + oneOf(clientHelper).getMessageMetadataAsDictionary(txn, + localGroup.getId()); + will(returnValue(localGroupMessageMetadata)); + oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId); + will(returnValue(oldUpdate)); + oneOf(clientHelper).parseAndValidateTransportProperties( + oldPropertiesDict); + will(returnValue(oldProperties)); + // Store the merged properties in the local group, version 2 + expectStoreMessage(txn, localGroup.getId(), "foo", + fooPropertiesDict, 2, true, false); + // Delete the previous update + oneOf(db).removeMessage(txn, localGroupUpdateId); + // Store the merged properties in each contact's group, version 2 + oneOf(db).getContacts(txn); + will(returnValue(singletonList(contact))); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, + MAJOR_VERSION, contact); + will(returnValue(contactGroup)); + oneOf(clientHelper).getMessageMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(contactGroupMessageMetadata)); + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(contactGroupMeta)); + // Reflect discovered properties + oneOf(clientHelper).parseAndValidateTransportProperties( + discoveredPropertiesDict); + will(returnValue(discoveredProperties)); + expectStoreMessage(txn, contactGroup.getId(), "foo", + mergedPropertiesDict, 2, true, true); + // Delete the previous update + oneOf(db).removeMessage(txn, contactGroupUpdateId); + }}); + + TransportPropertyManagerImpl t = createInstance(); + t.mergeLocalProperties(new TransportId("foo"), fooProperties); + } + private void expectGetLocalProperties(Transaction txn) throws Exception { Map messageMetadata = new LinkedHashMap<>(); // The latest update for transport "foo" should be returned From 41fdd584ad547a706f6eba36bd0fb3a5521de56e Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 17 Jul 2020 17:37:22 +0100 Subject: [PATCH 3/5] Test whether event is attached to transaction. --- .../TransportPropertyManagerImplTest.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java index 3a3e1c420..a7eea0660 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java @@ -8,11 +8,15 @@ import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.MetadataParser; +import org.briarproject.bramble.api.db.CommitAction; import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.EventAction; import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.properties.event.RemoteTransportPropertiesUpdatedEvent; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; @@ -47,6 +51,7 @@ import static org.briarproject.bramble.test.TestUtils.getMessage; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class TransportPropertyManagerImplTest extends BrambleMockTestCase { @@ -290,6 +295,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { TransportPropertyManagerImpl t = createInstance(); assertFalse(t.incomingMessage(txn, message, meta)); + assertTrue(hasEvent(txn, RemoteTransportPropertiesUpdatedEvent.class)); } @Test @@ -336,6 +342,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { TransportPropertyManagerImpl t = createInstance(); assertFalse(t.incomingMessage(txn, message, meta)); + assertTrue(hasEvent(txn, RemoteTransportPropertiesUpdatedEvent.class)); } @Test @@ -374,6 +381,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { TransportPropertyManagerImpl t = createInstance(); assertFalse(t.incomingMessage(txn, message, meta)); + assertFalse(hasEvent(txn, RemoteTransportPropertiesUpdatedEvent.class)); } @Test @@ -903,4 +911,15 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { false); }}); } + + private boolean hasEvent(Transaction txn, + Class eventClass) { + for (CommitAction action : txn.getActions()) { + if (action instanceof EventAction) { + Event event = ((EventAction) action).getEvent(); + if (eventClass.isInstance(event)) return true; + } + } + return false; + } } From 2063f6c57cd870bdd2d55ade46265e199daa7f67 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 21 Jul 2020 17:04:14 +0100 Subject: [PATCH 4/5] Don't attach contact ID to RemoteTransportPropertiesUpdatedEvent. --- ...RemoteTransportPropertiesUpdatedEvent.java | 10 +-- .../TransportPropertyManagerImpl.java | 46 +----------- .../TransportPropertyManagerImplTest.java | 74 +------------------ 3 files changed, 4 insertions(+), 126 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/event/RemoteTransportPropertiesUpdatedEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/event/RemoteTransportPropertiesUpdatedEvent.java index 9d5c41954..89b7ec131 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/event/RemoteTransportPropertiesUpdatedEvent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/event/RemoteTransportPropertiesUpdatedEvent.java @@ -1,6 +1,5 @@ package org.briarproject.bramble.api.properties.event; -import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; @@ -16,19 +15,12 @@ import javax.annotation.concurrent.Immutable; @NotNullByDefault public class RemoteTransportPropertiesUpdatedEvent extends Event { - private final ContactId contactId; private final TransportId transportId; - public RemoteTransportPropertiesUpdatedEvent(ContactId contactId, - TransportId transportId) { - this.contactId = contactId; + public RemoteTransportPropertiesUpdatedEvent(TransportId transportId) { this.transportId = transportId; } - public ContactId getContactId() { - return contactId; - } - public TransportId getTransportId() { return transportId; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java index a4110a150..d5f2d4212 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java @@ -39,8 +39,6 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_CONTACT_ID; -import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_CONTACT_IDS_STORED; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_DISCOVERED; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_LOCAL; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_TRANSPORT_ID; @@ -80,10 +78,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, @Override public void onDatabaseOpened(Transaction txn) throws DbException { - if (db.containsGroup(txn, localGroup.getId())) { - storeContactIdsForContactGroups(txn); - return; - } + if (db.containsGroup(txn, localGroup.getId())) return; db.addGroup(txn, localGroup); // Set things up for any pre-existing contacts for (Contact c : db.getContacts(txn)) addingContact(txn, c); @@ -98,8 +93,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, Visibility client = clientVersioningManager.getClientVisibility(txn, c.getId(), CLIENT_ID, MAJOR_VERSION); db.setGroupVisibility(txn, c.getId(), g.getId(), client); - // Attach the contact ID to the group - storeContactId(txn, c, g); // Copy the latest local properties into the group Map local = getLocalProperties(txn); for (Entry e : local.entrySet()) { @@ -141,8 +134,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, return false; } } - ContactId c = getContactId(txn, m.getGroupId()); - txn.attach(new RemoteTransportPropertiesUpdatedEvent(c, t)); + txn.attach(new RemoteTransportPropertiesUpdatedEvent(t)); } catch (FormatException e) { throw new InvalidMessageException(e); } @@ -268,40 +260,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, } } - private void storeContactIdsForContactGroups(Transaction txn) - throws DbException { - try { - BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, - localGroup.getId()); - if (meta.containsKey(GROUP_KEY_CONTACT_IDS_STORED)) return; - for (Contact c : db.getContacts(txn)) { - storeContactId(txn, c, getContactGroup(c)); - } - meta.put(GROUP_KEY_CONTACT_IDS_STORED, true); - clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta); - } catch (FormatException e) { - throw new DbException(e); - } - } - - private void storeContactId(Transaction txn, Contact c, Group contactGroup) - throws DbException { - BdfDictionary meta = new BdfDictionary(); - meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); - try { - clientHelper.mergeGroupMetadata(txn, contactGroup.getId(), meta); - } catch (FormatException e) { - throw new AssertionError(e); - } - } - - private ContactId getContactId(Transaction txn, GroupId contactGroupId) - throws DbException, FormatException { - BdfDictionary meta = - clientHelper.getGroupMetadataAsDictionary(txn, contactGroupId); - return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); - } - private TransportProperties getRemoteProperties(Transaction txn, Contact c, TransportId t) throws DbException { Group g = getContactGroup(c); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java index 8adffa45a..9073917a2 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java @@ -36,8 +36,6 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; -import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_CONTACT_ID; -import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_CONTACT_IDS_STORED; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.GROUP_KEY_DISCOVERED; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_LOCAL; import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_TRANSPORT_ID; @@ -106,9 +104,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); Contact contact = getContact(); Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); - BdfDictionary contactGroupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) - ); context.checking(new Expectations() {{ oneOf(db).containsGroup(txn, localGroup.getId()); @@ -125,8 +120,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { will(returnValue(SHARED)); oneOf(db).setGroupVisibility(txn, contact.getId(), contactGroup.getId(), SHARED); - oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), - contactGroupMeta); }}); // Copy the latest local properties into the group expectGetLocalProperties(txn); @@ -140,57 +133,13 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { } @Test - public void testAddsContactIdsToGroupsAtStartupIfAlreadyCreated() + public void testDoesNotCreateGroupsAtStartupIfAlreadyCreated() throws Exception { Transaction txn = new Transaction(null, false); - Contact contact = getContact(); - Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); - BdfDictionary contactGroupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) - ); - BdfDictionary localGroupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_IDS_STORED, true) - ); context.checking(new Expectations() {{ oneOf(db).containsGroup(txn, localGroup.getId()); will(returnValue(true)); - // Contact IDs have not been added to contact groups - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - localGroup.getId()); - will(returnValue(new BdfDictionary())); - // Add contact IDs to contact groups - oneOf(db).getContacts(txn); - will(returnValue(singletonList(contact))); - oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, - MAJOR_VERSION, contact); - will(returnValue(contactGroup)); - oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), - contactGroupMeta); - // Remember that contact IDs have been added - oneOf(clientHelper).mergeGroupMetadata(txn, localGroup.getId(), - localGroupMeta); - }}); - - TransportPropertyManagerImpl t = createInstance(); - t.onDatabaseOpened(txn); - } - - @Test - public void testDoesNotAddContactIdsToGroupsAtStartupIfAlreadyAdded() - throws Exception { - Transaction txn = new Transaction(null, false); - BdfDictionary localGroupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_IDS_STORED, true) - ); - - context.checking(new Expectations() {{ - oneOf(db).containsGroup(txn, localGroup.getId()); - will(returnValue(true)); - // Contact IDs have already been added to contact groups - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - localGroup.getId()); - will(returnValue(localGroupMeta)); }}); TransportPropertyManagerImpl t = createInstance(); @@ -202,9 +151,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); Contact contact = getContact(); Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); - BdfDictionary contactGroupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) - ); context.checking(new Expectations() {{ // Create the group and share it with the contact @@ -217,8 +163,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { will(returnValue(SHARED)); oneOf(db).setGroupVisibility(txn, contact.getId(), contactGroup.getId(), SHARED); - oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), - contactGroupMeta); }}); // Copy the latest local properties into the group expectGetLocalProperties(txn); @@ -252,11 +196,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { public void testDoesNotDeleteAnythingWhenFirstUpdateIsDelivered() throws Exception { Transaction txn = new Transaction(null, false); - Contact contact = getContact(); GroupId contactGroupId = new GroupId(getRandomId()); - BdfDictionary contactGroupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) - ); Message message = getMessage(contactGroupId); Metadata meta = new Metadata(); BdfDictionary metaDictionary = BdfDictionary.of( @@ -287,10 +227,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroupId); will(returnValue(messageMetadata)); - // Look up the contact ID to broadcast an event - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - contactGroupId); - will(returnValue(contactGroupMeta)); }}); TransportPropertyManagerImpl t = createInstance(); @@ -302,11 +238,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { public void testDeletesOlderUpdatesWhenUpdateIsDelivered() throws Exception { Transaction txn = new Transaction(null, false); - Contact contact = getContact(); GroupId contactGroupId = new GroupId(getRandomId()); - BdfDictionary contactGroupMeta = BdfDictionary.of( - new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()) - ); Message message = getMessage(contactGroupId); Metadata meta = new Metadata(); // Version 4 is being delivered @@ -334,10 +266,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { // The previous update (version 3) should be deleted oneOf(db).deleteMessage(txn, fooVersion3); oneOf(db).deleteMessageMetadata(txn, fooVersion3); - // Look up the contact ID to broadcast an event - oneOf(clientHelper).getGroupMetadataAsDictionary(txn, - contactGroupId); - will(returnValue(contactGroupMeta)); }}); TransportPropertyManagerImpl t = createInstance(); From f4e9e102452ea4b1b7d07b5a09e8c4ce2b561711 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 21 Jul 2020 17:07:37 +0100 Subject: [PATCH 5/5] Remove unused constants. --- .../api/properties/TransportPropertyConstants.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java index 8fc77fae0..0d46964d6 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/properties/TransportPropertyConstants.java @@ -40,15 +40,4 @@ public interface TransportPropertyConstants { * contact, as a BDF dictionary. */ String GROUP_KEY_DISCOVERED = "discovered"; - - /** - * Group metadata key for the contact's ID as a BDF long. - */ - String GROUP_KEY_CONTACT_ID = "contactId"; - - /** - * Group metadata key for the local group, indicating that contact IDs have - * been stored in the group metadata of contact groups. - */ - String GROUP_KEY_CONTACT_IDS_STORED = "contactIdsStored"; }