From 25222e5ea92c4bfee161f08965b56f2c11e54df4 Mon Sep 17 00:00:00 2001 From: "Nelson R. Perez" Date: Tue, 18 Sep 2018 11:15:07 -0500 Subject: [PATCH] Introducing the NodeProvider interface and its implementation LatencyNodeProvider --- .../network/LatencyNodeProvider.java | 55 ++++++++++++++++ .../graphenej/network/NodeProvider.java | 38 +++++++++++ .../network/LatencyNodeProviderTest.java | 63 +++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 graphenej/src/main/java/cy/agorise/graphenej/network/LatencyNodeProvider.java create mode 100644 graphenej/src/main/java/cy/agorise/graphenej/network/NodeProvider.java create mode 100644 graphenej/src/test/java/cy/agorise/graphenej/network/LatencyNodeProviderTest.java diff --git a/graphenej/src/main/java/cy/agorise/graphenej/network/LatencyNodeProvider.java b/graphenej/src/main/java/cy/agorise/graphenej/network/LatencyNodeProvider.java new file mode 100644 index 0000000..a201bbf --- /dev/null +++ b/graphenej/src/main/java/cy/agorise/graphenej/network/LatencyNodeProvider.java @@ -0,0 +1,55 @@ +package cy.agorise.graphenej.network; + +import java.util.Arrays; +import java.util.List; +import java.util.PriorityQueue; + +public class LatencyNodeProvider implements NodeProvider { + private PriorityQueue mFullNodeHeap; + + public LatencyNodeProvider(){ + mFullNodeHeap = new PriorityQueue<>(); + } + + @Override + public FullNode getBestNode() { + return mFullNodeHeap.peek(); + } + + @Override + public void addNode(FullNode fullNode) { + mFullNodeHeap.add(fullNode); + } + + @Override + public boolean updateNode(FullNode fullNode) { + if(mFullNodeHeap.remove(fullNode)){ + return mFullNodeHeap.offer(fullNode); + }else{ + return false; + } + } + + /** + * Updates an existing node with the new latency value. + * + * @param fullNode Existing full node instance + * @param latency New latency measurement + * @return True if the node priority was updated successfully + */ + public boolean updateNode(FullNode fullNode, int latency){ + if(mFullNodeHeap.remove(fullNode)){ + fullNode.addLatencyValue(latency); + return mFullNodeHeap.add(fullNode); + }else{ + return false; + } + } + + @Override + public List getSortedNodes() { + FullNode[] nodeArray = mFullNodeHeap.toArray(new FullNode[mFullNodeHeap.size()]); + Arrays.sort(nodeArray); + return Arrays.asList(nodeArray); + } +} diff --git a/graphenej/src/main/java/cy/agorise/graphenej/network/NodeProvider.java b/graphenej/src/main/java/cy/agorise/graphenej/network/NodeProvider.java new file mode 100644 index 0000000..1a380a5 --- /dev/null +++ b/graphenej/src/main/java/cy/agorise/graphenej/network/NodeProvider.java @@ -0,0 +1,38 @@ +package cy.agorise.graphenej.network; + +import java.util.List; + +/** + * Interface used to describe the high level characteristics of a class that will + * hold and manage a list of {@link FullNode} instances. + * + * The idea is that the class implementing this interface should provide node instances + * and thus URLs for the {@link cy.agorise.graphenej.api.android.NetworkService} with + * different sorting heuristics. + */ +public interface NodeProvider { + + /** + * Returns the node with the best characteristics. + * @return A FullNode instance + */ + FullNode getBestNode(); + + /** + * Adds a new node to the queue + * @param fullNode {@link FullNode} instance to add. + */ + void addNode(FullNode fullNode); + + /** + * Updates the rating of a specific node that is already in the NodeProvider + * @param fullNode + */ + boolean updateNode(FullNode fullNode); + + /** + * Returns an ordered list of {@link FullNode} instances. + * @return + */ + List getSortedNodes(); +} diff --git a/graphenej/src/test/java/cy/agorise/graphenej/network/LatencyNodeProviderTest.java b/graphenej/src/test/java/cy/agorise/graphenej/network/LatencyNodeProviderTest.java new file mode 100644 index 0000000..23c94b1 --- /dev/null +++ b/graphenej/src/test/java/cy/agorise/graphenej/network/LatencyNodeProviderTest.java @@ -0,0 +1,63 @@ +package cy.agorise.graphenej.network; + +import junit.framework.Assert; + +import org.junit.Test; + +import java.util.List; + +public class LatencyNodeProviderTest { + private FullNode nodeA, nodeB, nodeC; + private LatencyNodeProvider latencyNodeProvider; + + private void setupTestNodes(){ + // Creating 3 nodes with different latencies + nodeA = new FullNode("wss://nodeA"); + nodeB = new FullNode("wss://nodeB"); + nodeC = new FullNode("wss://nodeC"); + + // Adding latencies measurements + nodeA.addLatencyValue(100); + nodeB.addLatencyValue(50); + nodeC.addLatencyValue(20); + + // Creating a node provider and adding the nodes created previously + latencyNodeProvider = new LatencyNodeProvider(); + latencyNodeProvider.addNode(nodeC); + latencyNodeProvider.addNode(nodeA); + latencyNodeProvider.addNode(nodeB); + } + + @Test + public void testSorting(){ + setupTestNodes(); + + // Confirming that the best node is nodeC + FullNode bestNode = latencyNodeProvider.getBestNode(); + System.out.println("Best node latency: "+bestNode.getLatencyValue()); + Assert.assertSame("Check that the best node is nodeC", nodeC, bestNode); + + // Improving nodeA score by feeding it with new better latency measurements + latencyNodeProvider.updateNode(nodeA, 10); + latencyNodeProvider.updateNode(nodeA, 10); + latencyNodeProvider.updateNode(nodeA, 10); + latencyNodeProvider.updateNode(nodeA, 10); + + // Updating the nodeA position in the provider + latencyNodeProvider.updateNode(nodeA); + bestNode = latencyNodeProvider.getBestNode(); + System.out.println("Best node latency after update: "+bestNode.getLatencyValue()); + Assert.assertSame("Check that the best node now is the nodeA", nodeA, bestNode); + } + + @Test + public void testSortedList(){ + setupTestNodes(); + + // Confirming that the getSortedNodes gives us a sorted list of nodes in increasing latency order + List fullNodeList = latencyNodeProvider.getSortedNodes(); + Assert.assertSame(nodeC, fullNodeList.get(0)); + Assert.assertSame(nodeB, fullNodeList.get(1)); + Assert.assertSame(nodeA, fullNodeList.get(2)); + } +}