Now we use a StorageEntry class to send data accross peers

Out KadContent interface also now specifies a set of methods to force it's subclasses to do their own toByte conversions
This commit is contained in:
Joshua Kissoon 2014-04-02 18:05:14 +05:30
parent 9190b122c7
commit 3e236f4d17
15 changed files with 111 additions and 91 deletions

View File

@ -19,6 +19,7 @@ import kademlia.core.KadConfiguration;
import kademlia.core.KadServer; import kademlia.core.KadServer;
import kademlia.dht.DHT; import kademlia.dht.DHT;
import kademlia.dht.KadContent; import kademlia.dht.KadContent;
import kademlia.dht.StorageEntry;
import kademlia.exceptions.RoutingException; import kademlia.exceptions.RoutingException;
import kademlia.message.MessageFactory; import kademlia.message.MessageFactory;
import kademlia.node.Node; import kademlia.node.Node;
@ -280,7 +281,7 @@ public class Kademlia
* *
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public List<KadContent> get(GetParameter param, int numResultsReq) throws NoSuchElementException, IOException public List<StorageEntry> get(GetParameter param, int numResultsReq) throws NoSuchElementException, IOException
{ {
List contentFound; List contentFound;
if (this.dht.contains(param)) if (this.dht.contains(param))

View File

@ -19,26 +19,16 @@ public class GetParameter
private String ownerId = null; private String ownerId = null;
private String type = null; private String type = null;
/**
* Construct a GetParameter to search for data by NodeId
*
* @param key
*/
public GetParameter(NodeId key)
{
this.key = key;
}
/** /**
* Construct a GetParameter to search for data by NodeId and owner * Construct a GetParameter to search for data by NodeId and owner
* *
* @param key * @param key
* @param owner * @param type
*/ */
public GetParameter(NodeId key, String owner) public GetParameter(NodeId key, String type)
{ {
this(key); this.key = key;
this.ownerId = owner; this.type = type;
} }
/** /**

View File

@ -27,7 +27,7 @@ public class DHT
{ {
private transient StorageEntryManager entriesManager; private transient StorageEntryManager entriesManager;
private transient KadSerializer<KadContent> contentSerializer = null; private transient KadSerializer<StorageEntry> serializer = null;
private transient KadConfiguration config; private transient KadConfiguration config;
private final String ownerId; private final String ownerId;
@ -62,14 +62,14 @@ public class DHT
* *
* @return The new ContentSerializer * @return The new ContentSerializer
*/ */
public KadSerializer<KadContent> getContentSerializer() public KadSerializer<StorageEntry> getSerializer()
{ {
if (null == contentSerializer) if (null == serializer)
{ {
contentSerializer = new JsonSerializer<>(); serializer = new JsonSerializer<>();
} }
return contentSerializer; return serializer;
} }
/** /**
@ -79,22 +79,20 @@ public class DHT
* *
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public void store(KadContent content) throws IOException public void store(StorageEntry content) throws IOException
{ {
/* Keep track of this content in the entries manager */ /* Keep track of this content in the entries manager */
try try
{ {
StorageEntryMetadata sEntry = this.entriesManager.put(content); StorageEntryMetadata sEntry = this.entriesManager.put(content.getContentMetadata());
/* Now we store the content locally in a file */ /* Now we store the content locally in a file */
String contentStorageFolder = this.getContentStorageFolderName(content.getKey()); String contentStorageFolder = this.getContentStorageFolderName(content.getContentMetadata().getKey());
try (FileOutputStream fout = new FileOutputStream(contentStorageFolder + File.separator + sEntry.hashCode() + ".kct"); try (FileOutputStream fout = new FileOutputStream(contentStorageFolder + File.separator + sEntry.hashCode() + ".kct");
DataOutputStream dout = new DataOutputStream(fout)) DataOutputStream dout = new DataOutputStream(fout))
{ {
byte[] data = content.toBytes(); this.getSerializer().write(content, dout);
dout.writeInt(data.length);
dout.write(data);
} }
} }
catch (ContentExistException e) catch (ContentExistException e)
@ -103,6 +101,11 @@ public class DHT
} }
} }
public void store(KadContent content) throws IOException
{
this.store(new StorageEntry(content));
}
/** /**
* Retrieves a Content from local storage * Retrieves a Content from local storage
* *
@ -111,15 +114,11 @@ public class DHT
* *
* @return A KadContent object * @return A KadContent object
*/ */
private byte[] retrieve(NodeId key, int hashCode) throws FileNotFoundException, IOException, ClassNotFoundException private StorageEntry retrieve(NodeId key, int hashCode) throws FileNotFoundException, IOException, ClassNotFoundException
{ {
String folder = this.getContentStorageFolderName(key); String folder = this.getContentStorageFolderName(key);
DataInputStream din = new DataInputStream(new FileInputStream(folder + File.separator + hashCode + ".kct")); DataInputStream din = new DataInputStream(new FileInputStream(folder + File.separator + hashCode + ".kct"));
int length = din.readInt(); return this.getSerializer().read(din);
byte[] data = new byte[length];
din.read(data);
return data;
} }
/** /**
@ -143,7 +142,7 @@ public class DHT
* *
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public byte[] get(StorageEntryMetadata entry) throws IOException, NoSuchElementException public StorageEntry get(StorageEntryMetadata entry) throws IOException, NoSuchElementException
{ {
try try
{ {
@ -172,7 +171,7 @@ public class DHT
* *
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public byte[] get(GetParameter param) throws NoSuchElementException, IOException public StorageEntry get(GetParameter param) throws NoSuchElementException, IOException
{ {
/* Load a KadContent if any exist for the given criteria */ /* Load a KadContent if any exist for the given criteria */
try try

