mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 02:39:05 +01:00
Merge branch '393-message-tree' into 'master'
Sort threaded messages generic Constructed a generic that we can use to sort threaded messages. Closes #393 See merge request !203
This commit is contained in:
21
briar-api/src/org/briarproject/api/clients/MessageTree.java
Normal file
21
briar-api/src/org/briarproject/api/clients/MessageTree.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.api.clients;
|
||||
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
|
||||
public interface MessageTree<T extends MessageTree.MessageNode> {
|
||||
|
||||
void add(Collection<T> nodes);
|
||||
void clear();
|
||||
Collection<T> depthFirstOrder();
|
||||
void setComparator(Comparator<T> comparator);
|
||||
|
||||
interface MessageNode {
|
||||
MessageId getId();
|
||||
MessageId getParentId();
|
||||
long getTimestamp();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package org.briarproject.api.forum;
|
||||
|
||||
import org.briarproject.api.clients.MessageTree;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
public class ForumPostHeader {
|
||||
public class ForumPostHeader implements MessageTree.MessageNode {
|
||||
|
||||
private final MessageId id;
|
||||
private final MessageId parentId;
|
||||
|
||||
89
briar-core/src/org/briarproject/clients/MessageTreeImpl.java
Normal file
89
briar-core/src/org/briarproject/clients/MessageTreeImpl.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package org.briarproject.clients;
|
||||
|
||||
import org.briarproject.api.clients.MessageTree;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class MessageTreeImpl<T extends MessageTree.MessageNode>
|
||||
implements MessageTree<T> {
|
||||
|
||||
Map<MessageId, List<T>> nodeMap = new HashMap<MessageId, List<T>>();
|
||||
List<T> roots = new ArrayList<T>();
|
||||
|
||||
private Comparator<T> comparator = new Comparator<T>() {
|
||||
@Override
|
||||
public int compare(T o1, T o2) {
|
||||
return Long.valueOf(o1.getTimestamp()).compareTo(o2.getTimestamp());
|
||||
}
|
||||
};
|
||||
|
||||
@Inject
|
||||
public MessageTreeImpl() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
roots.clear();
|
||||
nodeMap.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Collection<T> nodes) {
|
||||
// add all nodes to the node map
|
||||
for (T node : nodes) {
|
||||
nodeMap.put(node.getId(), new ArrayList<T>());
|
||||
}
|
||||
// parse the nodes for dependencies
|
||||
for (T node : nodes) {
|
||||
if (node.getParentId() == null) {
|
||||
roots.add(node);
|
||||
}
|
||||
else {
|
||||
// retrieve the parent's children
|
||||
List<T> pChildren = nodeMap.get(node.getParentId());
|
||||
pChildren.add(node);
|
||||
}
|
||||
}
|
||||
sortAll();
|
||||
}
|
||||
|
||||
private void sortAll() {
|
||||
Collections.sort(roots, comparator);
|
||||
// Sort all the sub-lists
|
||||
for (Map.Entry<MessageId, List<T>> entry: nodeMap.entrySet()) {
|
||||
Collections.sort(entry.getValue(), comparator);
|
||||
}
|
||||
}
|
||||
|
||||
private void traverse(List<T> list, T node) {
|
||||
list.add(node);
|
||||
for (T child : nodeMap.get(node.getId())) {
|
||||
traverse(list, child);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> depthFirstOrder() {
|
||||
List<T> orderedList = new ArrayList<T>();
|
||||
for (T root : roots) {
|
||||
traverse(orderedList, root);
|
||||
}
|
||||
return Collections.unmodifiableList(orderedList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComparator(Comparator<T> comparator) {
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package org.briarproject.forum;
|
||||
|
||||
import org.briarproject.api.clients.ClientHelper;
|
||||
import org.briarproject.api.clients.MessageQueueManager;
|
||||
import org.briarproject.api.clients.MessageTree;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.data.MetadataEncoder;
|
||||
@@ -9,12 +10,14 @@ import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.forum.ForumFactory;
|
||||
import org.briarproject.api.forum.ForumManager;
|
||||
import org.briarproject.api.forum.ForumPostFactory;
|
||||
import org.briarproject.api.forum.ForumPostHeader;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.identity.AuthorFactory;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.sync.GroupFactory;
|
||||
import org.briarproject.api.sync.ValidationManager;
|
||||
import org.briarproject.api.system.Clock;
|
||||
import org.briarproject.clients.MessageTreeImpl;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
@@ -100,4 +103,11 @@ public class ForumModule {
|
||||
|
||||
return forumSharingManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
MessageTree<ForumPostHeader> provideForumMessageTree(
|
||||
MessageTreeImpl<ForumPostHeader> messageTree) {
|
||||
return messageTree;
|
||||
}
|
||||
}
|
||||
|
||||
102
briar-tests/src/org/briarproject/clients/MessageTreeTest.java
Normal file
102
briar-tests/src/org/briarproject/clients/MessageTreeTest.java
Normal file
@@ -0,0 +1,102 @@
|
||||
package org.briarproject.clients;
|
||||
|
||||
import org.briarproject.TestUtils;
|
||||
import org.briarproject.api.clients.MessageTree;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class MessageTreeTest {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(MessageTreeTest.class.getName());
|
||||
|
||||
private MessageTree<TestNode> tree;
|
||||
|
||||
@Test
|
||||
public void testMessageTree() {
|
||||
tree = new MessageTreeImpl<>();
|
||||
testSimpleTree();
|
||||
tree.clear();
|
||||
testSimpleTree();
|
||||
}
|
||||
|
||||
private void testSimpleTree() {
|
||||
TestNode[] nodes = new TestNode[5];
|
||||
for (int i = 0; i < nodes.length; i++) {
|
||||
nodes[i] = new TestNode();
|
||||
}
|
||||
/*
|
||||
Construct the following tree:
|
||||
4
|
||||
1 ->
|
||||
0 ->
|
||||
2
|
||||
3
|
||||
*/
|
||||
nodes[0].setParentId(nodes[1].getId());
|
||||
nodes[2].setParentId(nodes[0].getId());
|
||||
nodes[3].setParentId(nodes[1].getId());
|
||||
long timestamp = System.currentTimeMillis();
|
||||
nodes[4].setTimestamp(timestamp - 5);
|
||||
nodes[1].setTimestamp(timestamp - 4);
|
||||
nodes[0].setTimestamp(timestamp - 3);
|
||||
nodes[3].setTimestamp(timestamp - 2);
|
||||
nodes[2].setTimestamp(timestamp - 1);
|
||||
// add all nodes except the last one
|
||||
tree.add(Arrays.asList(Arrays.copyOf(nodes, nodes.length-1)));
|
||||
tree.add(Collections.singletonList(nodes[nodes.length-1]));
|
||||
TestNode[] sortedNodes = tree.depthFirstOrder().toArray(new TestNode[5]);
|
||||
assertEquals(nodes[4], sortedNodes[0]);
|
||||
assertEquals(nodes[1], sortedNodes[1]);
|
||||
assertEquals(nodes[0], sortedNodes[2]);
|
||||
assertEquals(nodes[2], sortedNodes[3]);
|
||||
assertEquals(nodes[3], sortedNodes[4]);
|
||||
}
|
||||
|
||||
private void printNodes(TestNode[] nodes, TestNode[] sortedNodes) {
|
||||
for (int i = 0; i < sortedNodes.length; i++) {
|
||||
for (int j = 0; j < nodes.length; j++) {
|
||||
if (sortedNodes[i] == nodes[j]) {
|
||||
LOG.info("index: " + j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TestNode implements MessageTree.MessageNode {
|
||||
|
||||
private final MessageId id = new MessageId(TestUtils.getRandomId());
|
||||
private MessageId parentId;
|
||||
private long timestamp;
|
||||
|
||||
@Override
|
||||
public MessageId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageId getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setParentId(MessageId parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user