diff --git a/briar-android/src/org/briarproject/android/AndroidComponent.java b/briar-android/src/org/briarproject/android/AndroidComponent.java index 24f4c4103c915f98c73dbe9aa2644b8573371a46..accd45a4cdedfc1b33c49780842fab34b3880741 100644 --- a/briar-android/src/org/briarproject/android/AndroidComponent.java +++ b/briar-android/src/org/briarproject/android/AndroidComponent.java @@ -5,7 +5,6 @@ import org.briarproject.CoreModule; import org.briarproject.android.api.AndroidExecutor; import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.api.ReferenceManager; -import org.briarproject.android.forum.ForumPersistentData; import org.briarproject.android.report.BriarReportSender; import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogPostFactory; @@ -33,7 +32,6 @@ import org.briarproject.api.messaging.MessagingManager; import org.briarproject.api.messaging.PrivateMessageFactory; import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.plugins.PluginManager; -import org.briarproject.api.properties.TransportPropertyManager; import org.briarproject.api.settings.SettingsManager; import org.briarproject.plugins.AndroidPluginsModule; import org.briarproject.system.AndroidSystemModule; @@ -114,8 +112,6 @@ public interface AndroidComponent extends CoreEagerSingletons { AndroidExecutor androidExecutor(); - ForumPersistentData forumPersistentData(); - @IoExecutor Executor ioExecutor(); diff --git a/briar-android/src/org/briarproject/android/AppModule.java b/briar-android/src/org/briarproject/android/AppModule.java index 766a79362d465e72e8fc9a723f1a3ba59a619659..8f80ce0395841c0d5d1a5e81eb2d0c7f14a77831 100644 --- a/briar-android/src/org/briarproject/android/AppModule.java +++ b/briar-android/src/org/briarproject/android/AppModule.java @@ -4,7 +4,6 @@ import android.app.Application; import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.api.ReferenceManager; -import org.briarproject.android.forum.ForumPersistentData; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.PublicKey; import org.briarproject.api.crypto.SecretKey; @@ -137,10 +136,4 @@ public class AppModule { eventBus.addListener(notificationManager); return notificationManager; } - - @Provides - @Singleton - ForumPersistentData provideForumPersistence() { - return new ForumPersistentData(); - } } diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java index 77f574f20f4a2a18f4471c01e0d9e1e63006fd06..f6a0c597f583591fa249157d91f12f8f36bfc13b 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java +++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java @@ -37,6 +37,7 @@ import org.briarproject.android.controller.handler.UiResultHandler; import org.briarproject.android.util.AndroidUtils; import org.briarproject.android.util.BriarRecyclerView; import org.briarproject.android.util.TrustIndicatorView; +import org.briarproject.api.forum.Forum; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; import org.briarproject.util.StringUtils; @@ -117,7 +118,8 @@ public class ForumActivity extends BriarActivity implements @Override public void onResultUi(Boolean result) { if (result) { - setTitle(forumController.getForumName()); + Forum forum = forumController.getForum(); + if (forum != null) setTitle(forum.getName()); forumAdapter = new ForumAdapter( forumController.getForumEntries()); recyclerView.setAdapter(forumAdapter); @@ -264,6 +266,7 @@ public class ForumActivity extends BriarActivity implements String text = textInput.getText().toString(); if (text.trim().length() == 0) return; + if (forumController.getForum() == null) return; ForumEntry replyEntry = forumAdapter.getReplyEntry(); if (replyEntry == null) { // root post diff --git a/briar-android/src/org/briarproject/android/forum/ForumController.java b/briar-android/src/org/briarproject/android/forum/ForumController.java index a3419b812f84edf39839f587186c2bcb2adff167..be8b427919a4e0150281f6f7224c13360473c86a 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumController.java +++ b/briar-android/src/org/briarproject/android/forum/ForumController.java @@ -1,7 +1,11 @@ package org.briarproject.android.forum; +import android.support.annotation.Nullable; + import org.briarproject.android.controller.ActivityLifecycleController; +import org.briarproject.android.controller.handler.ResultHandler; import org.briarproject.android.controller.handler.UiResultHandler; +import org.briarproject.api.forum.Forum; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; @@ -10,8 +14,9 @@ import java.util.List; public interface ForumController extends ActivityLifecycleController { - void loadForum(GroupId groupId, UiResultHandler<Boolean> resultHandler); - String getForumName(); + void loadForum(GroupId groupId, ResultHandler<Boolean> resultHandler); + @Nullable + Forum getForum(); List<ForumEntry> getForumEntries(); void unsubscribe(UiResultHandler<Boolean> resultHandler); void entryRead(ForumEntry forumEntry); diff --git a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java index b5e83f8f4fa1c317eefc0130c2aed156e0cc2f87..54ff74de204ec58c7c5a65616422a44bcaecc768 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java +++ b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java @@ -1,10 +1,13 @@ package org.briarproject.android.forum; import android.app.Activity; +import android.support.annotation.Nullable; import org.briarproject.android.controller.DbControllerImpl; +import org.briarproject.android.controller.handler.ResultHandler; import org.briarproject.android.controller.handler.UiResultHandler; import org.briarproject.api.FormatException; +import org.briarproject.api.clients.MessageTree; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoExecutor; import org.briarproject.api.crypto.KeyParser; @@ -15,22 +18,25 @@ import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.event.ForumPostReceivedEvent; import org.briarproject.api.event.GroupRemovedEvent; +import org.briarproject.api.forum.Forum; import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumPost; import org.briarproject.api.forum.ForumPostFactory; import org.briarproject.api.forum.ForumPostHeader; -import org.briarproject.api.identity.Author; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; +import org.briarproject.clients.MessageTreeImpl; import org.briarproject.util.StringUtils; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Stack; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -62,8 +68,13 @@ public class ForumControllerImpl extends DbControllerImpl protected volatile EventBus eventBus; @Inject protected volatile IdentityManager identityManager; - @Inject - protected ForumPersistentData data; + + private volatile MessageTree<ForumPostHeader> tree = + new MessageTreeImpl<>(); + private volatile Map<MessageId, byte[]> bodyCache = new HashMap<>(); + private volatile LocalAuthor localAuthor = null; + private volatile Forum forum = null; + private volatile List<ForumEntry> forumEntries = null; private ForumPostListener listener; @@ -95,22 +106,21 @@ public class ForumControllerImpl extends DbControllerImpl @Override public void onActivityDestroy() { - if (activity.isFinishing()) { - data.clearAll(); - } } @Override public void eventOccurred(Event e) { + if (forum == null) return; + if (e instanceof ForumPostReceivedEvent) { ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e; - if (pe.getGroupId().equals(data.getGroupId())) { + if (pe.getGroupId().equals(forum.getId())) { LOG.info("Forum Post received, adding..."); addNewPost(pe.getForumPostHeader()); } } else if (e instanceof GroupRemovedEvent) { GroupRemovedEvent s = (GroupRemovedEvent) e; - if (s.getGroup().getId().equals(data.getGroupId())) { + if (s.getGroup().getId().equals(forum.getId())) { LOG.info("Forum removed"); activity.runOnUiThread(new Runnable() { @Override @@ -123,28 +133,29 @@ public class ForumControllerImpl extends DbControllerImpl } private void addNewPost(final ForumPostHeader h) { - if (data == null) return; + if (forum == null) return; runOnDbThread(new Runnable() { @Override public void run() { - data.addHeader(h); - data.clearForumEntries(); - - try { - byte[] body = forumManager.getPostBody(h.getId()); - data.addBody(h.getId(), body); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); + if (!bodyCache.containsKey(h.getId())) { + try { + byte[] body = forumManager.getPostBody(h.getId()); + bodyCache.put(h.getId(), body); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + return; + } } - Author a = data.getLocalAuthor(); + tree.add(h); + forumEntries = null; // FIXME we should not need to calculate the index here // the index is essentially stored in two different locations int i = 0; for (ForumEntry entry : getForumEntries()) { if (entry.getMessageId().equals(h.getId())) { - if (a != null && a.equals(h.getAuthor())) { + if (localAuthor != null && localAuthor.equals(h.getAuthor())) { addLocalEntry(i, entry); } else { addForeignEntry(i, entry); @@ -156,31 +167,29 @@ public class ForumControllerImpl extends DbControllerImpl }); } - private void loadAuthor() throws DbException { - Collection<LocalAuthor> localAuthors = - identityManager.getLocalAuthors(); - - for (LocalAuthor author : localAuthors) { - if (author == null) - continue; - data.setLocalAuthor(author); - break; - } - } - + /** + * This should only be run from the DbThread. + * @throws DbException + */ private void loadPosts() throws DbException { + if (forum == null) + throw new RuntimeException("Forum has not been initialized"); + + // Get Headers long now = System.currentTimeMillis(); Collection<ForumPostHeader> headers = - forumManager.getPostHeaders(data.getGroupId()); - data.addHeaders(headers); + forumManager.getPostHeaders(forum.getId()); + tree.add(headers); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Loading headers took " + duration + " ms"); + + // Get Bodies now = System.currentTimeMillis(); for (ForumPostHeader header : headers) { - if (data.getBody(header.getId()) == null) { + if (!bodyCache.containsKey(header.getId())) { byte[] body = forumManager.getPostBody(header.getId()); - data.addBody(header.getId(), body); + bodyCache.put(header.getId(), body); } } duration = System.currentTimeMillis() - now; @@ -190,29 +199,32 @@ public class ForumControllerImpl extends DbControllerImpl @Override public void loadForum(final GroupId groupId, - final UiResultHandler<Boolean> resultHandler) { - LOG.info("Loading forum..."); - + final ResultHandler<Boolean> resultHandler) { runOnDbThread(new Runnable() { @Override public void run() { + LOG.info("Loading forum..."); try { - if (data.getGroupId() == null || - !data.getGroupId().equals(groupId)) { - data.clearAll(); - data.setGroupId(groupId); + if (forum == null) { + // Get Forum long now = System.currentTimeMillis(); - data.setForum(forumManager.getForum(groupId)); + forum = forumManager.getForum(groupId); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Loading forum took " + duration + " ms"); + + // Get First Identity now = System.currentTimeMillis(); - loadAuthor(); + localAuthor = + identityManager.getLocalAuthors().iterator() + .next(); duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Loading author took " + duration + " ms"); + + // Get Forum Posts and Bodies loadPosts(); } resultHandler.onResult(true); @@ -223,21 +235,21 @@ public class ForumControllerImpl extends DbControllerImpl } } }); - } @Override - public String getForumName() { - return data.getForum() == null ? null : data.getForum().getName(); + @Nullable + public Forum getForum() { + return forum; } @Override public List<ForumEntry> getForumEntries() { - if (data.getForumEntries() != null) { - return data.getForumEntries(); + if (forumEntries != null) { + return forumEntries; } - Collection<ForumPostHeader> headers = data.getHeaders(); - List<ForumEntry> forumEntries = new ArrayList<>(); + Collection<ForumPostHeader> headers = getHeaders(); + List<ForumEntry> entries = new ArrayList<>(); Stack<MessageId> idStack = new Stack<>(); for (ForumPostHeader h : headers) { @@ -251,21 +263,22 @@ public class ForumControllerImpl extends DbControllerImpl idStack.pop(); } while (!h.getParentId().equals(idStack.peek())); } - forumEntries.add(new ForumEntry(h, - StringUtils.fromUtf8(data.getBody(h.getId())), - idStack.size())); + byte[] body = bodyCache.get(h.getId()); + entries.add(new ForumEntry(h, StringUtils.fromUtf8(body), + idStack.size())); } - data.setForumEntries(forumEntries); - return forumEntries; + forumEntries = entries; + return entries; } @Override public void unsubscribe(final UiResultHandler<Boolean> resultHandler) { + if (forum == null) return; runOnDbThread(new Runnable() { public void run() { try { long now = System.currentTimeMillis(); - forumManager.removeForum(data.getForum()); + forumManager.removeForum(forum); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Removing forum took " + duration + " ms"); @@ -315,7 +328,7 @@ public class ForumControllerImpl extends DbControllerImpl public void run() { long timestamp = System.currentTimeMillis(); long newestTimeStamp = 0; - Collection<ForumPostHeader> headers = data.getHeaders(); + Collection<ForumPostHeader> headers = getHeaders(); if (headers != null) { for (ForumPostHeader h : headers) { if (h.getTimestamp() > newestTimeStamp) @@ -329,15 +342,16 @@ public class ForumControllerImpl extends DbControllerImpl ForumPost p; try { KeyParser keyParser = crypto.getSignatureKeyParser(); - byte[] b = data.getLocalAuthor().getPrivateKey(); + byte[] b = localAuthor.getPrivateKey(); PrivateKey authorKey = keyParser.parsePrivateKey(b); p = forumPostFactory.createPseudonymousPost( - data.getGroupId(), timestamp, parentId, - data.getLocalAuthor(), "text/plain", body, + forum.getId(), timestamp, parentId, + localAuthor, "text/plain", body, authorKey); } catch (GeneralSecurityException | FormatException e) { throw new RuntimeException(e); } + bodyCache.put(p.getMessage().getId(), body); storePost(p); addNewPost(p); } @@ -388,4 +402,8 @@ public class ForumControllerImpl extends DbControllerImpl addNewPost(h); } + private Collection<ForumPostHeader> getHeaders() { + return tree.depthFirstOrder(); + } + } diff --git a/briar-android/src/org/briarproject/android/forum/ForumPersistentData.java b/briar-android/src/org/briarproject/android/forum/ForumPersistentData.java deleted file mode 100644 index 6464be24ead03476e301674648cee386da43b0df..0000000000000000000000000000000000000000 --- a/briar-android/src/org/briarproject/android/forum/ForumPersistentData.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.briarproject.android.forum; - -import org.briarproject.api.clients.MessageTree; -import org.briarproject.api.forum.Forum; -import org.briarproject.api.forum.ForumPostHeader; -import org.briarproject.api.identity.LocalAuthor; -import org.briarproject.api.sync.GroupId; -import org.briarproject.api.sync.MessageId; -import org.briarproject.clients.MessageTreeImpl; - -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * This class is a singleton that defines the data that should persist, i.e. - * still be present in memory after activity restarts. This class is not thread - * safe. - */ -public class ForumPersistentData { - - private volatile MessageTree<ForumPostHeader> tree = - new MessageTreeImpl<>(); - private volatile Map<MessageId, byte[]> bodyCache = new HashMap<>(); - private volatile LocalAuthor localAuthor; - private volatile Forum forum; - private volatile GroupId groupId; - private List<ForumEntry> forumEntries; - - void clearAll() { - clearForumEntries(); - tree.clear(); - bodyCache.clear(); - localAuthor = null; - forum = null; - groupId = null; - } - - void clearForumEntries() { - forumEntries = null; - } - - void addHeaders(Collection<ForumPostHeader> headers) { - tree.add(headers); - } - - void addHeader(ForumPostHeader header) { - tree.add(header); - } - - public Collection<ForumPostHeader> getHeaders() { - return tree.depthFirstOrder(); - } - - void addBody(MessageId messageId, byte[] body) { - bodyCache.put(messageId, body); - } - - byte[] getBody(MessageId messageId) { - return bodyCache.get(messageId); - } - - public LocalAuthor getLocalAuthor() { - return localAuthor; - } - - public void setLocalAuthor( - LocalAuthor localAuthor) { - this.localAuthor = localAuthor; - } - - public Forum getForum() { - return forum; - } - - public void setForum(Forum forum) { - this.forum = forum; - } - - public GroupId getGroupId() { - return groupId; - } - - public void setGroupId(GroupId groupId) { - this.groupId = groupId; - } - - List<ForumEntry> getForumEntries() { - return forumEntries; - } - - void setForumEntries(List<ForumEntry> forumEntries) { - this.forumEntries = forumEntries; - } -} diff --git a/briar-android/src/org/briarproject/android/forum/ForumTestControllerImpl.java b/briar-android/src/org/briarproject/android/forum/ForumTestControllerImpl.java index 2aef2ae5e121fe61e60789800aea97ac75e51a0b..8f90062415305e34021dc4ad87c8f8294245f858 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumTestControllerImpl.java +++ b/briar-android/src/org/briarproject/android/forum/ForumTestControllerImpl.java @@ -1,7 +1,9 @@ package org.briarproject.android.forum; +import org.briarproject.android.controller.handler.ResultHandler; import org.briarproject.android.controller.handler.UiResultHandler; import org.briarproject.api.UniqueId; +import org.briarproject.api.forum.Forum; import org.briarproject.api.identity.AuthorId; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; @@ -63,7 +65,7 @@ public class ForumTestControllerImpl implements ForumController { private ForumEntry[] forumEntries; @Inject - public ForumTestControllerImpl() { + ForumTestControllerImpl() { } @@ -94,7 +96,7 @@ public class ForumTestControllerImpl implements ForumController { @Override public void loadForum(GroupId groupId, - UiResultHandler<Boolean> resultHandler) { + ResultHandler<Boolean> resultHandler) { SecureRandom random = new SecureRandom(); forumEntries = new ForumEntry[100]; // string cut off index @@ -124,14 +126,14 @@ public class ForumTestControllerImpl implements ForumController { } @Override - public String getForumName() { - return "SAGA"; + public Forum getForum() { + return null; } @Override public List<ForumEntry> getForumEntries() { return forumEntries == null ? null : - new ArrayList<ForumEntry>(Arrays.asList(forumEntries)); + new ArrayList<>(Arrays.asList(forumEntries)); } @Override