View File

@ -1,11 +1,14 @@
package kademlia.dht; package kademlia.dht;
import com.google.gson.Gson;
import kademlia.node.NodeId; import kademlia.node.NodeId;
/** /**
* Any piece of content that needs to be stored on the DHT * Any piece of content that needs to be stored on the DHT
* *
* @author Joshua Kissoon * @author Joshua Kissoon
* @param <T>
*
* @since 20140224 * @since 20140224
*/ */
public interface KadContent public interface KadContent
@ -42,13 +45,7 @@ public interface KadContent
*/ */
public String getOwnerId(); public String getOwnerId();
public default byte[] toBytes() public byte[] toBytes();
{
return new byte[2];
}
public default void fromBytes(byte[] data)
{
} public KadContent fromBytes(byte[] data);
} }

View File

@ -8,16 +8,28 @@ package kademlia.dht;
*/ */
public class StorageEntry public class StorageEntry
{ {
private byte[] content;
private StorageEntryMetadata metadata; private final byte[] content;
private final StorageEntryMetadata metadata;
public StorageEntry(KadContent content) public StorageEntry(KadContent content)
{ {
this(content, new StorageEntryMetadata(content));
} }
public StorageEntry(KadContent content, StorageEntryMetadata metadata) public StorageEntry(KadContent content, StorageEntryMetadata metadata)
{ {
this.content = content.g this.content = content.toBytes();
this.metadata = metadata;
}
public byte[] getContent()
{
return this.content;
}
public StorageEntryMetadata getContentMetadata()
{
return this.metadata;
} }
} }

View File

@ -3,7 +3,7 @@ package kademlia.message;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import kademlia.dht.KadContent; import kademlia.dht.StorageEntry;
import kademlia.node.Node; import kademlia.node.Node;
import kademlia.serializer.JsonSerializer; import kademlia.serializer.JsonSerializer;
@ -18,7 +18,7 @@ public class ContentMessage implements Message
public static final byte CODE = 0x04; public static final byte CODE = 0x04;
private byte[] content; private StorageEntry content;
private Node origin; private Node origin;
/** /**
@ -26,7 +26,7 @@ public class ContentMessage implements Message
* @param content The content to be stored * @param content The content to be stored
* *
*/ */
public ContentMessage(Node origin, byte[] content) public ContentMessage(Node origin, StorageEntry content)
{ {
this.content = content; this.content = content;
this.origin = origin; this.origin = origin;
@ -43,8 +43,7 @@ public class ContentMessage implements Message
this.origin.toStream(out); this.origin.toStream(out);
/* Serialize the KadContent, then send it to the stream */ /* Serialize the KadContent, then send it to the stream */
out.writeInt(content.length); new JsonSerializer<StorageEntry>().write(content, out);
out.write(content);
} }
@Override @Override
@ -52,9 +51,14 @@ public class ContentMessage implements Message
{ {
this.origin = new Node(in); this.origin = new Node(in);
final int length = in.readInt(); try
this.content = new byte[length]; {
in.read(content); this.content = new JsonSerializer<StorageEntry>().read(in);
}
catch (ClassNotFoundException e)
{
System.err.println("ClassNotFoundException when reading StorageEntry; Message: " + e.getMessage());
}
} }
public Node getOrigin() public Node getOrigin()
@ -62,7 +66,7 @@ public class ContentMessage implements Message
return this.origin; return this.origin;
} }
public byte[] getContent() public StorageEntry getContent()
{ {
return this.content; return this.content;
} }

