diff --git a/briar-android/src/org/briarproject/android/AndroidModule.java b/briar-android/src/org/briarproject/android/AndroidModule.java index d3a7d8a4d53d10897cf3b2b61c64c948e71f6318..9dc8fcd884407be47ab952554fb917fbd062251a 100644 --- a/briar-android/src/org/briarproject/android/AndroidModule.java +++ b/briar-android/src/org/briarproject/android/AndroidModule.java @@ -93,10 +93,8 @@ public class AndroidModule { AndroidNotificationManager provideAndroidNotificationManager( LifecycleManager lifecycleManager, EventBus eventBus, AndroidNotificationManagerImpl notificationManager) { - lifecycleManager.register(notificationManager); + lifecycleManager.registerService(notificationManager); eventBus.addListener(notificationManager); - return notificationManager; } - } diff --git a/briar-api/src/org/briarproject/api/clients/Client.java b/briar-api/src/org/briarproject/api/clients/Client.java new file mode 100644 index 0000000000000000000000000000000000000000..28954c238a7768e0c2b8109d1c5f5fa0f5036703 --- /dev/null +++ b/briar-api/src/org/briarproject/api/clients/Client.java @@ -0,0 +1,12 @@ +package org.briarproject.api.clients; + +import org.briarproject.api.db.DbException; +import org.briarproject.api.db.Transaction; + +public interface Client { + + /** + * Called at startup to create any local state needed by the client. + */ + void createLocalState(Transaction txn) throws DbException; +} diff --git a/briar-api/src/org/briarproject/api/clients/PrivateGroupFactory.java b/briar-api/src/org/briarproject/api/clients/PrivateGroupFactory.java index 3a87775724028aade1cf68ed3ffa732099c042ec..01e26801721428e8b75c7f9d53512590bbbf9f56 100644 --- a/briar-api/src/org/briarproject/api/clients/PrivateGroupFactory.java +++ b/briar-api/src/org/briarproject/api/clients/PrivateGroupFactory.java @@ -6,6 +6,9 @@ import org.briarproject.api.sync.Group; public interface PrivateGroupFactory { + /** Creates a group that is not shared with any contacts. */ + Group createLocalGroup(ClientId clientId); + /** Creates a group for the given client to share with the given contact. */ Group createPrivateGroup(ClientId clientId, Contact contact); } diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java index a360fa98b61bb104e754a7bd42c6463a8e0918e0..2a627fb8a222329fc173529653c151aad6616927 100644 --- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java +++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java @@ -44,6 +44,7 @@ public interface DatabaseComponent { * <p/> * This method acquires locks, so it must not be called while holding a * lock. + * * @param readOnly true if the transaction will only be used for reading. */ Transaction startTransaction(boolean readOnly) throws DbException; @@ -90,13 +91,27 @@ public interface DatabaseComponent { void addTransportKeys(Transaction txn, ContactId c, TransportKeys k) throws DbException; + /** + * Returns true if the database contains the given contact for the given + * local pseudonym. + */ + boolean containsContact(Transaction txn, AuthorId remote, AuthorId local) + throws DbException; + + /** + * Returns true if the database contains the given group. + */ + boolean containsGroup(Transaction txn, GroupId g) throws DbException; + /** * Deletes the message with the given ID. The message ID and any other * associated data are not deleted. */ void deleteMessage(Transaction txn, MessageId m) throws DbException; - /** Deletes any metadata associated with the given message. */ + /** + * Deletes any metadata associated with the given message. + */ void deleteMessageMetadata(Transaction txn, MessageId m) throws DbException; /** @@ -162,13 +177,6 @@ public interface DatabaseComponent { Collection<ContactId> getContacts(Transaction txn, AuthorId a) throws DbException; - /** - * Returns true if the database contains the given contact for the given - * local pseudonym. - */ - boolean containsContact(Transaction txn, AuthorId remote, AuthorId local) - throws DbException; - /** * Returns the unique ID for this device. * <p/> @@ -359,7 +367,7 @@ public interface DatabaseComponent { * Marks the given contact as active or inactive. */ void setContactActive(Transaction txn, ContactId c, boolean active) - throws DbException; + throws DbException; /** * Marks the given message as shared or unshared. diff --git a/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java b/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java index 5f75237c25e080ed40cdfc0614cdb4107d345fe9..536c9c30937266cc17409218217b0ff4ed3bbff9 100644 --- a/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java +++ b/briar-api/src/org/briarproject/api/lifecycle/LifecycleManager.java @@ -1,32 +1,49 @@ package org.briarproject.api.lifecycle; +import org.briarproject.api.clients.Client; + import java.util.concurrent.ExecutorService; /** - * Manages the lifecycle of the app, starting and stopping {@link Service - * Services}, shutting down {@link java.util.concurrent.ExecutorService + * Manages the lifecycle of the app, starting {@link + * org.briarproject.api.clients.Client Clients}, starting and stopping {@link + * Service Services}, shutting down {@link java.util.concurrent.ExecutorService * ExecutorServices}, and opening and closing the {@link * org.briarproject.api.db.DatabaseComponent DatabaseComponent}. */ public interface LifecycleManager { - /** The result of calling {@link LifecycleManager#startServices()}. */ - enum StartResult { ALREADY_RUNNING, DB_ERROR, SERVICE_ERROR, SUCCESS } + /** + * The result of calling {@link LifecycleManager#startServices()}. + */ + enum StartResult { + ALREADY_RUNNING, DB_ERROR, SERVICE_ERROR, SUCCESS + } + + /** + * Registers a {@link Service} to be started and stopped. + */ + void registerService(Service s); - /** Registers a {@link Service} to be started and stopped. */ - public void register(Service s); + /** + * Registers a {@link org.briarproject.api.clients.Client Client} to be + * started. + */ + void registerClient(Client c); /** * Registers an {@link java.util.concurrent.ExecutorService ExecutorService} * to be shut down. */ - public void registerForShutdown(ExecutorService e); + void registerForShutdown(ExecutorService e); /** - * Starts any registered {@link Service Services} and opens the {@link - * org.briarproject.api.db.DatabaseComponent DatabaseComponent}. + * Opens the {@link org.briarproject.api.db.DatabaseComponent + * DatabaseComponent} and starts any registered {@link + * org.briarproject.api.clients.Client Clients} and {@link Service + * Services}. */ - public StartResult startServices(); + StartResult startServices(); /** * Stops any registered {@link Service Services}, shuts down any @@ -34,20 +51,21 @@ public interface LifecycleManager { * and closes the {@link org.briarproject.api.db.DatabaseComponent * DatabaseComponent}. */ - public void stopServices(); + void stopServices(); /** * Waits for the {@link org.briarproject.api.db.DatabaseComponent * DatabaseComponent} to be opened before returning. */ - public void waitForDatabase() throws InterruptedException; + void waitForDatabase() throws InterruptedException; /** * Waits for the {@link org.briarproject.api.db.DatabaseComponent - * DatabaseComponent} to be opened and all registered {@link Service + * DatabaseComponent} to be opened and all registered {@link + * org.briarproject.api.clients.Client Clients} and {@link Service * Services} to start before returning. */ - public void waitForStartup() throws InterruptedException; + void waitForStartup() throws InterruptedException; /** * Waits for all registered {@link Service Services} to stop, all @@ -55,5 +73,5 @@ public interface LifecycleManager { * to shut down, and the {@link org.briarproject.api.db.DatabaseComponent * DatabaseComponent} to be closed before returning. */ - public void waitForShutdown() throws InterruptedException; + void waitForShutdown() throws InterruptedException; } \ No newline at end of file diff --git a/briar-core/src/org/briarproject/clients/PrivateGroupFactoryImpl.java b/briar-core/src/org/briarproject/clients/PrivateGroupFactoryImpl.java index bb0ede9441d3df0d73d33a3eaedd0caf53f313ff..56ed9f5300917b20a23c348c7da01467275df80d 100644 --- a/briar-core/src/org/briarproject/clients/PrivateGroupFactoryImpl.java +++ b/briar-core/src/org/briarproject/clients/PrivateGroupFactoryImpl.java @@ -16,6 +16,8 @@ import javax.inject.Inject; class PrivateGroupFactoryImpl implements PrivateGroupFactory { + private static final byte[] LOCAL_GROUP_DESCRIPTOR = new byte[0]; + private final GroupFactory groupFactory; private final ClientHelper clientHelper; @@ -26,6 +28,11 @@ class PrivateGroupFactoryImpl implements PrivateGroupFactory { this.clientHelper = clientHelper; } + @Override + public Group createLocalGroup(ClientId clientId) { + return groupFactory.createGroup(clientId, LOCAL_GROUP_DESCRIPTOR); + } + @Override public Group createPrivateGroup(ClientId clientId, Contact contact) { AuthorId local = contact.getLocalAuthorId(); diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java index d3e48748c6dea3c2fb745476cf30f9f470be8f5d..6617823aa8e6ba25eb42aee3b0f75e9996961395 100644 --- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java +++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java @@ -228,6 +228,20 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { db.addTransportKeys(txn, c, k); } + public boolean containsContact(Transaction transaction, AuthorId remote, + AuthorId local) throws DbException { + T txn = unbox(transaction); + if (!db.containsLocalAuthor(txn, local)) + throw new NoSuchLocalAuthorException(); + return db.containsContact(txn, remote, local); + } + + public boolean containsGroup(Transaction transaction, GroupId g) + throws DbException { + T txn = unbox(transaction); + return db.containsGroup(txn, g); + } + public void deleteMessage(Transaction transaction, MessageId m) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); @@ -342,14 +356,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { return db.getContacts(txn, a); } - public boolean containsContact(Transaction transaction, AuthorId remote, - AuthorId local) throws DbException { - T txn = unbox(transaction); - if (!db.containsLocalAuthor(txn, local)) - throw new NoSuchLocalAuthorException(); - return db.containsContact(txn, remote, local); - } - public DeviceId getDeviceId(Transaction transaction) throws DbException { T txn = unbox(transaction); return db.getDeviceId(txn); diff --git a/briar-core/src/org/briarproject/forum/ForumModule.java b/briar-core/src/org/briarproject/forum/ForumModule.java index 4a51872e7abc05aed8f2cdbfb59a6ecda10eca7d..f801e2770cf200a7fb0f1997d4dea5470a2cdec0 100644 --- a/briar-core/src/org/briarproject/forum/ForumModule.java +++ b/briar-core/src/org/briarproject/forum/ForumModule.java @@ -3,14 +3,13 @@ package org.briarproject.forum; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.data.BdfReaderFactory; import org.briarproject.api.data.MetadataEncoder; -import org.briarproject.api.data.MetadataParser; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumPostFactory; import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.identity.AuthorFactory; +import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.sync.ValidationManager; import org.briarproject.api.system.Clock; @@ -73,9 +72,11 @@ public class ForumModule { @Provides @Singleton ForumSharingManager provideForumSharingManager( + LifecycleManager lifecycleManager, ContactManager contactManager, ValidationManager validationManager, ForumSharingManagerImpl forumSharingManager) { + lifecycleManager.registerClient(forumSharingManager); contactManager.registerAddContactHook(forumSharingManager); contactManager.registerRemoveContactHook(forumSharingManager); validationManager.registerIncomingMessageHook( diff --git a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java index c30834e8f6b0a570644533b7bbd0e3b47b5a8fda..b975a4537790396f2e5ad6a5dc5b3d074d9a5f97 100644 --- a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java +++ b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java @@ -1,6 +1,7 @@ package org.briarproject.forum; import org.briarproject.api.FormatException; +import org.briarproject.api.clients.Client; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.PrivateGroupFactory; import org.briarproject.api.contact.Contact; @@ -43,15 +44,13 @@ import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH; import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH; import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; -class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, - RemoveContactHook, IncomingMessageHook { +class ForumSharingManagerImpl implements ForumSharingManager, Client, + AddContactHook, RemoveContactHook, IncomingMessageHook { static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( "cd11a5d04dccd9e2931d6fc3df456313" + "63bb3e9d9d0e9405fccdb051f41f5449")); - private static final byte[] LOCAL_GROUP_DESCRIPTOR = new byte[0]; - private final DatabaseComponent db; private final ForumManager forumManager; private final ClientHelper clientHelper; @@ -73,8 +72,14 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, this.privateGroupFactory = privateGroupFactory; this.random = random; this.clock = clock; - localGroup = groupFactory.createGroup(CLIENT_ID, - LOCAL_GROUP_DESCRIPTOR); + localGroup = privateGroupFactory.createLocalGroup(CLIENT_ID); + } + + @Override + public void createLocalState(Transaction txn) throws DbException { + db.addGroup(txn, localGroup); + // Ensure we've set things up for any pre-existing contacts + for (Contact c : db.getContacts(txn)) addingContact(txn, c); } @Override @@ -82,6 +87,8 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, try { // Create a group to share with the contact Group g = getContactGroup(c); + // Return if we've already set things up for this contact + if (db.containsGroup(txn, g.getId())) return; // Store the group and share it with the contact db.addGroup(txn, g); db.setVisibleToContact(txn, c.getId(), g.getId(), true); @@ -297,8 +304,6 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, private List<Forum> getForumsSharedWithAllContacts(Transaction txn) throws DbException, FormatException { - // Ensure the local group exists - db.addGroup(txn, localGroup); // Find the latest update in the local group LatestUpdate latest = findLatest(txn, localGroup.getId(), true); if (latest == null) return Collections.emptyList(); diff --git a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java index a01c62b1010fc5b6b964e4d8471faca613bb6a72..e28af29e4d1c0ffbc886e342739d6afc977d3b98 100644 --- a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java +++ b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java @@ -1,6 +1,7 @@ package org.briarproject.introduction; import org.briarproject.api.FormatException; +import org.briarproject.api.clients.Client; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.PrivateGroupFactory; @@ -31,7 +32,6 @@ import org.briarproject.api.introduction.SessionId; import org.briarproject.api.properties.TransportPropertyManager; import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.Group; -import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.Message; import org.briarproject.api.sync.MessageId; @@ -82,14 +82,13 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUE import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE; class IntroductionManagerImpl extends BdfIncomingMessageHook - implements IntroductionManager, AddContactHook, RemoveContactHook { + implements IntroductionManager, Client, AddContactHook, + RemoveContactHook { static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( "23b1897c198a90ae75b976ac023d0f32" + "80ca67b12f2346b2c23a34f34e2434c3")); - private static final byte[] LOCAL_GROUP_DESCRIPTOR = new byte[0]; - private static final Logger LOG = Logger.getLogger(IntroductionManagerImpl.class.getName()); @@ -104,8 +103,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook @Inject IntroductionManagerImpl(DatabaseComponent db, MessageQueueManager messageQueueManager, - ClientHelper clientHelper, GroupFactory groupFactory, - PrivateGroupFactory privateGroupFactory, + ClientHelper clientHelper, PrivateGroupFactory privateGroupFactory, MetadataEncoder metadataEncoder, MetadataParser metadataParser, CryptoComponent cryptoComponent, TransportPropertyManager transportPropertyManager, @@ -117,6 +115,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook this.messageQueueManager = messageQueueManager; this.privateGroupFactory = privateGroupFactory; this.metadataEncoder = metadataEncoder; + // TODO: Inject these dependencies for easier testing this.introducerManager = new IntroducerManager(this, clientHelper, clock, cryptoComponent); @@ -124,8 +123,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook new IntroduceeManager(db, this, clientHelper, clock, cryptoComponent, transportPropertyManager, authorFactory, contactManager); - localGroup = - groupFactory.createGroup(CLIENT_ID, LOCAL_GROUP_DESCRIPTOR); + localGroup = privateGroupFactory.createLocalGroup(CLIENT_ID); } @Override @@ -133,11 +131,21 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook return CLIENT_ID; } + @Override + public void createLocalState(Transaction txn) throws DbException { + db.addGroup(txn, localGroup); + // Ensure we've set things up for any pre-existing contacts + for (Contact c : db.getContacts(txn)) addingContact(txn, c); + } + @Override public void addingContact(Transaction txn, Contact c) throws DbException { try { - // create an introduction group for sending introduction messages + // Create an introduction group for sending introduction messages Group g = getIntroductionGroup(c); + // Return if we've already set things up for this contact + if (db.containsGroup(txn, g.getId())) return; + // Store the group and share it with the contact db.addGroup(txn, g); db.setVisibleToContact(txn, c.getId(), g.getId(), true); // Attach the contact ID to the group @@ -169,7 +177,6 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook introducerManager.abort(txn, d); } } - } } catch (FormatException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -189,9 +196,6 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook protected void incomingMessage(Transaction txn, Message m, BdfList body, BdfDictionary message) throws DbException { - // add local group for engine states to make sure it exists - db.addGroup(txn, localGroup); - // Get message data and type GroupId groupId = m.getGroupId(); message.put(GROUP_ID, groupId); @@ -265,15 +269,13 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook public void makeIntroduction(Contact c1, Contact c2, String msg) throws DbException, FormatException { - Transaction txn = db.startTransaction(false); - try { - // add local group for session states to make sure it exists - db.addGroup(txn, getLocalGroup()); - introducerManager.makeIntroduction(txn, c1, c2, msg); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } + Transaction txn = db.startTransaction(false); + try { + introducerManager.makeIntroduction(txn, c1, c2, msg); + txn.setComplete(); + } finally { + db.endTransaction(txn); + } } @Override @@ -468,7 +470,7 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook } if (LOG.isLoggable(WARNING)) { LOG.warning( - "No session state found for this message with session ID " + + "No session state found for message with session ID " + Arrays.hashCode(sessionId)); } throw new FormatException(); @@ -505,5 +507,4 @@ class IntroductionManagerImpl extends BdfIncomingMessageHook db.deleteMessage(txn, messageId); db.deleteMessageMetadata(txn, messageId); } - } diff --git a/briar-core/src/org/briarproject/introduction/IntroductionModule.java b/briar-core/src/org/briarproject/introduction/IntroductionModule.java index 686a34edadb0d4451cc4162bcf79bac33345581b..4fb0e493df2349fbe75da4acbe4a25f5932e18ea 100644 --- a/briar-core/src/org/briarproject/introduction/IntroductionModule.java +++ b/briar-core/src/org/briarproject/introduction/IntroductionModule.java @@ -5,6 +5,7 @@ import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.introduction.IntroductionManager; +import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.system.Clock; import javax.inject.Inject; @@ -41,15 +42,17 @@ public class IntroductionModule { @Provides @Singleton IntroductionManager getIntroductionManager( + LifecycleManager lifecycleManager, ContactManager contactManager, MessageQueueManager messageQueueManager, IntroductionManagerImpl introductionManager) { + lifecycleManager.registerClient(introductionManager); contactManager.registerAddContactHook(introductionManager); contactManager.registerRemoveContactHook(introductionManager); - messageQueueManager - .registerIncomingMessageHook(introductionManager.getClientId(), - introductionManager); + messageQueueManager.registerIncomingMessageHook( + introductionManager.getClientId(), + introductionManager); return introductionManager; } diff --git a/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java b/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java index f153a3a37714ca1ae8c7935fa12c2d9d950138ea..bd2d31765cf4f228e15875bc08b7ec9b0e0f429c 100644 --- a/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java +++ b/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java @@ -1,14 +1,16 @@ package org.briarproject.lifecycle; +import org.briarproject.api.clients.Client; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; +import org.briarproject.api.db.Transaction; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.ShutdownEvent; import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.Service; import java.io.IOException; -import java.util.Collection; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -31,8 +33,9 @@ class LifecycleManagerImpl implements LifecycleManager { private final DatabaseComponent db; private final EventBus eventBus; - private final Collection<Service> services; - private final Collection<ExecutorService> executors; + private final List<Service> services; + private final List<Client> clients; + private final List<ExecutorService> executors; private final Semaphore startStopSemaphore = new Semaphore(1); private final CountDownLatch dbLatch = new CountDownLatch(1); private final CountDownLatch startupLatch = new CountDownLatch(1); @@ -43,15 +46,22 @@ class LifecycleManagerImpl implements LifecycleManager { this.db = db; this.eventBus = eventBus; services = new CopyOnWriteArrayList<Service>(); + clients = new CopyOnWriteArrayList<Client>(); executors = new CopyOnWriteArrayList<ExecutorService>(); } - public void register(Service s) { + public void registerService(Service s) { if (LOG.isLoggable(INFO)) LOG.info("Registering service " + s.getClass().getName()); services.add(s); } + public void registerClient(Client c) { + if (LOG.isLoggable(INFO)) + LOG.info("Registering client " + c.getClass().getName()); + clients.add(c); + } + public void registerForShutdown(ExecutorService e) { if (LOG.isLoggable(INFO)) LOG.info("Registering executor " + e.getClass().getName()); @@ -74,15 +84,28 @@ class LifecycleManagerImpl implements LifecycleManager { else LOG.info("Creating database took " + duration + " ms"); } dbLatch.countDown(); + Transaction txn = db.startTransaction(false); + try { + for (Client c : clients) { + start = System.currentTimeMillis(); + c.createLocalState(txn); + duration = System.currentTimeMillis() - start; + if (LOG.isLoggable(INFO)) { + LOG.info("Starting " + c.getClass().getName() + + " took " + duration + " ms"); + } + } + txn.setComplete(); + } finally { + db.endTransaction(txn); + } for (Service s : services) { start = System.currentTimeMillis(); boolean started = s.start(); duration = System.currentTimeMillis() - start; if (!started) { - if (LOG.isLoggable(WARNING)) { - String name = s.getClass().getName(); - LOG.warning(name + " did not start"); - } + if (LOG.isLoggable(WARNING)) + LOG.warning(s.getClass().getName() + " did not start"); return SERVICE_ERROR; } if (LOG.isLoggable(INFO)) { diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java index e7e64552f5c3a6d42f6b8ec2123c2edf03ebfe1b..93a0cc979cfbab9f5296d95158555132d28c650d 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java +++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java @@ -1,6 +1,7 @@ package org.briarproject.messaging; import org.briarproject.api.FormatException; +import org.briarproject.api.clients.Client; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.PrivateGroupFactory; import org.briarproject.api.contact.Contact; @@ -28,7 +29,7 @@ import java.util.Map; import javax.inject.Inject; -class MessagingManagerImpl implements MessagingManager, AddContactHook, +class MessagingManagerImpl implements MessagingManager, Client, AddContactHook, RemoveContactHook { static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( @@ -47,11 +48,19 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook, this.privateGroupFactory = privateGroupFactory; } + @Override + public void createLocalState(Transaction txn) throws DbException { + // Ensure we've set things up for any pre-existing contacts + for (Contact c : db.getContacts(txn)) addingContact(txn, c); + } + @Override public void addingContact(Transaction txn, Contact c) throws DbException { try { // Create a group to share with the contact Group g = getContactGroup(c); + // Return if we've already set things up for this contact + if (db.containsGroup(txn, g.getId())) return; // Store the group and share it with the contact db.addGroup(txn, g); db.setVisibleToContact(txn, c.getId(), g.getId(), true); diff --git a/briar-core/src/org/briarproject/messaging/MessagingModule.java b/briar-core/src/org/briarproject/messaging/MessagingModule.java index b943a6921d87c689ed83ac44dbf36424e9338207..8fec2d9b6c10b24a9adc0c6398d27555a3a59324 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingModule.java +++ b/briar-core/src/org/briarproject/messaging/MessagingModule.java @@ -3,6 +3,7 @@ package org.briarproject.messaging; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.data.MetadataEncoder; +import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.messaging.MessagingManager; import org.briarproject.api.messaging.PrivateMessageFactory; import org.briarproject.api.sync.ValidationManager; @@ -43,8 +44,10 @@ public class MessagingModule { @Provides @Singleton - MessagingManager getMessagingManager(ContactManager contactManager, + MessagingManager getMessagingManager(LifecycleManager lifecycleManager, + ContactManager contactManager, MessagingManagerImpl messagingManager) { + lifecycleManager.registerClient(messagingManager); contactManager.registerAddContactHook(messagingManager); contactManager.registerRemoveContactHook(messagingManager); return messagingManager; diff --git a/briar-core/src/org/briarproject/plugins/PluginsModule.java b/briar-core/src/org/briarproject/plugins/PluginsModule.java index d106d8920f549b308a30006094e01818ec8e1313..41294866593643833f27c5c9f69fa3218f28fa0d 100644 --- a/briar-core/src/org/briarproject/plugins/PluginsModule.java +++ b/briar-core/src/org/briarproject/plugins/PluginsModule.java @@ -64,7 +64,7 @@ public class PluginsModule { @Singleton PluginManager getPluginManager(LifecycleManager lifecycleManager, PluginManagerImpl pluginManager) { - lifecycleManager.register(pluginManager); + lifecycleManager.registerService(pluginManager); return pluginManager; } } diff --git a/briar-core/src/org/briarproject/properties/PropertiesModule.java b/briar-core/src/org/briarproject/properties/PropertiesModule.java index e9f2fcf5801726e72acd6ea8c815be42c68cf738..cea2c7504e7a563856d6c7257da8e0c329e3dd29 100644 --- a/briar-core/src/org/briarproject/properties/PropertiesModule.java +++ b/briar-core/src/org/briarproject/properties/PropertiesModule.java @@ -3,6 +3,7 @@ package org.briarproject.properties; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.data.MetadataEncoder; +import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.properties.TransportPropertyManager; import org.briarproject.api.sync.ValidationManager; import org.briarproject.api.system.Clock; @@ -36,8 +37,10 @@ public class PropertiesModule { @Provides @Singleton TransportPropertyManager getTransportPropertyManager( + LifecycleManager lifecycleManager, ContactManager contactManager, TransportPropertyManagerImpl transportPropertyManager) { + lifecycleManager.registerClient(transportPropertyManager); contactManager.registerAddContactHook(transportPropertyManager); contactManager.registerRemoveContactHook(transportPropertyManager); return transportPropertyManager; diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java index 4b10c48edeef1b79ea322826b2e3661bd3d7f32b..f393e3eaa29f9c49a88df097e189797d11e5d18c 100644 --- a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java +++ b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java @@ -3,6 +3,7 @@ package org.briarproject.properties; import org.briarproject.api.DeviceId; import org.briarproject.api.FormatException; import org.briarproject.api.TransportId; +import org.briarproject.api.clients.Client; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.PrivateGroupFactory; import org.briarproject.api.contact.Contact; @@ -13,13 +14,11 @@ import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfList; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; -import org.briarproject.api.db.NoSuchGroupException; import org.briarproject.api.db.Transaction; import org.briarproject.api.properties.TransportProperties; import org.briarproject.api.properties.TransportPropertyManager; import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.Group; -import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.Message; import org.briarproject.api.sync.MessageId; @@ -34,14 +33,12 @@ import java.util.Map.Entry; import javax.inject.Inject; class TransportPropertyManagerImpl implements TransportPropertyManager, - AddContactHook, RemoveContactHook { + Client, AddContactHook, RemoveContactHook { static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( "673ea091673561e28f70122f6a8ea8f4" + "97c3624b86fa07f785bb15f09fb87b4b")); - private static final byte[] LOCAL_GROUP_DESCRIPTOR = new byte[0]; - private final DatabaseComponent db; private final ClientHelper clientHelper; private final PrivateGroupFactory privateGroupFactory; @@ -50,20 +47,28 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, @Inject TransportPropertyManagerImpl(DatabaseComponent db, - ClientHelper clientHelper, GroupFactory groupFactory, - PrivateGroupFactory privateGroupFactory, Clock clock) { + ClientHelper clientHelper, PrivateGroupFactory privateGroupFactory, + Clock clock) { this.db = db; this.clientHelper = clientHelper; this.privateGroupFactory = privateGroupFactory; this.clock = clock; - localGroup = groupFactory.createGroup(CLIENT_ID, - LOCAL_GROUP_DESCRIPTOR); + localGroup = privateGroupFactory.createLocalGroup(CLIENT_ID); + } + + @Override + public void createLocalState(Transaction txn) throws DbException { + db.addGroup(txn, localGroup); + // Ensure we've set things up for any pre-existing contacts + for (Contact c : db.getContacts(txn)) addingContact(txn, c); } @Override public void addingContact(Transaction txn, Contact c) throws DbException { // Create a group to share with the contact Group g = getContactGroup(c); + // Return if we've already set things up for this contact + if (db.containsGroup(txn, g.getId())) return; // Store the group and share it with the contact db.addGroup(txn, g); db.setVisibleToContact(txn, c.getId(), g.getId(), true); @@ -126,9 +131,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, db.endTransaction(txn); } return p; - } catch (NoSuchGroupException e) { - // Local group doesn't exist - there are no local properties - return null; } catch (FormatException e) { throw new DbException(e); } @@ -169,8 +171,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, try { Transaction txn = db.startTransaction(false); try { - // Create the local group if necessary - db.addGroup(txn, localGroup); // Merge the new properties with any existing properties TransportProperties merged; boolean changed; @@ -230,9 +230,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, local.put(e.getKey(), parseProperties(message)); } return local; - } catch (NoSuchGroupException e) { - // Local group doesn't exist - there are no local properties - return Collections.emptyMap(); } catch (FormatException e) { throw new DbException(e); } diff --git a/briar-core/src/org/briarproject/sync/SyncModule.java b/briar-core/src/org/briarproject/sync/SyncModule.java index 15d13ce66fc0174e188bc0bcd7ce2386cb90ef11..2cbbac5d796c17d288ee0cb7c82f4391d75a3f0b 100644 --- a/briar-core/src/org/briarproject/sync/SyncModule.java +++ b/briar-core/src/org/briarproject/sync/SyncModule.java @@ -62,7 +62,7 @@ public class SyncModule { @Singleton ValidationManager getValidationManager(LifecycleManager lifecycleManager, EventBus eventBus, ValidationManagerImpl validationManager) { - lifecycleManager.register(validationManager); + lifecycleManager.registerService(validationManager); eventBus.addListener(validationManager); return validationManager; } diff --git a/briar-core/src/org/briarproject/transport/TransportModule.java b/briar-core/src/org/briarproject/transport/TransportModule.java index d5819fbfcbe19f94b376f51dbac8db4fb4fd3d2b..5cc81e458a00c02b109721c0061bc7ae4c37ac91 100644 --- a/briar-core/src/org/briarproject/transport/TransportModule.java +++ b/briar-core/src/org/briarproject/transport/TransportModule.java @@ -37,7 +37,7 @@ public class TransportModule { @Singleton KeyManager getKeyManager(LifecycleManager lifecycleManager, EventBus eventBus, KeyManagerImpl keyManager) { - lifecycleManager.register(keyManager); + lifecycleManager.registerService(keyManager); eventBus.addListener(keyManager); return keyManager; } diff --git a/briar-tests/src/org/briarproject/TestLifecycleModule.java b/briar-tests/src/org/briarproject/TestLifecycleModule.java index fbf07ca0d4ff861a7de86dd0ca2fd87331305cab..04137713c0315464ffbb0e3e5989959ce3abc437 100644 --- a/briar-tests/src/org/briarproject/TestLifecycleModule.java +++ b/briar-tests/src/org/briarproject/TestLifecycleModule.java @@ -1,5 +1,6 @@ package org.briarproject; +import org.briarproject.api.clients.Client; import org.briarproject.api.lifecycle.IoExecutor; import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.Service; @@ -20,8 +21,14 @@ public class TestLifecycleModule { @Provides LifecycleManager provideLifecycleManager() { return new LifecycleManager() { + @Override - public void register(Service s) { + public void registerService(Service s) { + + } + + @Override + public void registerClient(Client c) { } @@ -60,6 +67,7 @@ public class TestLifecycleModule { @Provides ShutdownManager provideShutdownManager() { return new ShutdownManager() { + @Override public int addShutdownHook(Runnable hook) { return 0; @@ -75,8 +83,7 @@ public class TestLifecycleModule { @Provides @IoExecutor @Singleton - Executor provideExecutor() { + Executor provideIoExecutor() { return Executors.newCachedThreadPool(); } - }