Addressing second round of review issues

This commit is contained in:
Torsten Grote
2016-10-19 09:03:48 -02:00
parent 0523c4e718
commit 8f882dc910
26 changed files with 167 additions and 164 deletions

View File

@@ -34,7 +34,7 @@ import static android.widget.Toast.LENGTH_SHORT;
import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH; import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH;
public class ForumActivity extends public class ForumActivity extends
ThreadListActivity<Forum, ForumEntry, ForumPostHeader, NestedForumAdapter> { ThreadListActivity<Forum, ForumItem, ForumPostHeader, NestedForumAdapter> {
private static final int REQUEST_FORUM_SHARED = 3; private static final int REQUEST_FORUM_SHARED = 3;
@@ -47,7 +47,7 @@ public class ForumActivity extends
} }
@Override @Override
protected ThreadListController<Forum, ForumEntry, ForumPostHeader> getController() { protected ThreadListController<Forum, ForumItem, ForumPostHeader> getController() {
return forumController; return forumController;
} }

View File

@@ -1,12 +1,10 @@
package org.briarproject.android.forum; package org.briarproject.android.forum;
import org.briarproject.android.controller.handler.ResultExceptionHandler;
import org.briarproject.android.threaded.ThreadListController; import org.briarproject.android.threaded.ThreadListController;
import org.briarproject.api.db.DbException;
import org.briarproject.api.forum.Forum; import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumPostHeader; import org.briarproject.api.forum.ForumPostHeader;
public interface ForumController public interface ForumController
extends ThreadListController<Forum, ForumEntry, ForumPostHeader> { extends ThreadListController<Forum, ForumItem, ForumPostHeader> {
} }

View File

@@ -4,6 +4,7 @@ import android.support.annotation.Nullable;
import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.threaded.ThreadListControllerImpl; import org.briarproject.android.threaded.ThreadListControllerImpl;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.crypto.CryptoExecutor; import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.db.DatabaseExecutor; import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
@@ -14,20 +15,20 @@ import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPost; import org.briarproject.api.forum.ForumPost;
import org.briarproject.api.forum.ForumPostHeader; import org.briarproject.api.forum.ForumPostHeader;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
public class ForumControllerImpl public class ForumControllerImpl
extends ThreadListControllerImpl<Forum, ForumEntry, ForumPostHeader, ForumPost> extends ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost>
implements ForumController { implements ForumController {
private static final Logger LOG = private static final Logger LOG =
@@ -37,12 +38,12 @@ public class ForumControllerImpl
@Inject @Inject
ForumControllerImpl(@DatabaseExecutor Executor dbExecutor, ForumControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, LifecycleManager lifecycleManager, IdentityManager identityManager,
@CryptoExecutor Executor cryptoExecutor, @CryptoExecutor Executor cryptoExecutor,
ForumManager forumManager, EventBus eventBus, ForumManager forumManager, EventBus eventBus,
AndroidNotificationManager notificationManager) { AndroidNotificationManager notificationManager) {
super(dbExecutor, lifecycleManager, cryptoExecutor, eventBus, super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
notificationManager); eventBus, notificationManager);
this.forumManager = forumManager; this.forumManager = forumManager;
} }
@@ -72,7 +73,7 @@ public class ForumControllerImpl
} }
@Override @Override
protected Forum loadGroupItem() throws DbException { protected Forum loadNamedGroup() throws DbException {
return forumManager.getForum(getGroupId()); return forumManager.getForum(getGroupId());
} }
@@ -82,18 +83,8 @@ public class ForumControllerImpl
} }
@Override @Override
protected Map<MessageId, String> loadBodies( protected String loadMessageBody(MessageId id) throws DbException {
Collection<ForumPostHeader> headers) return StringUtils.fromUtf8(forumManager.getPostBody(id));
throws DbException {
Map<MessageId, String> bodies = new HashMap<>();
for (ForumPostHeader header : headers) {
if (!bodyCache.containsKey(header.getId())) {
String body = StringUtils
.fromUtf8(forumManager.getPostBody(header.getId()));
bodies.put(header.getId(), body);
}
}
return bodies;
} }
@Override @Override
@@ -102,9 +93,17 @@ public class ForumControllerImpl
} }
@Override @Override
protected ForumPost createLocalMessage(String body, protected long getLatestTimestamp() throws DbException {
@Nullable MessageId parentId) throws DbException { GroupCount count = forumManager.getGroupCount(getGroupId());
return forumManager.createLocalPost(getGroupId(), body, parentId); return count.getLatestMsgTime();
}
@Override
protected ForumPost createLocalMessage(String body, long timestamp,
@Nullable MessageId parentId, LocalAuthor author) {
return forumManager
.createLocalPost(getGroupId(), body, timestamp, parentId,
author);
} }
@Override @Override
@@ -114,13 +113,13 @@ public class ForumControllerImpl
} }
@Override @Override
protected void deleteGroupItem(Forum forum) throws DbException { protected void deleteNamedGroup(Forum forum) throws DbException {
forumManager.removeForum(forum); forumManager.removeForum(forum);
} }
@Override @Override
protected ForumEntry buildItem(ForumPostHeader header, String body) { protected ForumItem buildItem(ForumPostHeader header, String body) {
return new ForumEntry(header, body); return new ForumItem(header, body);
} }
} }