View File

@ -4,6 +4,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import kademlia.dht.KadContent; import kademlia.dht.KadContent;
import kademlia.dht.StorageEntry;
import kademlia.node.Node; import kademlia.node.Node;
import kademlia.serializer.JsonSerializer; import kademlia.serializer.JsonSerializer;
@ -18,7 +19,7 @@ public class StoreContentMessage implements Message
public static final byte CODE = 0x08; public static final byte CODE = 0x08;
private KadContent content; private StorageEntry content;
private Node origin; private Node origin;
/** /**
@ -26,7 +27,7 @@ public class StoreContentMessage implements Message
* @param content The content to be stored * @param content The content to be stored
* *
*/ */
public StoreContentMessage(Node origin, KadContent content) public StoreContentMessage(Node origin, StorageEntry content)
{ {
this.content = content; this.content = content;
this.origin = origin; this.origin = origin;
@ -43,7 +44,7 @@ public class StoreContentMessage implements Message
this.origin.toStream(out); this.origin.toStream(out);
/* Serialize the KadContent, then send it to the stream */ /* Serialize the KadContent, then send it to the stream */
new JsonSerializer<KadContent>().write(content, out); new JsonSerializer<StorageEntry>().write(content, out);
} }
@Override @Override
@ -52,7 +53,7 @@ public class StoreContentMessage implements Message
this.origin = new Node(in); this.origin = new Node(in);
try try
{ {
this.content = new JsonSerializer<KadContent>().read(in); this.content = new JsonSerializer<StorageEntry>().read(in);
} }
catch (ClassNotFoundException e) catch (ClassNotFoundException e)
{ {
@ -65,7 +66,7 @@ public class StoreContentMessage implements Message
return this.origin; return this.origin;
} }
public KadContent getContent() public StorageEntry getContent()
{ {
return this.content; return this.content;
} }

View File

@ -12,7 +12,7 @@ import java.util.TreeMap;
import kademlia.core.GetParameter; import kademlia.core.GetParameter;
import kademlia.core.KadConfiguration; import kademlia.core.KadConfiguration;
import kademlia.core.KadServer; import kademlia.core.KadServer;
import kademlia.dht.KadContent; import kademlia.dht.StorageEntry;
import kademlia.exceptions.RoutingException; import kademlia.exceptions.RoutingException;
import kademlia.exceptions.UnknownMessageException; import kademlia.exceptions.UnknownMessageException;
import kademlia.message.ContentLookupMessage; import kademlia.message.ContentLookupMessage;
@ -42,7 +42,7 @@ public class ContentLookupOperation implements Operation, Receiver
private final KadServer server; private final KadServer server;
private final Node localNode; private final Node localNode;
private final GetParameter params; private final GetParameter params;
private final List<KadContent> contentFound; private final List<StorageEntry> contentFound;
private final int numResultsReq; private final int numResultsReq;
private final KadConfiguration config; private final KadConfiguration config;
@ -250,7 +250,7 @@ public class ContentLookupOperation implements Operation, Receiver
this.localNode.getRoutingTable().insert(msg.getOrigin()); this.localNode.getRoutingTable().insert(msg.getOrigin());
/* Get the Content and check if it satisfies the required parameters */ /* Get the Content and check if it satisfies the required parameters */
KadContent content = msg.getContent(); StorageEntry content = msg.getContent();
System.out.println("Content Received: " + content); System.out.println("Content Received: " + content);
/*@todo Check if the content matches the given criteria */ /*@todo Check if the content matches the given criteria */
@ -313,7 +313,7 @@ public class ContentLookupOperation implements Operation, Receiver
/** /**
* @return The list of all content found during the lookup operation * @return The list of all content found during the lookup operation
*/ */
public List<KadContent> getContentFound() public List<StorageEntry> getContentFound()
{ {
return this.contentFound; return this.contentFound;
} }

