diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml index 0f541d6fb34dd2af859df89fb23e7675fff52349..b1652f5fb7c1ea51c54367e5d0137ac4bdc99d83 100644 --- a/briar-android/res/values/strings.xml +++ b/briar-android/res/values/strings.xml @@ -75,6 +75,7 @@ <string name="send">Send</string> <string name="no_data">No data</string> <string name="ellipsis">…</string> + <string name="text_too_long">The entered text is too long</string> <!-- Contacts and Private Conversations--> <string name="no_contacts">It seems that you are new here and have no contacts yet.\n\nTap the + icon at the top and follow the instructions to add some friends to your list.\n\nPlease remember: You can only add new contacts face-to-face to prevent anyone from impersonating you or reading your messages in the future.</string> diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java index 74537eed76d8c4ee4fc16948803d96c1d7853a61..eafa66098ca47026d91cf04be40e47c756145e49 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java +++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java @@ -2,7 +2,9 @@ package org.briarproject.android.forum; import android.content.DialogInterface; import android.content.Intent; +import android.os.Bundle; import android.support.annotation.LayoutRes; +import android.support.annotation.StringRes; import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityOptionsCompat; import android.support.v7.app.AlertDialog; @@ -29,6 +31,7 @@ import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation; import static android.widget.Toast.LENGTH_SHORT; +import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH; public class ForumActivity extends ThreadListActivity<Forum, ForumEntry, ForumPostHeader, NestedForumAdapter> { @@ -36,7 +39,7 @@ public class ForumActivity extends private static final int REQUEST_FORUM_SHARED = 3; @Inject - protected ForumController forumController; + ForumController forumController; @Override public void injectActivity(ActivityComponent component) { @@ -49,7 +52,23 @@ public class ForumActivity extends } @Override - protected @LayoutRes int getLayout() { + public void onCreate(Bundle state) { + super.onCreate(state); + + Intent i = getIntent(); + String groupName = i.getStringExtra(GROUP_NAME); + if (groupName != null) setTitle(groupName); + else loadNamedGroup(); + } + + @Override + protected void onNamedGroupLoaded(Forum forum) { + setTitle(forum.getName()); + } + + @Override + @LayoutRes + protected int getLayout() { return R.layout.activity_forum; } @@ -110,11 +129,18 @@ public class ForumActivity extends } @Override + protected int getMaxBodyLength() { + return MAX_FORUM_POST_BODY_LENGTH; + } + + @Override + @StringRes protected int getItemPostedString() { return R.string.forum_new_entry_posted; } @Override + @StringRes protected int getItemReceivedString() { return R.string.forum_new_entry_received; } @@ -125,24 +151,7 @@ public class ForumActivity extends @Override public void onClick(final DialogInterface dialog, int which) { - forumController.deleteGroupItem( - new UiResultExceptionHandler<Void, DbException>( - ForumActivity.this) { - @Override - public void onResultUi(Void v) { - Toast.makeText(ForumActivity.this, - R.string.forum_left_toast, - LENGTH_SHORT) - .show(); - } - - @Override - public void onExceptionUi( - DbException exception) { - // TODO proper error handling - dialog.dismiss(); - } - }); + deleteNamedGroup(); } }; AlertDialog.Builder builder = @@ -155,4 +164,25 @@ public class ForumActivity extends builder.show(); } + private void deleteNamedGroup() { + forumController.deleteNamedGroup( + new UiResultExceptionHandler<Void, DbException>( + ForumActivity.this) { + @Override + public void onResultUi(Void v) { + Toast.makeText(ForumActivity.this, + R.string.forum_left_toast, + LENGTH_SHORT) + .show(); + } + + @Override + public void onExceptionUi( + DbException exception) { + // TODO proper error handling + finish(); + } + }); + } + } diff --git a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java index 9375d0a35d40ab6b81245b784c4e8f555b4bd6ff..9ec21e76cfa49adf1da8d1a7b64171b3b6451821 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java +++ b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java @@ -15,11 +15,12 @@ import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumPost; import org.briarproject.api.forum.ForumPostHeader; import org.briarproject.api.lifecycle.LifecycleManager; -import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; import org.briarproject.util.StringUtils; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -48,7 +49,7 @@ public class ForumControllerImpl @Override public void onActivityResume() { super.onActivityResume(); - notificationManager.clearForumPostNotification(groupId); + notificationManager.clearForumPostNotification(getGroupId()); } @Override @@ -57,7 +58,7 @@ public class ForumControllerImpl if (e instanceof ForumPostReceivedEvent) { final ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e; - if (pe.getGroupId().equals(groupId)) { + if (pe.getGroupId().equals(getGroupId())) { LOG.info("Forum post received, adding..."); final ForumPostHeader fph = pe.getForumPostHeader(); listener.runOnUiThreadUnlessDestroyed(new Runnable() { @@ -72,35 +73,38 @@ public class ForumControllerImpl @Override protected Forum loadGroupItem() throws DbException { - return forumManager.getForum(groupId); + return forumManager.getForum(getGroupId()); } @Override protected Collection<ForumPostHeader> loadHeaders() throws DbException { - return forumManager.getPostHeaders(groupId); + return forumManager.getPostHeaders(getGroupId()); } @Override - protected void loadBodies(Collection<ForumPostHeader> headers) + protected Map<MessageId, String> loadBodies( + Collection<ForumPostHeader> headers) 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())); - bodyCache.put(header.getId(), body); + bodies.put(header.getId(), body); } } + return bodies; } @Override protected void markRead(MessageId id) throws DbException { - forumManager.setReadFlag(groupId, id, true); + forumManager.setReadFlag(getGroupId(), id, true); } @Override - protected ForumPost createLocalMessage(GroupId g, String body, + protected ForumPost createLocalMessage(String body, @Nullable MessageId parentId) throws DbException { - return forumManager.createLocalPost(groupId, body, parentId); + return forumManager.createLocalPost(getGroupId(), body, parentId); } @Override @@ -115,8 +119,8 @@ public class ForumControllerImpl } @Override - protected ForumEntry buildItem(ForumPostHeader header) { - return new ForumEntry(header, bodyCache.get(header.getId())); + protected ForumEntry buildItem(ForumPostHeader header, String body) { + return new ForumEntry(header, body); } } diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java index 0ad58273464064702ddee40a6cb7b7d5a3b7fe80..71a4865b516bf1e14e8b5d1ef9c6317179092c2a 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupActivity.java @@ -1,8 +1,9 @@ package org.briarproject.android.privategroup.conversation; +import android.content.Intent; import android.os.Bundle; import android.support.annotation.LayoutRes; -import android.support.annotation.Nullable; +import android.support.annotation.StringRes; import android.support.v7.app.ActionBar; import android.support.v7.widget.LinearLayoutManager; import android.view.Menu; @@ -18,11 +19,13 @@ import org.briarproject.api.privategroup.PrivateGroup; import javax.inject.Inject; +import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_POST_BODY_LENGTH; + public class GroupActivity extends ThreadListActivity<PrivateGroup, GroupMessageItem, GroupMessageHeader, GroupMessageAdapter> { @Inject - protected GroupController controller; + GroupController controller; @Override public void injectActivity(ActivityComponent component) { @@ -37,23 +40,18 @@ public class GroupActivity extends @Override public void onCreate(Bundle state) { super.onCreate(state); - list.setEmptyText(R.string.groups_no_messages); - } - @Override - protected @LayoutRes int getLayout() { - return R.layout.activity_forum; - } + Intent i = getIntent(); + String groupName = i.getStringExtra(GROUP_NAME); + if (groupName != null) setTitle(groupName); + loadNamedGroup(); - @Override - protected void setActionBarTitle(@Nullable String title) { - if (title != null) setTitle(title); - loadGroupItem(); + list.setEmptyText(R.string.groups_no_messages); } @Override - protected void onGroupItemLoaded(PrivateGroup group) { - super.onGroupItemLoaded(group); + protected void onNamedGroupLoaded(PrivateGroup group) { + setTitle(group.getName()); // Created by ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { @@ -62,6 +60,12 @@ public class GroupActivity extends } } + @Override + @LayoutRes + protected int getLayout() { + return R.layout.activity_forum; + } + @Override protected GroupMessageAdapter createAdapter( LinearLayoutManager layoutManager) { @@ -89,11 +93,18 @@ public class GroupActivity extends } @Override + protected int getMaxBodyLength() { + return MAX_GROUP_POST_BODY_LENGTH; + } + + @Override + @StringRes protected int getItemPostedString() { return R.string.groups_message_sent; } @Override + @StringRes protected int getItemReceivedString() { return R.string.groups_message_received; } diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java index 18a9bb57e357bb6945626a2e7a64f14e6299d0fc..dfadc9d414f846b91f6e29435f9444d19703b10a 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java @@ -15,10 +15,11 @@ import org.briarproject.api.privategroup.GroupMessage; import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.privategroup.PrivateGroupManager; -import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -47,7 +48,7 @@ public class GroupControllerImpl @Override public void onActivityResume() { super.onActivityResume(); - notificationManager.clearForumPostNotification(groupId); + notificationManager.clearForumPostNotification(getGroupId()); } @Override @@ -55,14 +56,14 @@ public class GroupControllerImpl super.eventOccurred(e); if (e instanceof GroupMessageAddedEvent) { - final GroupMessageAddedEvent pe = (GroupMessageAddedEvent) e; - if (!pe.isLocal() && pe.getGroupId().equals(groupId)) { + final GroupMessageAddedEvent gmae = (GroupMessageAddedEvent) e; + if (!gmae.isLocal() && gmae.getGroupId().equals(getGroupId())) { LOG.info("Group message received, adding..."); - final GroupMessageHeader fph = pe.getHeader(); + final GroupMessageHeader h = gmae.getHeader(); listener.runOnUiThreadUnlessDestroyed(new Runnable() { @Override public void run() { - listener.onHeaderReceived(fph); + listener.onHeaderReceived(h); } }); } @@ -71,35 +72,39 @@ public class GroupControllerImpl @Override protected PrivateGroup loadGroupItem() throws DbException { - return privateGroupManager.getPrivateGroup(groupId); + return privateGroupManager.getPrivateGroup(getGroupId()); } @Override protected Collection<GroupMessageHeader> loadHeaders() throws DbException { - return privateGroupManager.getHeaders(groupId); + return privateGroupManager.getHeaders(getGroupId()); } @Override - protected void loadBodies(Collection<GroupMessageHeader> headers) + protected Map<MessageId, String> loadBodies( + Collection<GroupMessageHeader> headers) throws DbException { + Map<MessageId, String> bodies = new HashMap<>(); for (GroupMessageHeader header : headers) { if (!bodyCache.containsKey(header.getId())) { String body = privateGroupManager.getMessageBody(header.getId()); - bodyCache.put(header.getId(), body); + bodies.put(header.getId(), body); } } + return bodies; } @Override protected void markRead(MessageId id) throws DbException { - privateGroupManager.setReadFlag(groupId, id, true); + privateGroupManager.setReadFlag(getGroupId(), id, true); } @Override - protected GroupMessage createLocalMessage(GroupId g, String body, + protected GroupMessage createLocalMessage(String body, @Nullable MessageId parentId) throws DbException { - return privateGroupManager.createLocalMessage(groupId, body, parentId); + return privateGroupManager + .createLocalMessage(getGroupId(), body, parentId); } @Override @@ -114,8 +119,9 @@ public class GroupControllerImpl } @Override - protected GroupMessageItem buildItem(GroupMessageHeader header) { - return new GroupMessageItem(header, bodyCache.get(header.getId())); + protected GroupMessageItem buildItem(GroupMessageHeader header, + String body) { + return new GroupMessageItem(header, body); } } diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java b/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java index 82e1fca18f4873f658c4f4b0f0559093384b9a51..01aae5c68b8f50689b88759e1ba8ee43d71d2a86 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java @@ -41,7 +41,7 @@ public abstract class ThreadItemAdapter<I extends ThreadItem> @Override public void onBindViewHolder(ThreadItemViewHolder<I> ui, int position) { - final I item = getVisibleItem(position); + I item = getVisibleItem(position); if (item == null) return; listener.onItemVisible(item); ui.bind(this, listener, item, position); @@ -151,10 +151,9 @@ public abstract class ThreadItemAdapter<I extends ThreadItem> } } - public void setReplyItemById(byte[] id) { - MessageId messageId = new MessageId(id); + public void setReplyItemById(MessageId id) { for (I item : items) { - if (item.getId().equals(messageId)) { + if (item.getId().equals(id)) { setReplyItem(item); break; } diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java index 529d588de0f5d54e7fa24199aa21c2f382888774..ab480a4bd04f84f0cc51517b6412d6e81518191a 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java @@ -21,10 +21,11 @@ import org.briarproject.android.threaded.ThreadListController.ThreadListListener import org.briarproject.android.view.BriarRecyclerView; import org.briarproject.android.view.TextInputView; import org.briarproject.android.view.TextInputView.TextInputListener; -import org.briarproject.api.clients.BaseGroup; +import org.briarproject.api.clients.NamedGroup; import org.briarproject.api.clients.PostHeader; import org.briarproject.api.db.DbException; import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; import java.util.ArrayList; import java.util.Collection; @@ -34,7 +35,7 @@ import static android.support.design.widget.Snackbar.make; import static android.view.View.GONE; import static android.view.View.VISIBLE; -public abstract class ThreadListActivity<G extends BaseGroup, I extends ThreadItem, H extends PostHeader, A extends ThreadItemAdapter<I>> +public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadItem, H extends PostHeader, A extends ThreadItemAdapter<I>> extends BriarActivity implements ThreadListListener<H>, TextInputListener, ThreadItemListener<I> { @@ -46,7 +47,7 @@ public abstract class ThreadListActivity<G extends BaseGroup, I extends ThreadIt protected BriarRecyclerView list; protected TextInputView textInput; protected GroupId groupId; - private byte[] replyId; + private MessageId replyId; protected abstract ThreadListController<G, I, H> getController(); @@ -63,8 +64,6 @@ public abstract class ThreadListActivity<G extends BaseGroup, I extends ThreadIt if (b == null) throw new IllegalStateException("No GroupId in intent."); groupId = new GroupId(b); getController().setGroupId(groupId); - String groupName = i.getStringExtra(GROUP_NAME); - setActionBarTitle(groupName); textInput = (TextInputView) findViewById(R.id.text_input_container); textInput.setVisibility(GONE); @@ -76,27 +75,23 @@ public abstract class ThreadListActivity<G extends BaseGroup, I extends ThreadIt list.setAdapter(adapter); if (state != null) { - replyId = state.getByteArray(KEY_REPLY_ID); + replyId = new MessageId(state.getByteArray(KEY_REPLY_ID)); } loadItems(); } - protected abstract @LayoutRes int getLayout(); + @LayoutRes + protected abstract int getLayout(); protected abstract A createAdapter(LinearLayoutManager layoutManager); - protected void setActionBarTitle(@Nullable String title) { - if (title != null) setTitle(title); - else loadGroupItem(); - } - - protected void loadGroupItem() { - getController().loadGroupItem( + protected void loadNamedGroup() { + getController().loadNamedGroup( new UiResultExceptionHandler<G, DbException>(this) { @Override public void onResultUi(G groupItem) { - onGroupItemLoaded(groupItem); + onNamedGroupLoaded(groupItem); } @Override @@ -107,11 +102,8 @@ public abstract class ThreadListActivity<G extends BaseGroup, I extends ThreadIt }); } - @CallSuper @UiThread - protected void onGroupItemLoaded(G groupItem) { - setTitle(groupItem.getName()); - } + protected abstract void onNamedGroupLoaded(G groupItem); private void loadItems() { getController().loadItems( @@ -208,7 +200,7 @@ public abstract class ThreadListActivity<G extends BaseGroup, I extends ThreadIt showTextInput(item); } - protected void displaySnackbarShort(int stringId) { + protected void displaySnackbarShort(@StringRes int stringId) { Snackbar snackbar = make(list, stringId, Snackbar.LENGTH_SHORT); snackbar.getView().setBackgroundResource(R.color.briar_primary); snackbar.show(); @@ -233,6 +225,10 @@ public abstract class ThreadListActivity<G extends BaseGroup, I extends ThreadIt public void onSendClick(String text) { if (text.trim().length() == 0) return; + if (text.length() > getMaxBodyLength()) { + displaySnackbarShort(R.string.text_too_long); + return; + } I replyItem = adapter.getReplyItem(); UiResultExceptionHandler<I, DbException> handler = new UiResultExceptionHandler<I, DbException>(this) { @@ -258,6 +254,8 @@ public abstract class ThreadListActivity<G extends BaseGroup, I extends ThreadIt adapter.setReplyItem(null); } + protected abstract int getMaxBodyLength(); + @Override public void onHeaderReceived(H header) { getController().loadItem(header, @@ -302,8 +300,10 @@ public abstract class ThreadListActivity<G extends BaseGroup, I extends ThreadIt } } - protected abstract @StringRes int getItemPostedString(); + @StringRes + protected abstract int getItemPostedString(); - protected abstract @StringRes int getItemReceivedString(); + @StringRes + protected abstract int getItemReceivedString(); } diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListController.java b/briar-android/src/org/briarproject/android/threaded/ThreadListController.java index ec876f3602c5e72375612d3a0e0983cbab7e2969..b62b6fd27788a2e7009f8b3a1eb59e443abb80b6 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListController.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListController.java @@ -6,21 +6,20 @@ import android.support.annotation.UiThread; import org.briarproject.android.DestroyableContext; import org.briarproject.android.controller.ActivityLifecycleController; import org.briarproject.android.controller.handler.ResultExceptionHandler; -import org.briarproject.api.clients.BaseGroup; +import org.briarproject.api.clients.NamedGroup; import org.briarproject.api.clients.PostHeader; import org.briarproject.api.db.DbException; -import org.briarproject.api.forum.ForumPostHeader; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; import java.util.Collection; -public interface ThreadListController<G extends BaseGroup, I extends ThreadItem, H extends PostHeader> +public interface ThreadListController<G extends NamedGroup, I extends ThreadItem, H extends PostHeader> extends ActivityLifecycleController { void setGroupId(GroupId groupId); - void loadGroupItem(ResultExceptionHandler<G, DbException> handler); + void loadNamedGroup(ResultExceptionHandler<G, DbException> handler); void loadItem(H header, ResultExceptionHandler<I, DbException> handler); @@ -35,7 +34,7 @@ public interface ThreadListController<G extends BaseGroup, I extends ThreadItem, void send(String body, @Nullable MessageId parentId, ResultExceptionHandler<I, DbException> handler); - void deleteGroupItem(ResultExceptionHandler<Void, DbException> handler); + void deleteNamedGroup(ResultExceptionHandler<Void, DbException> handler); interface ThreadListListener<H> extends DestroyableContext { @UiThread diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java index 3fbf2bccc6c94217842e60b790dc000cf0b1d236..c412d2eaacfd11c435a13b8623544baf257d017a 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java @@ -7,8 +7,8 @@ import android.support.annotation.Nullable; import org.briarproject.android.api.AndroidNotificationManager; import org.briarproject.android.controller.DbControllerImpl; import org.briarproject.android.controller.handler.ResultExceptionHandler; -import org.briarproject.api.clients.BaseGroup; import org.briarproject.api.clients.BaseMessage; +import org.briarproject.api.clients.NamedGroup; import org.briarproject.api.clients.PostHeader; import org.briarproject.api.crypto.CryptoExecutor; import org.briarproject.api.db.DatabaseExecutor; @@ -33,7 +33,7 @@ import java.util.logging.Logger; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; -public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends ThreadItem, H extends PostHeader, M extends BaseMessage> +public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends ThreadItem, H extends PostHeader, M extends BaseMessage> extends DbControllerImpl implements ThreadListController<G, I, H>, EventListener { @@ -47,7 +47,7 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th protected final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>(); - protected volatile GroupId groupId; + private volatile GroupId groupId; protected ThreadListListener<H> listener; @@ -110,7 +110,7 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th } @Override - public void loadGroupItem( + public void loadNamedGroup( final ResultExceptionHandler<G, DbException> handler) { checkGroupId(); runOnDbThread(new Runnable() { @@ -121,7 +121,8 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th G groupItem = loadGroupItem(); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) - LOG.info("Loading forum took " + duration + " ms"); + LOG.info( + "Loading named group took " + duration + " ms"); handler.onResult(groupItem); } catch (DbException e) { if (LOG.isLoggable(WARNING)) @@ -132,11 +133,7 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th }); } - /** - * This should only be run from the DbThread. - * - * @throws DbException - */ + @DatabaseExecutor protected abstract G loadGroupItem() throws DbException; @Override @@ -157,7 +154,8 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th // Load bodies now = System.currentTimeMillis(); - loadBodies(headers); + Map<MessageId, String> bodies = loadBodies(headers); + bodyCache.putAll(bodies); duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Loading bodies took " + duration + " ms"); @@ -173,19 +171,11 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th }); } - /** - * This should only be run from the DbThread. - * - * @throws DbException - */ + @DatabaseExecutor protected abstract Collection<H> loadHeaders() throws DbException; - /** - * This should only be run from the DbThread. - * - * @throws DbException - */ - protected abstract void loadBodies(Collection<H> headers) + @DatabaseExecutor + protected abstract Map<MessageId, String> loadBodies(Collection<H> headers) throws DbException; @Override @@ -196,8 +186,10 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th public void run() { LOG.info("Loading item..."); try { - loadBodies(Collections.singletonList(header)); - I item = buildItem(header); + String body = loadBodies(Collections.singletonList(header)) + .get(header.getId()); + bodyCache.put(header.getId(), body); + I item = buildItem(header, body); handler.onResult(item); } catch (DbException e) { if (LOG.isLoggable(WARNING)) @@ -234,11 +226,7 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th }); } - /** - * This should only be run from the DbThread. - * - * @throws DbException - */ + @DatabaseExecutor protected abstract void markRead(MessageId id) throws DbException; @Override @@ -255,9 +243,8 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th public void run() { LOG.info("Creating message..."); try { - M msg = createLocalMessage(groupId, body, parentId); - bodyCache.put(msg.getMessage().getId(), body); - storePost(msg, handler); + M msg = createLocalMessage(body, parentId); + storePost(msg, body, handler); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -267,15 +254,11 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th }); } - /** - * This should only be run from the DbThread. - * - * @throws DbException - */ - protected abstract M createLocalMessage(GroupId g, String body, + @DatabaseExecutor + protected abstract M createLocalMessage(String body, @Nullable MessageId parentId) throws DbException; - private void storePost(final M p, + private void storePost(final M msg, final String body, final ResultExceptionHandler<I, DbException> resultHandler) { runOnDbThread(new Runnable() { @Override @@ -283,11 +266,12 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th try { LOG.info("Store message..."); long now = System.currentTimeMillis(); - H h = addLocalMessage(p); + H header = addLocalMessage(msg); + bodyCache.put(msg.getMessage().getId(), body); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Storing message took " + duration + " ms"); - resultHandler.onResult(buildItem(h)); + resultHandler.onResult(buildItem(header, body)); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -297,15 +281,11 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th }); } - /** - * This should only be run from the DbThread. - * - * @throws DbException - */ + @DatabaseExecutor protected abstract H addLocalMessage(M message) throws DbException; @Override - public void deleteGroupItem( + public void deleteNamedGroup( final ResultExceptionHandler<Void, DbException> handler) { runOnDbThread(new Runnable() { @Override @@ -328,17 +308,13 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th }); } - /** - * This should only be run from the DbThread. - * - * @throws DbException - */ + @DatabaseExecutor protected abstract void deleteGroupItem(G groupItem) throws DbException; private List<I> buildItems(Collection<H> headers) { List<I> entries = new ArrayList<>(); for (H h : headers) { - entries.add(buildItem(h)); + entries.add(buildItem(h, bodyCache.get(h.getId()))); } return entries; } @@ -346,7 +322,12 @@ public abstract class ThreadListControllerImpl<G extends BaseGroup, I extends Th /** * When building the item, the body can be assumed to be cached */ - protected abstract I buildItem(H header); + protected abstract I buildItem(H header, String body); + + protected GroupId getGroupId() { + checkGroupId(); + return groupId; + } private void checkGroupId() { if (groupId == null) { diff --git a/briar-api/src/org/briarproject/api/blogs/Blog.java b/briar-api/src/org/briarproject/api/blogs/Blog.java index 5de781e7de8875d3ee305466b59432594fb7cd6f..14bfbd97bdb883ef97db58ef34a88b3132e6b7db 100644 --- a/briar-api/src/org/briarproject/api/blogs/Blog.java +++ b/briar-api/src/org/briarproject/api/blogs/Blog.java @@ -2,19 +2,22 @@ package org.briarproject.api.blogs; import org.briarproject.api.clients.BaseGroup; import org.briarproject.api.identity.Author; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.sharing.Shareable; import org.briarproject.api.sync.Group; import org.jetbrains.annotations.NotNull; +import javax.annotation.concurrent.ThreadSafe; + +@ThreadSafe +@NotNullByDefault public class Blog extends BaseGroup implements Shareable { private final String description; private final Author author; - public Blog(@NotNull Group group, @NotNull String name, - @NotNull String description, @NotNull Author author) { - super(group, name, null); - + public Blog(Group group, String name, String description, Author author) { + super(group, name); this.description = description; this.author = author; } diff --git a/briar-api/src/org/briarproject/api/clients/BaseGroup.java b/briar-api/src/org/briarproject/api/clients/BaseGroup.java index fe8a282f5b7fb50770be89e170dd3bf889d6171d..d2e1e8428a4a6442fd91f35d323f009f29021968 100644 --- a/briar-api/src/org/briarproject/api/clients/BaseGroup.java +++ b/briar-api/src/org/briarproject/api/clients/BaseGroup.java @@ -1,19 +1,22 @@ package org.briarproject.api.clients; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.sync.Group; import org.briarproject.api.sync.GroupId; import org.jetbrains.annotations.NotNull; +import javax.annotation.concurrent.ThreadSafe; + +@ThreadSafe +@NotNullByDefault public abstract class BaseGroup { private final Group group; private final String name; - private final byte[] salt; - public BaseGroup(@NotNull Group group, @NotNull String name, byte[] salt) { + public BaseGroup(Group group, String name) { this.group = group; this.name = name; - this.salt = salt; } @NotNull @@ -31,10 +34,6 @@ public abstract class BaseGroup { return name; } - public byte[] getSalt() { - return salt; - } - @Override public int hashCode() { return group.hashCode(); diff --git a/briar-api/src/org/briarproject/api/clients/NamedGroup.java b/briar-api/src/org/briarproject/api/clients/NamedGroup.java new file mode 100644 index 0000000000000000000000000000000000000000..c41429e7aca8f33963a68a0ba4db63c39d49225d --- /dev/null +++ b/briar-api/src/org/briarproject/api/clients/NamedGroup.java @@ -0,0 +1,29 @@ +package org.briarproject.api.clients; + +import org.briarproject.api.nullsafety.NotNullByDefault; +import org.briarproject.api.sync.Group; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.concurrent.ThreadSafe; + +@ThreadSafe +@NotNullByDefault +public abstract class NamedGroup extends BaseGroup { + + private final byte[] salt; + + public NamedGroup(@NotNull Group group, @NotNull String name, byte[] salt) { + super(group, name); + this.salt = salt; + } + + public byte[] getSalt() { + return salt; + } + + @Override + public boolean equals(Object o) { + return o instanceof NamedGroup && super.equals(o); + } + +} diff --git a/briar-api/src/org/briarproject/api/forum/Forum.java b/briar-api/src/org/briarproject/api/forum/Forum.java index cdaa091b98960d65cce7d150e0994a785ab8e28a..3cbf297a07792509062813248ff34cb4bd9a8873 100644 --- a/briar-api/src/org/briarproject/api/forum/Forum.java +++ b/briar-api/src/org/briarproject/api/forum/Forum.java @@ -1,10 +1,15 @@ package org.briarproject.api.forum; -import org.briarproject.api.clients.BaseGroup; +import org.briarproject.api.clients.NamedGroup; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.sharing.Shareable; import org.briarproject.api.sync.Group; -public class Forum extends BaseGroup implements Shareable { +import javax.annotation.concurrent.ThreadSafe; + +@ThreadSafe +@NotNullByDefault +public class Forum extends NamedGroup implements Shareable { public Forum(Group group, String name, byte[] salt) { super(group, name, salt); diff --git a/briar-api/src/org/briarproject/api/privategroup/PrivateGroup.java b/briar-api/src/org/briarproject/api/privategroup/PrivateGroup.java index f6d5862c78da7a15f9f81adaf41d62c501d6b551..3141ab40b7af64a8a8bc73622766576ff4a06e95 100644 --- a/briar-api/src/org/briarproject/api/privategroup/PrivateGroup.java +++ b/briar-api/src/org/briarproject/api/privategroup/PrivateGroup.java @@ -1,11 +1,16 @@ package org.briarproject.api.privategroup; -import org.briarproject.api.clients.BaseGroup; +import org.briarproject.api.clients.NamedGroup; import org.briarproject.api.identity.Author; +import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.sync.Group; import org.jetbrains.annotations.NotNull; -public class PrivateGroup extends BaseGroup { +import javax.annotation.concurrent.ThreadSafe; + +@ThreadSafe +@NotNullByDefault +public class PrivateGroup extends NamedGroup { private final Author author; diff --git a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java index ce47a5c3ee80adc3d6602ff0ec22d459f67a44a0..4983385c0a956514da6ebd08b7a13de43affd75e 100644 --- a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java +++ b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java @@ -154,7 +154,7 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager { } catch (GeneralSecurityException e) { throw new RuntimeException(e); } catch (FormatException e) { - throw new DbException(e); + throw new RuntimeException(e); } return p; }