View File

@@ -6,15 +6,17 @@ import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.Author.Status; import org.briarproject.api.identity.Author.Status;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
/* This class is not thread safe */ import javax.annotation.concurrent.NotThreadSafe;
public class ForumEntry extends ThreadItem {
ForumEntry(ForumPostHeader h, String text) { @NotThreadSafe
super(h.getId(), h.getParentId(), text, h.getTimestamp(), h.getAuthor(), public class ForumItem extends ThreadItem {
ForumItem(ForumPostHeader h, String body) {
super(h.getId(), h.getParentId(), body, h.getTimestamp(), h.getAuthor(),
h.getAuthorStatus(), h.isRead()); h.getAuthorStatus(), h.isRead());
} }
public ForumEntry(MessageId messageId, MessageId parentId, String text, public ForumItem(MessageId messageId, MessageId parentId, String text,
long timestamp, Author author, Status status) { long timestamp, Author author, Status status) {
super(messageId, parentId, text, timestamp, author, status, true); super(messageId, parentId, text, timestamp, author, status, true);
} }

View File

@@ -10,9 +10,9 @@ import org.briarproject.R;
import org.briarproject.android.threaded.ThreadItemAdapter; import org.briarproject.android.threaded.ThreadItemAdapter;
@UiThread @UiThread
public class NestedForumAdapter extends ThreadItemAdapter<ForumEntry> { public class NestedForumAdapter extends ThreadItemAdapter<ForumItem> {
public NestedForumAdapter(ThreadItemListener<ForumEntry> listener, public NestedForumAdapter(ThreadItemListener<ForumItem> listener,
LinearLayoutManager layoutManager) { LinearLayoutManager layoutManager) {
super(listener, layoutManager); super(listener, layoutManager);
} }

View File

@@ -4,7 +4,7 @@ import android.view.View;
import org.briarproject.android.threaded.ThreadItemViewHolder; import org.briarproject.android.threaded.ThreadItemViewHolder;
public class NestedForumHolder extends ThreadItemViewHolder<ForumEntry> { public class NestedForumHolder extends ThreadItemViewHolder<ForumItem> {
public NestedForumHolder(View v) { public NestedForumHolder(View v) {
super(v); super(v);

View File

@@ -4,12 +4,15 @@ import android.support.annotation.Nullable;
import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.threaded.ThreadListControllerImpl; import org.briarproject.android.threaded.ThreadListControllerImpl;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.crypto.CryptoExecutor; import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.db.DatabaseExecutor; import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event; import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.GroupMessageAddedEvent; import org.briarproject.api.event.GroupMessageAddedEvent;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.privategroup.GroupMessage; import org.briarproject.api.privategroup.GroupMessage;
import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.privategroup.GroupMessageHeader;
@@ -18,8 +21,6 @@ import org.briarproject.api.privategroup.PrivateGroupManager;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -36,19 +37,19 @@ public class GroupControllerImpl
@Inject @Inject
GroupControllerImpl(@DatabaseExecutor Executor dbExecutor, GroupControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, LifecycleManager lifecycleManager, IdentityManager identityManager,
@CryptoExecutor Executor cryptoExecutor, @CryptoExecutor Executor cryptoExecutor,
PrivateGroupManager privateGroupManager, EventBus eventBus, PrivateGroupManager privateGroupManager, EventBus eventBus,
AndroidNotificationManager notificationManager) { AndroidNotificationManager notificationManager) {
super(dbExecutor, lifecycleManager, cryptoExecutor, eventBus, super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
notificationManager); eventBus, notificationManager);
this.privateGroupManager = privateGroupManager; this.privateGroupManager = privateGroupManager;
} }
@Override @Override
public void onActivityResume() { public void onActivityResume() {
super.onActivityResume(); super.onActivityResume();
notificationManager.clearForumPostNotification(getGroupId()); // TODO: Add new notification manager methods for private groups
} }
@Override @Override
@@ -56,7 +57,7 @@ public class GroupControllerImpl
super.eventOccurred(e); super.eventOccurred(e);
if (e instanceof GroupMessageAddedEvent) { if (e instanceof GroupMessageAddedEvent) {
final GroupMessageAddedEvent gmae = (GroupMessageAddedEvent) e; GroupMessageAddedEvent gmae = (GroupMessageAddedEvent) e;
if (!gmae.isLocal() && gmae.getGroupId().equals(getGroupId())) { if (!gmae.isLocal() && gmae.getGroupId().equals(getGroupId())) {
LOG.info("Group message received, adding..."); LOG.info("Group message received, adding...");
final GroupMessageHeader h = gmae.getHeader(); final GroupMessageHeader h = gmae.getHeader();
@@ -71,7 +72,7 @@ public class GroupControllerImpl
} }
@Override @Override
protected PrivateGroup loadGroupItem() throws DbException { protected PrivateGroup loadNamedGroup() throws DbException {
return privateGroupManager.getPrivateGroup(getGroupId()); return privateGroupManager.getPrivateGroup(getGroupId());
} }
@@ -81,18 +82,8 @@ public class GroupControllerImpl
} }
@Override @Override
protected Map<MessageId, String> loadBodies( protected String loadMessageBody(MessageId id) throws DbException {
Collection<GroupMessageHeader> headers) return privateGroupManager.getMessageBody(id);
throws DbException {
Map<MessageId, String> bodies = new HashMap<>();
for (GroupMessageHeader header : headers) {
if (!bodyCache.containsKey(header.getId())) {
String body =
privateGroupManager.getMessageBody(header.getId());
bodies.put(header.getId(), body);
}
}
return bodies;
} }
@Override @Override
@@ -101,10 +92,17 @@ public class GroupControllerImpl
} }
@Override @Override
protected GroupMessage createLocalMessage(String body, protected long getLatestTimestamp() throws DbException {
@Nullable MessageId parentId) throws DbException { GroupCount count = privateGroupManager.getGroupCount(getGroupId());
return count.getLatestMsgTime();
}
@Override
protected GroupMessage createLocalMessage(String body, long timestamp,
@Nullable MessageId parentId, LocalAuthor author) {
return privateGroupManager return privateGroupManager
.createLocalMessage(getGroupId(), body, parentId); .createLocalMessage(getGroupId(), body, timestamp, parentId,
author);
} }
@Override @Override
@@ -114,7 +112,7 @@ public class GroupControllerImpl
} }
@Override @Override
protected void deleteGroupItem(PrivateGroup group) throws DbException { protected void deleteNamedGroup(PrivateGroup group) throws DbException {
privateGroupManager.removePrivateGroup(group.getId()); privateGroupManager.removePrivateGroup(group.getId());
} }

View File

@@ -31,7 +31,7 @@ class GroupListAdapter extends BriarAdapter<GroupItem, GroupViewHolder> {
@Override @Override
public void onBindViewHolder(GroupViewHolder ui, int position) { public void onBindViewHolder(GroupViewHolder ui, int position) {
ui.bindView(ctx, getItemAt(position), listener); ui.bindView(ctx, items.get(position), listener);
} }
@Override @Override

View File

@@ -68,6 +68,7 @@ public class GroupListControllerImpl extends DbControllerImpl
throw new IllegalStateException( throw new IllegalStateException(
"GroupListListener needs to be attached"); "GroupListListener needs to be attached");
eventBus.addListener(this); eventBus.addListener(this);
// TODO: Add new notification manager methods for private groups
} }
@Override @Override

View File

@@ -2,7 +2,6 @@ package org.briarproject.android.privategroup.list;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityOptionsCompat; import android.support.v4.app.ActivityOptionsCompat;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
@@ -51,7 +50,7 @@ class GroupViewHolder extends RecyclerView.ViewHolder {
remove = (Button) v.findViewById(R.id.removeButton); remove = (Button) v.findViewById(R.id.removeButton);
} }
void bindView(final Context ctx, @Nullable final GroupItem group, void bindView(final Context ctx, final GroupItem group,
@NotNull final OnGroupRemoveClickListener listener) { @NotNull final OnGroupRemoveClickListener listener) {
if (group == null) return; if (group == null) return;

View File

@@ -9,6 +9,7 @@ import android.support.v7.widget.RecyclerView;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -56,7 +57,7 @@ public abstract class ThreadItemAdapter<I extends ThreadItem>
return replyItem; return replyItem;
} }
public void setItems(List<I> items) { public void setItems(Collection<I> items) {
this.items.clear(); this.items.clear();
this.items.addAll(items); this.items.addAll(items);
notifyDataSetChanged(); notifyDataSetChanged();

View File

@@ -57,7 +57,7 @@ public abstract class ThreadItemViewHolder<I extends ThreadItem>
// TODO improve encapsulation, so we don't need to pass the adapter here // TODO improve encapsulation, so we don't need to pass the adapter here
public void bind(final ThreadItemAdapter<I> adapter, public void bind(final ThreadItemAdapter<I> adapter,
final ThreadItemListener listener, final I item, int pos) { final ThreadItemListener<I> listener, final I item, int pos) {
textView.setText(StringUtils.trim(item.getText())); textView.setText(StringUtils.trim(item.getText()));

View File

@@ -26,10 +26,9 @@ import org.briarproject.api.clients.PostHeader;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.briarproject.util.StringUtils;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import static android.support.design.widget.Snackbar.make; import static android.support.design.widget.Snackbar.make;
import static android.view.View.GONE; import static android.view.View.GONE;
@@ -75,7 +74,8 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
list.setAdapter(adapter); list.setAdapter(adapter);
if (state != null) { if (state != null) {
replyId = new MessageId(state.getByteArray(KEY_REPLY_ID)); byte[] replyIdBytes = state.getByteArray(KEY_REPLY_ID);
if(replyIdBytes != null) replyId = new MessageId(replyIdBytes);
} }
loadItems(); loadItems();
@@ -110,9 +110,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
new UiResultExceptionHandler<Collection<I>, DbException>( new UiResultExceptionHandler<Collection<I>, DbException>(
this) { this) {
@Override @Override
public void onResultUi(Collection<I> result) { public void onResultUi(Collection<I> items) {
// FIXME What's the benefit of copying the collection?
List<I> items = new ArrayList<>(result);
if (items.isEmpty()) { if (items.isEmpty()) {
list.showData(); list.showData();
} else { } else {
@@ -225,7 +223,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
public void onSendClick(String text) { public void onSendClick(String text) {
if (text.trim().length() == 0) if (text.trim().length() == 0)
return; return;
if (text.length() > getMaxBodyLength()) { if (StringUtils.isTooLong(text, getMaxBodyLength())) {
displaySnackbarShort(R.string.text_too_long); displaySnackbarShort(R.string.text_too_long);
return; return;
} }
@@ -243,12 +241,8 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
finish(); finish();
} }
}; };
if (replyItem == null) { getController().createAndStoreMessage(text,
// root post replyItem != null ? replyItem.getId() : null, handler);
getController().send(text, handler);
} else {
getController().send(text, replyItem.getId(), handler);
}
textInput.hideSoftKeyboard(); textInput.hideSoftKeyboard();
textInput.setVisibility(GONE); textInput.setVisibility(GONE);
adapter.setReplyItem(null); adapter.setReplyItem(null);
@@ -268,6 +262,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
@Override @Override
public void onExceptionUi(DbException exception) { public void onExceptionUi(DbException exception) {
// TODO add proper exception handling // TODO add proper exception handling
finish();
} }
}); });
} }

View File

@@ -29,9 +29,7 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
void markItemsRead(Collection<I> items); void markItemsRead(Collection<I> items);
void send(String body, ResultExceptionHandler<I, DbException> handler); void createAndStoreMessage(String body, @Nullable MessageId parentId,
void send(String body, @Nullable MessageId parentId,
ResultExceptionHandler<I, DbException> handler); ResultExceptionHandler<I, DbException> handler);
void deleteNamedGroup(ResultExceptionHandler<Void, DbException> handler); void deleteNamedGroup(ResultExceptionHandler<Void, DbException> handler);

View File

@@ -17,6 +17,8 @@ import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener; import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.GroupRemovedEvent; import org.briarproject.api.event.GroupRemovedEvent;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
@@ -40,11 +42,12 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ThreadListControllerImpl.class.getName()); Logger.getLogger(ThreadListControllerImpl.class.getName());
protected final Executor cryptoExecutor; private final IdentityManager identityManager;
private final Executor cryptoExecutor;
protected final AndroidNotificationManager notificationManager; protected final AndroidNotificationManager notificationManager;
private final EventBus eventBus; private final EventBus eventBus;
protected final Map<MessageId, String> bodyCache = private final Map<MessageId, String> bodyCache =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
private volatile GroupId groupId; private volatile GroupId groupId;
@@ -52,10 +55,11 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
protected ThreadListListener<H> listener; protected ThreadListListener<H> listener;
protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor, protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, LifecycleManager lifecycleManager, IdentityManager identityManager,
@CryptoExecutor Executor cryptoExecutor, EventBus eventBus, @CryptoExecutor Executor cryptoExecutor, EventBus eventBus,
AndroidNotificationManager notificationManager) { AndroidNotificationManager notificationManager) {
super(dbExecutor, lifecycleManager); super(dbExecutor, lifecycleManager);
this.identityManager = identityManager;
this.cryptoExecutor = cryptoExecutor; this.cryptoExecutor = cryptoExecutor;
this.eventBus = eventBus; this.eventBus = eventBus;
this.notificationManager = notificationManager; this.notificationManager = notificationManager;
@@ -76,15 +80,14 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
@CallSuper @CallSuper
@Override @Override
public void onActivityResume() { public void onActivityResume() {
checkGroupId(); notificationManager.blockNotification(getGroupId());
notificationManager.blockNotification(groupId);
eventBus.addListener(this); eventBus.addListener(this);
} }
@CallSuper @CallSuper
@Override @Override
public void onActivityPause() { public void onActivityPause() {
notificationManager.unblockNotification(groupId); notificationManager.unblockNotification(getGroupId());
eventBus.removeListener(this); eventBus.removeListener(this);
} }
@@ -97,7 +100,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof GroupRemovedEvent) { if (e instanceof GroupRemovedEvent) {
GroupRemovedEvent s = (GroupRemovedEvent) e; GroupRemovedEvent s = (GroupRemovedEvent) e;
if (s.getGroup().getId().equals(groupId)) { if (s.getGroup().getId().equals(getGroupId())) {
LOG.info("Group removed"); LOG.info("Group removed");
listener.runOnUiThreadUnlessDestroyed(new Runnable() { listener.runOnUiThreadUnlessDestroyed(new Runnable() {
@Override @Override
@@ -118,7 +121,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
public void run() { public void run() {
try { try {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
G groupItem = loadGroupItem(); G groupItem = loadNamedGroup();
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info( LOG.info(
@@ -134,7 +137,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
} }
@DatabaseExecutor @DatabaseExecutor
protected abstract G loadGroupItem() throws DbException; protected abstract G loadNamedGroup() throws DbException;
@Override @Override
public void loadItems( public void loadItems(
@@ -152,10 +155,14 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Loading headers took " + duration + " ms"); LOG.info("Loading headers took " + duration + " ms");
// Load bodies // Load bodies into cache
now = System.currentTimeMillis(); now = System.currentTimeMillis();
Map<MessageId, String> bodies = loadBodies(headers); for (H header : headers) {
bodyCache.putAll(bodies); if (!bodyCache.containsKey(header.getId())) {
bodyCache.put(header.getId(),
loadMessageBody(header.getId()));
}
}
duration = System.currentTimeMillis() - now; duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Loading bodies took " + duration + " ms"); LOG.info("Loading bodies took " + duration + " ms");
@@ -175,8 +182,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
protected abstract Collection<H> loadHeaders() throws DbException; protected abstract Collection<H> loadHeaders() throws DbException;
@DatabaseExecutor @DatabaseExecutor
protected abstract Map<MessageId, String> loadBodies(Collection<H> headers) protected abstract String loadMessageBody(MessageId id) throws DbException;
throws DbException;
@Override @Override
public void loadItem(final H header, public void loadItem(final H header,
@@ -186,9 +192,13 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
public void run() { public void run() {
LOG.info("Loading item..."); LOG.info("Loading item...");
try { try {
String body = loadBodies(Collections.singletonList(header)) String body;
.get(header.getId()); if (!bodyCache.containsKey(header.getId())) {
bodyCache.put(header.getId(), body); body = loadMessageBody(header.getId());
bodyCache.put(header.getId(), body);
} else {
body = bodyCache.get(header.getId());
}
I item = buildItem(header, body); I item = buildItem(header, body);
handler.onResult(item); handler.onResult(item);
} catch (DbException e) { } catch (DbException e) {
@@ -230,21 +240,19 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
protected abstract void markRead(MessageId id) throws DbException; protected abstract void markRead(MessageId id) throws DbException;
@Override @Override
public void send(String body, public void createAndStoreMessage(final String body,
ResultExceptionHandler<I, DbException> resultHandler) { @Nullable final MessageId parentId,
send(body, null, resultHandler);
}
@Override
public void send(final String body, @Nullable final MessageId parentId,
final ResultExceptionHandler<I, DbException> handler) { final ResultExceptionHandler<I, DbException> handler) {
cryptoExecutor.execute(new Runnable() { runOnDbThread(new Runnable() {
@Override @Override
public void run() { public void run() {
LOG.info("Creating message...");
try { try {
M msg = createLocalMessage(body, parentId); LocalAuthor author = identityManager.getLocalAuthor();
storePost(msg, body, handler); long timestamp = getLatestTimestamp();
timestamp =
Math.max(timestamp, System.currentTimeMillis());
createMessage(body, timestamp, parentId, author,
handler);
} catch (DbException e) { } catch (DbException e) {
if (LOG.isLoggable(WARNING)) if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e); LOG.log(WARNING, e.toString(), e);
@@ -255,8 +263,24 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
} }
@DatabaseExecutor @DatabaseExecutor
protected abstract M createLocalMessage(String body, protected abstract long getLatestTimestamp() throws DbException;
@Nullable MessageId parentId) throws DbException;
private void createMessage(final String body, final long timestamp,
final @Nullable MessageId parentId, final LocalAuthor author,
final ResultExceptionHandler<I, DbException> handler) {
cryptoExecutor.execute(new Runnable() {
@Override
public void run() {
LOG.info("Creating message...");
M msg = createLocalMessage(body, timestamp, parentId, author);
storePost(msg, body, handler);
}
});
}
@CryptoExecutor
protected abstract M createLocalMessage(String body, long timestamp,
@Nullable MessageId parentId, LocalAuthor author);
private void storePost(final M msg, final String body, private void storePost(final M msg, final String body,
final ResultExceptionHandler<I, DbException> resultHandler) { final ResultExceptionHandler<I, DbException> resultHandler) {
@@ -292,8 +316,8 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
public void run() { public void run() {
try { try {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
G groupItem = loadGroupItem(); G groupItem = loadNamedGroup();
deleteGroupItem(groupItem); deleteNamedGroup(groupItem);
long duration = System.currentTimeMillis() - now; long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Removing group took " + duration + " ms"); LOG.info("Removing group took " + duration + " ms");
@@ -309,7 +333,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
} }
@DatabaseExecutor @DatabaseExecutor
protected abstract void deleteGroupItem(G groupItem) throws DbException; protected abstract void deleteNamedGroup(G groupItem) throws DbException;
private List<I> buildItems(Collection<H> headers) { private List<I> buildItems(Collection<H> headers) {
List<I> entries = new ArrayList<>(); List<I> entries = new ArrayList<>();

View File

@@ -11,14 +11,12 @@ import org.briarproject.android.controller.handler.UiResultExceptionHandler;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.identity.Author; import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric; import org.robolectric.Robolectric;
import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.RobolectricGradleTestRunner;
@@ -82,7 +80,7 @@ public class ForumActivityTest {
private TestForumActivity forumActivity; private TestForumActivity forumActivity;
@Captor @Captor
private ArgumentCaptor<UiResultExceptionHandler<Collection<ForumEntry>, DbException>> private ArgumentCaptor<UiResultExceptionHandler<Collection<ForumItem>, DbException>>
rc; rc;
@Before @Before
@@ -94,14 +92,14 @@ public class ForumActivityTest {
.withIntent(intent).create().resume().get(); .withIntent(intent).create().resume().get();
} }
private List<ForumEntry> getDummyData() { private List<ForumItem> getDummyData() {
ForumEntry[] forumEntries = new ForumEntry[6]; ForumItem[] forumEntries = new ForumItem[6];
for (int i = 0; i < forumEntries.length; i++) { for (int i = 0; i < forumEntries.length; i++) {
AuthorId authorId = new AuthorId(TestUtils.getRandomId()); AuthorId authorId = new AuthorId(TestUtils.getRandomId());
byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH); byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
Author author = new Author(authorId, AUTHORS[i], publicKey); Author author = new Author(authorId, AUTHORS[i], publicKey);
forumEntries[i] = forumEntries[i] =
new ForumEntry(AUTHOR_IDS[i], PARENT_AUTHOR_IDS[i], new ForumItem(AUTHOR_IDS[i], PARENT_AUTHOR_IDS[i],
AUTHORS[i], System.currentTimeMillis(), author, AUTHORS[i], System.currentTimeMillis(), author,
UNKNOWN); UNKNOWN);
forumEntries[i].setLevel(LEVELS[i]); forumEntries[i].setLevel(LEVELS[i]);
@@ -112,7 +110,7 @@ public class ForumActivityTest {
@Test @Test
public void testNestedEntries() { public void testNestedEntries() {
ForumController mc = forumActivity.getController(); ForumController mc = forumActivity.getController();
List<ForumEntry> dummyData = getDummyData(); List<ForumItem> dummyData = getDummyData();
verify(mc, times(1)).loadItems(rc.capture()); verify(mc, times(1)).loadItems(rc.capture());
rc.getValue().onResult(dummyData); rc.getValue().onResult(dummyData);
NestedForumAdapter adapter = forumActivity.getAdapter(); NestedForumAdapter adapter = forumActivity.getAdapter();

View File

@@ -7,9 +7,9 @@ import org.briarproject.api.sharing.Shareable;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.Immutable;
@ThreadSafe @Immutable
@NotNullByDefault @NotNullByDefault
public class Blog extends BaseGroup implements Shareable { public class Blog extends BaseGroup implements Shareable {

View File

@@ -5,9 +5,9 @@ import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.Immutable;
@ThreadSafe @Immutable
@NotNullByDefault @NotNullByDefault
public abstract class BaseGroup { public abstract class BaseGroup {

View File

@@ -4,9 +4,9 @@ import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.Immutable;
@ThreadSafe @Immutable
@NotNullByDefault @NotNullByDefault
public abstract class NamedGroup extends BaseGroup { public abstract class NamedGroup extends BaseGroup {

View File

@@ -5,9 +5,9 @@ import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sharing.Shareable; import org.briarproject.api.sharing.Shareable;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.Immutable;
@ThreadSafe @Immutable
@NotNullByDefault @NotNullByDefault
public class Forum extends NamedGroup implements Shareable { public class Forum extends NamedGroup implements Shareable {

View File

@@ -1,8 +1,10 @@
package org.briarproject.api.forum; package org.briarproject.api.forum;
import org.briarproject.api.clients.MessageTracker; import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
@@ -22,8 +24,9 @@ public interface ForumManager extends MessageTracker {
void removeForum(Forum f) throws DbException; void removeForum(Forum f) throws DbException;
/** Creates a local forum post. */ /** Creates a local forum post. */
ForumPost createLocalPost(GroupId groupId, String text, @CryptoExecutor
@Nullable MessageId parentId) throws DbException; ForumPost createLocalPost(GroupId groupId, String body, long timestamp,
@Nullable MessageId parentId, LocalAuthor author);
/** Stores a local forum post. */ /** Stores a local forum post. */
ForumPostHeader addLocalPost(ForumPost p) throws DbException; ForumPostHeader addLocalPost(ForumPost p) throws DbException;

View File

@@ -6,9 +6,9 @@ import org.briarproject.api.nullsafety.NotNullByDefault;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.Immutable;
@ThreadSafe @Immutable
@NotNullByDefault @NotNullByDefault
public class PrivateGroup extends NamedGroup { public class PrivateGroup extends NamedGroup {

View File

@@ -3,6 +3,7 @@ package org.briarproject.api.privategroup;
import org.briarproject.api.clients.MessageTracker; import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction; import org.briarproject.api.db.Transaction;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
@@ -21,8 +22,8 @@ public interface PrivateGroupManager extends MessageTracker {
void removePrivateGroup(GroupId g) throws DbException; void removePrivateGroup(GroupId g) throws DbException;
/** Creates a local group message. */ /** Creates a local group message. */
GroupMessage createLocalMessage(GroupId groupId, String text, GroupMessage createLocalMessage(GroupId groupId, String body,
@Nullable MessageId parentId) throws DbException; long timestamp, @Nullable MessageId parentId, LocalAuthor author);
/** Stores (and sends) a local group message. */ /** Stores (and sends) a local group message. */
GroupMessageHeader addLocalMessage(GroupMessage p) throws DbException; GroupMessageHeader addLocalMessage(GroupMessage p) throws DbException;

View File

@@ -25,7 +25,6 @@ import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.briarproject.api.system.Clock;
import org.briarproject.clients.BdfIncomingMessageHook; import org.briarproject.clients.BdfIncomingMessageHook;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -64,20 +63,17 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final ForumFactory forumFactory; private final ForumFactory forumFactory;
private final ForumPostFactory forumPostFactory; private final ForumPostFactory forumPostFactory;
private final Clock clock;
private final List<RemoveForumHook> removeHooks; private final List<RemoveForumHook> removeHooks;
@Inject @Inject
ForumManagerImpl(DatabaseComponent db, IdentityManager identityManager, ForumManagerImpl(DatabaseComponent db, IdentityManager identityManager,
ClientHelper clientHelper, MetadataParser metadataParser, ClientHelper clientHelper, MetadataParser metadataParser,
ForumFactory forumFactory, ForumPostFactory forumPostFactory, ForumFactory forumFactory, ForumPostFactory forumPostFactory) {
Clock clock) {
super(db, clientHelper, metadataParser); super(db, clientHelper, metadataParser);
this.identityManager = identityManager; this.identityManager = identityManager;
this.forumFactory = forumFactory; this.forumFactory = forumFactory;
this.forumPostFactory = forumPostFactory; this.forumPostFactory = forumPostFactory;
this.clock = clock;
removeHooks = new CopyOnWriteArrayList<RemoveForumHook>(); removeHooks = new CopyOnWriteArrayList<RemoveForumHook>();
} }
@@ -129,23 +125,9 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
} }
@Override @Override
public ForumPost createLocalPost(final GroupId groupId, public ForumPost createLocalPost(final GroupId groupId, final String body,
final String body, final @Nullable MessageId parentId) final long timestamp, final @Nullable MessageId parentId,
throws DbException { final LocalAuthor author) {
LocalAuthor author;
GroupCount count;
Transaction txn = db.startTransaction(true);
try {
author = identityManager.getLocalAuthor(txn);
count = getGroupCount(txn, groupId);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
long timestamp = clock.currentTimeMillis();
timestamp = Math.max(timestamp, count.getLatestMsgTime());
ForumPost p; ForumPost p;
try { try {
p = forumPostFactory p = forumPostFactory

View File

@@ -77,16 +77,13 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
@Override @Override
public GroupMessage createLocalMessage(GroupId groupId, String body, public GroupMessage createLocalMessage(GroupId groupId, String body,
@Nullable MessageId parentId) throws DbException { long timestamp, @Nullable MessageId parentId, LocalAuthor author) {
long timestamp = clock.currentTimeMillis();
LocalAuthor author = identityManager.getLocalAuthor();
try { try {
return groupMessageFactory return groupMessageFactory
.createGroupMessage(groupId, timestamp, parentId, author, .createGroupMessage(groupId, timestamp, parentId, author,
body); body);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new RuntimeException(e);
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -86,4 +86,11 @@ public class StringUtils {
public static String trim(String s) { public static String trim(String s) {
return s.trim(); return s.trim();
} }
/**
* Returns true if the string is longer than maxLength
*/
public static boolean isTooLong(String s, int maxLength) {
return toUtf8(s).length > maxLength;
}
} }