View File

@ -2,7 +2,6 @@ package kademlia.operation;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import kademlia.core.DefaultConfiguration;
import kademlia.core.KadConfiguration; import kademlia.core.KadConfiguration;
import kademlia.core.KadServer; import kademlia.core.KadServer;
import kademlia.dht.DHT; import kademlia.dht.DHT;

View File

@ -6,6 +6,7 @@ import kademlia.core.KadConfiguration;
import kademlia.core.KadServer; import kademlia.core.KadServer;
import kademlia.dht.DHT; import kademlia.dht.DHT;
import kademlia.dht.KadContent; import kademlia.dht.KadContent;
import kademlia.dht.StorageEntry;
import kademlia.message.Message; import kademlia.message.Message;
import kademlia.message.StoreContentMessage; import kademlia.message.StoreContentMessage;
import kademlia.node.Node; import kademlia.node.Node;
@ -50,7 +51,7 @@ public class StoreOperation implements Operation
List<Node> nodes = ndlo.getClosestNodes(); List<Node> nodes = ndlo.getClosestNodes();
/* Create the message */ /* Create the message */
Message msg = new StoreContentMessage(this.localNode, this.content); Message msg = new StoreContentMessage(this.localNode, new StorageEntry(this.content));
/*Store the message on all of the K-Nodes*/ /*Store the message on all of the K-Nodes*/
for (Node n : nodes) for (Node n : nodes)

View File

@ -25,7 +25,7 @@ public class AutoRefreshOperationTest
final Kademlia kad2 = new Kademlia("Crystal", new NodeId("AJDHR678947584567464"), 4585); final Kademlia kad2 = new Kademlia("Crystal", new NodeId("AJDHR678947584567464"), 4585);
final Kademlia kad3 = new Kademlia("Shameer", new NodeId("AS84k6789KRNS45KFJ8W"), 8104); final Kademlia kad3 = new Kademlia("Shameer", new NodeId("AS84k6789KRNS45KFJ8W"), 8104);
final Kademlia kad4 = new Kademlia("Lokesh.", new NodeId("ASF45678947A845674GG"), 8335); final Kademlia kad4 = new Kademlia("Lokesh.", new NodeId("ASF45678947A845674GG"), 8335);
final Kademlia kad5 = new Kademlia("Chandu.", new NodeId("AS84RUD894758456dyrj"), 13345); final Kademlia kad5 = new Kademlia("Chandu.", new NodeId("AS84kUD894758456dyrj"), 13345);
/* Connecting nodes */ /* Connecting nodes */
System.out.println("Connecting Nodes"); System.out.println("Connecting Nodes");

View File

@ -4,7 +4,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import kademlia.core.GetParameter; import kademlia.core.GetParameter;
import kademlia.Kademlia; import kademlia.Kademlia;
import kademlia.dht.KadContent; import kademlia.dht.StorageEntry;
import kademlia.node.NodeId; import kademlia.node.NodeId;
/** /**
@ -37,14 +37,15 @@ public class ContentSendingTest
* Lets retrieve the content * Lets retrieve the content
*/ */
System.out.println("Retrieving Content"); System.out.println("Retrieving Content");
GetParameter gp = new GetParameter(c.getKey()); GetParameter gp = new GetParameter(c.getKey(), DHTContentImpl.TYPE);
gp.setType(DHTContentImpl.TYPE); gp.setType(DHTContentImpl.TYPE);
gp.setOwnerId(c.getOwnerId()); gp.setOwnerId(c.getOwnerId());
System.out.println("Get Parameter: " + gp); System.out.println("Get Parameter: " + gp);
List<KadContent> conte = kad2.get(gp, 1); List<StorageEntry> conte = kad2.get(gp, 4);
for (KadContent cc : conte) for (StorageEntry cc : conte)
{ {
System.out.println("Content Found: " + cc); System.out.println("Content Found: " + new DHTContentImpl().fromBytes(cc.getContent()));
System.out.println("Content Metadata: " + cc.getContentMetadata());
} }
} }

