diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml
index ed7498d..9092fc0 100644
--- a/nbproject/build-impl.xml
+++ b/nbproject/build-impl.xml
@@ -80,9 +80,12 @@ is divided into following sections:
-
-
-
+
+
+
+
+
+
@@ -1199,11 +1202,14 @@ is divided into following sections:
-
+
+
+
+
-
+
@@ -1277,7 +1283,7 @@ is divided into following sections:
-
+
Some tests failed; see details above.
diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties
index 2dd29bc..cc9dd93 100644
--- a/nbproject/genfiles.properties
+++ b/nbproject/genfiles.properties
@@ -4,5 +4,5 @@ build.xml.stylesheet.CRC32=8064a381@1.68.1.46
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=7e563d6e
-nbproject/build-impl.xml.script.CRC32=5c6dd9f7
-nbproject/build-impl.xml.stylesheet.CRC32=5a01deb7@1.68.1.46
+nbproject/build-impl.xml.script.CRC32=934ae712
+nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.74.1.48
diff --git a/src/kademlia/core/KadServer.java b/src/kademlia/core/KadServer.java
index cea718f..1512d8f 100644
--- a/src/kademlia/core/KadServer.java
+++ b/src/kademlia/core/KadServer.java
@@ -1,8 +1,3 @@
-/**
- * @author Joshua Kissoon
- * @created 20140215
- * @desc This server handles sending and receiving messages
- */
package kademlia.core;
import java.io.ByteArrayInputStream;
@@ -23,6 +18,11 @@ import kademlia.message.MessageFactory;
import kademlia.node.Node;
import kademlia.operation.Receiver;
+/**
+ * @author Joshua Kissoon
+ * @created 20140215
+ * @desc This server handles sending and receiving messages
+ */
public class KadServer
{
diff --git a/src/kademlia/core/Kademlia.java b/src/kademlia/core/Kademlia.java
index dd82451..1186422 100644
--- a/src/kademlia/core/Kademlia.java
+++ b/src/kademlia/core/Kademlia.java
@@ -16,7 +16,8 @@ import kademlia.node.NodeId;
import kademlia.operation.ConnectOperation;
import kademlia.operation.ContentLookupOperation;
import kademlia.operation.Operation;
-import kademlia.operation.RefreshOperation;
+import kademlia.operation.BucketRefreshOperation;
+import kademlia.operation.KadRefreshOperation;
import kademlia.operation.StoreOperation;
/**
@@ -79,7 +80,7 @@ public class Kademlia
try
{
/* Runs a RefreshOperation to refresh K-Buckets and stored content */
- new RefreshOperation(server, localNode).execute();
+ new BucketRefreshOperation(server, localNode).execute();
}
catch (IOException e)
{
@@ -174,6 +175,16 @@ public class Kademlia
return contentFound;
}
+ /**
+ * Allow the user of the System to call refresh even out of the normal Kad refresh timing
+ *
+ * @throws java.io.IOException
+ */
+ public void refresh() throws IOException
+ {
+ new KadRefreshOperation(server, localNode).execute();
+ }
+
/**
* @return String The ID of the owner of this local network
*/
diff --git a/src/kademlia/node/NodeId.java b/src/kademlia/node/NodeId.java
index 21b9b1f..515de7c 100644
--- a/src/kademlia/node/NodeId.java
+++ b/src/kademlia/node/NodeId.java
@@ -42,11 +42,16 @@ public class NodeId implements Streamable
new Random().nextBytes(keyBytes);
}
+ /**
+ * Generate the NodeId from a given byte[]
+ *
+ * @param bytes
+ */
public NodeId(byte[] bytes)
{
if (bytes.length != ID_LENGTH / 8)
{
- throw new IllegalArgumentException("Specified Data need to be " + (ID_LENGTH / 8) + " characters long.");
+ throw new IllegalArgumentException("Specified Data need to be " + (ID_LENGTH / 8) + " characters long. Data Given: '" + new String(bytes) + "'");
}
this.keyBytes = bytes;
}
diff --git a/src/kademlia/operation/RefreshOperation.java b/src/kademlia/operation/BucketRefreshOperation.java
similarity index 54%
rename from src/kademlia/operation/RefreshOperation.java
rename to src/kademlia/operation/BucketRefreshOperation.java
index 3f0d911..c7c15b3 100644
--- a/src/kademlia/operation/RefreshOperation.java
+++ b/src/kademlia/operation/BucketRefreshOperation.java
@@ -1,23 +1,25 @@
package kademlia.operation;
import java.io.IOException;
+import java.util.List;
import kademlia.core.KadServer;
import kademlia.node.Node;
+import kademlia.node.NodeId;
/**
- * At each time interval t, nodes need to refresh their K-Buckets and their Data Storage
- * This Operation will manage refreshing the K-Buckets and data storage
+ * At each time interval t, nodes need to refresh their K-Buckets
+ * This operation takes care of refreshing this node's K-Buckets
*
* @author Joshua Kissoon
* @created 20140224
*/
-public class RefreshOperation implements Operation
+public class BucketRefreshOperation implements Operation
{
private final KadServer server;
private final Node localNode;
- public RefreshOperation(KadServer server, Node localNode)
+ public BucketRefreshOperation(KadServer server, Node localNode)
{
this.server = server;
this.localNode = localNode;
@@ -26,6 +28,17 @@ public class RefreshOperation implements Operation
@Override
public synchronized void execute() throws IOException
{
+ System.out.println("Bucket Refresh Operation Started");
+
+ /* Get a list of NodeIds for each distance from the LocalNode NodeId */
+ List refreshIds = this.localNode.getRoutingTable().getRefreshList();
+
+ /* Test whether each nodeId in this list is a different distance from our current NID */
+ for (NodeId nid : refreshIds)
+ {
+ System.out.println(nid.xor(localNode.getNodeId()).getFirstSetBitIndex());
+ }
+
/* @todo Do a Node Lookup operation to refresh K-Buckets */
new NodeLookupOperation(this.server, this.localNode, this.localNode.getNodeId()).execute();
@@ -34,9 +47,5 @@ public class RefreshOperation implements Operation
* This is better than asking closest nodes for data,
* since the data may not always come from the closest nodes
*/
- /**
- * @todo Delete any content on this node that this node is not one of the K-Closest nodes to
- * @todo Delete any expired content
- */
}
}
diff --git a/src/kademlia/operation/ContentRefreshOperation.java b/src/kademlia/operation/ContentRefreshOperation.java
new file mode 100644
index 0000000..774ec39
--- /dev/null
+++ b/src/kademlia/operation/ContentRefreshOperation.java
@@ -0,0 +1,19 @@
+package kademlia.operation;
+
+/**
+ * Refresh the data on this node by sending the data to the K-Closest nodes to the data
+ *
+ * @author Joshua Kissoon
+ * @since 20140306
+ */
+public class ContentRefreshOperation
+{
+
+ public void execute()
+ {
+ /**
+ * @todo Delete any content on this node that this node is not one of the K-Closest nodes to
+ * @todo Delete any expired content
+ */
+ }
+}
diff --git a/src/kademlia/operation/KadRefreshOperation.java b/src/kademlia/operation/KadRefreshOperation.java
new file mode 100644
index 0000000..a56de57
--- /dev/null
+++ b/src/kademlia/operation/KadRefreshOperation.java
@@ -0,0 +1,33 @@
+package kademlia.operation;
+
+import java.io.IOException;
+import kademlia.core.KadServer;
+import kademlia.node.Node;
+
+/**
+ * An operation that handles refreshing the entire Kademlia Systems including buckets and content
+ *
+ * @author Joshua Kissoon
+ * @since 20140306
+ */
+public class KadRefreshOperation implements Operation
+{
+
+ private final KadServer server;
+ private final Node localNode;
+
+ public KadRefreshOperation(KadServer server, Node localNode)
+ {
+ this.server = server;
+ this.localNode = localNode;
+ }
+
+ @Override
+ public void execute() throws IOException
+ {
+ /* Run our BucketRefreshOperation to refresh buckets */
+ new BucketRefreshOperation(server, localNode).execute();
+
+ /* After buckets have been refreshed, we refresh content */
+ }
+}
diff --git a/src/kademlia/routing/RoutingTable.java b/src/kademlia/routing/RoutingTable.java
index fe5ad63..261b97c 100644
--- a/src/kademlia/routing/RoutingTable.java
+++ b/src/kademlia/routing/RoutingTable.java
@@ -6,6 +6,7 @@
package kademlia.routing;
import java.util.ArrayList;
+import java.util.BitSet;
import java.util.List;
import kademlia.node.Node;
import kademlia.node.NodeId;
@@ -73,7 +74,7 @@ public class RoutingTable
* @param target The NodeId to find contacts close to
* @param num The number of contacts to find
*
- * @return List A List of num contacts closest to target
+ * @return List A List of contacts closest to target
*/
public List findClosest(NodeId target, int num)
{
@@ -145,7 +146,10 @@ public class RoutingTable
return closest;
}
- public List getAllNodes()
+ /**
+ * @return List A List of all Nodes in this RoutingTable
+ */
+ public List getAllNodes()
{
List nodes = new ArrayList<>();
@@ -157,6 +161,53 @@ public class RoutingTable
return nodes;
}
+ /**
+ * Each bucket need to be refreshed at every time interval t.
+ * Here we return an identifier in each bucket's range;
+ * this identifier will then be used to look for nodes closest to this identifier
+ * allowing the bucket to be refreshed.
+ *
+ * The first bucket containing only the local node is skipped.
+ *
+ * @return List A list of NodeIds for each distance (1 - NodeId.ID_LENGTH) from the LocalNode NodeId
+ */
+ public List getRefreshList()
+ {
+ List refreshList = new ArrayList<>(NodeId.ID_LENGTH);
+
+ for (int i = 1; i < NodeId.ID_LENGTH; i++)
+ {
+ /* Construct a NodeId that is i bits away from the current node Id */
+ System.out.println("\nGenerating a new NodeId ");
+ BitSet temp = new BitSet(NodeId.ID_LENGTH);
+
+ /* Fill the first i parts with 1 */
+ for (int j = 0; j < i; j++)
+ {
+ System.out.println("Got here 1 - j: " + j);
+ temp.set(j);
+ }
+
+ /* Fill the last parts with 0 */
+ for (int j = i; j < NodeId.ID_LENGTH; j++)
+ {
+ System.out.println("Got here 2 - j: " + j);
+ temp.set(j, false);
+ }
+
+ /**
+ * LocalNode NodeId xor the Bits we generated will give a new NodeId
+ * i distance away from our LocalNode NodeId, we add this to our refreshList
+ */
+ System.out.println("Bits: " + temp);
+ NodeId nid = this.localNode.getNodeId().xor(new NodeId(temp.toByteArray()));
+ System.out.println("NodeId: " + nid);
+ refreshList.add(nid);
+ }
+
+ return refreshList;
+ }
+
@Override
public String toString()
{
diff --git a/src/kademlia/tests/RefreshOperationTest.java b/src/kademlia/tests/RefreshOperationTest.java
new file mode 100644
index 0000000..0758b24
--- /dev/null
+++ b/src/kademlia/tests/RefreshOperationTest.java
@@ -0,0 +1,45 @@
+package kademlia.tests;
+
+import java.io.IOException;
+import java.util.List;
+import kademlia.core.GetParameter;
+import kademlia.core.Kademlia;
+import kademlia.dht.KadContent;
+import kademlia.node.NodeId;
+
+/**
+ * Testing sending and receiving content between 2 Nodes on a network
+ *
+ * @author Joshua Kissoon
+ * @since 20140224
+ */
+public class RefreshOperationTest
+{
+
+ public static void main(String[] args)
+ {
+ try
+ {
+ /* Setting up 2 Kad networks */
+ Kademlia kad1 = new Kademlia("JoshuaK", new NodeId("ASF45678947584567467"), 7574);
+ Kademlia kad2 = new Kademlia("Crystal", new NodeId("ASERTKJDHGVHERJHGFLK"), 7572);
+ kad2.connect(kad1.getNode());
+
+ /* Lets create the content and share it */
+ DHTContentImpl c = new DHTContentImpl(kad2.getOwnerId(), "Some Data");
+ kad2.put(c);
+
+ /* Lets retrieve the content */
+ GetParameter gp = new GetParameter(c.getKey());
+ gp.setType(DHTContentImpl.TYPE);
+ gp.setOwnerId(c.getOwnerId());
+ List conte = kad2.get(gp, 1);
+
+ kad2.refresh();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}