View File

@ -1,5 +1,6 @@
package kademlia.tests; package kademlia.tests;
import com.google.gson.Gson;
import kademlia.dht.KadContent; import kademlia.dht.KadContent;
import kademlia.node.NodeId; import kademlia.node.NodeId;
@ -12,18 +13,21 @@ import kademlia.node.NodeId;
public class DHTContentImpl implements KadContent public class DHTContentImpl implements KadContent
{ {
private final NodeId key; private NodeId key;
private String data; private String data;
private final String ownerId; private String ownerId;
private final long createTs, updateTs; private long createTs, updateTs;
public static final String TYPE = "DHTContentImpl";
{ {
this.createTs = this.updateTs = System.currentTimeMillis() / 1000L; this.createTs = this.updateTs = System.currentTimeMillis() / 1000L;
} }
public DHTContentImpl()
{
}
public DHTContentImpl(String ownerId, String data) public DHTContentImpl(String ownerId, String data)
{ {
this.ownerId = ownerId; this.ownerId = ownerId;
@ -42,11 +46,6 @@ public class DHTContentImpl implements KadContent
this.data = newData; this.data = newData;
} }
public String toBytes()
{
return this.data;
}
@Override @Override
public NodeId getKey() public NodeId getKey()
{ {
@ -77,6 +76,22 @@ public class DHTContentImpl implements KadContent
return this.updateTs; return this.updateTs;
} }
@Override
public byte[] toBytes()
{
Gson gson = new Gson();
return gson.toJson(this).getBytes();
}
@Override
public DHTContentImpl fromBytes(byte[] data)
{
Gson gson = new Gson();
DHTContentImpl val = gson.fromJson(new String(data), DHTContentImpl.class);
return val;
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -4,7 +4,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import kademlia.core.GetParameter; import kademlia.core.GetParameter;
import kademlia.Kademlia; import kademlia.Kademlia;
import kademlia.dht.KadContent; import kademlia.dht.StorageEntry;
import kademlia.node.NodeId; import kademlia.node.NodeId;
/** /**
@ -30,10 +30,10 @@ public class RefreshOperationTest
kad2.put(c); kad2.put(c);
/* Lets retrieve the content */ /* Lets retrieve the content */
GetParameter gp = new GetParameter(c.getKey()); GetParameter gp = new GetParameter(c.getKey(), DHTContentImpl.TYPE);
gp.setType(DHTContentImpl.TYPE); gp.setType(DHTContentImpl.TYPE);
gp.setOwnerId(c.getOwnerId()); gp.setOwnerId(c.getOwnerId());
List<KadContent> conte = kad2.get(gp, 1); List<StorageEntry> conte = kad2.get(gp, 1);
kad2.refresh(); kad2.refresh();
} }

View File

@ -3,7 +3,7 @@ package kademlia.tests;
import java.util.List; import java.util.List;
import kademlia.Kademlia; import kademlia.Kademlia;
import kademlia.core.GetParameter; import kademlia.core.GetParameter;
import kademlia.dht.KadContent; import kademlia.dht.StorageEntry;
import kademlia.node.NodeId; import kademlia.node.NodeId;
/** /**
@ -53,11 +53,11 @@ public class SaveStateTest2
/* Trying to get a content stored on the restored node */ /* Trying to get a content stored on the restored node */
GetParameter gp = new GetParameter(c.getKey(), kad2.getOwnerId(), c.getType()); GetParameter gp = new GetParameter(c.getKey(), kad2.getOwnerId(), c.getType());
List<KadContent> content = kad2.get(gp, 1); List<StorageEntry> content = kad2.get(gp, 1);
if (!content.isEmpty()) if (!content.isEmpty())
{ {
DHTContentImpl cc = (DHTContentImpl) content.get(0); DHTContentImpl cc = new DHTContentImpl().fromBytes(content.get(0).getContent());
System.out.println("Content received: " + cc); System.out.println("Content received: " + cc);
} }
else else