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.dht.DHT;
import kademlia.dht.KadContent;
import kademlia.dht.StorageEntry;
import kademlia.exceptions.RoutingException;
import kademlia.message.MessageFactory;
import kademlia.node.Node;
@ -280,7 +281,7 @@ public class Kademlia
*
* @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;
if (this.dht.contains(param))

View File

@ -19,26 +19,16 @@ public class GetParameter
private String ownerId = 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
*
* @param key
* @param owner
* @param type
*/
public GetParameter(NodeId key, String owner)
public GetParameter(NodeId key, String type)
{
this(key);
this.ownerId = owner;
this.key = key;
this.type = type;
}
/**

View File

@ -27,7 +27,7 @@ public class DHT
{
private transient StorageEntryManager entriesManager;
private transient KadSerializer<KadContent> contentSerializer = null;
private transient KadSerializer<StorageEntry> serializer = null;
private transient KadConfiguration config;
private final String ownerId;
@ -62,14 +62,14 @@ public class DHT
*
* @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
*/
public void store(KadContent content) throws IOException
public void store(StorageEntry content) throws IOException
{
/* Keep track of this content in the entries manager */
try
{
StorageEntryMetadata sEntry = this.entriesManager.put(content);
StorageEntryMetadata sEntry = this.entriesManager.put(content.getContentMetadata());
/* 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");
DataOutputStream dout = new DataOutputStream(fout))
{
byte[] data = content.toBytes();
dout.writeInt(data.length);
dout.write(data);
this.getSerializer().write(content, dout);
}
}
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
*
@ -111,15 +114,11 @@ public class DHT
*
* @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);
DataInputStream din = new DataInputStream(new FileInputStream(folder + File.separator + hashCode + ".kct"));
int length = din.readInt();
byte[] data = new byte[length];
din.read(data);
return data;
return this.getSerializer().read(din);
}
/**
@ -143,7 +142,7 @@ public class DHT
*
* @throws java.io.IOException
*/
public byte[] get(StorageEntryMetadata entry) throws IOException, NoSuchElementException
public StorageEntry get(StorageEntryMetadata entry) throws IOException, NoSuchElementException
{
try
{
@ -172,7 +171,7 @@ public class DHT
*
* @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 */
try

View File

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

View File

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

View File

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

View File

@ -12,7 +12,7 @@ import java.util.TreeMap;
import kademlia.core.GetParameter;
import kademlia.core.KadConfiguration;
import kademlia.core.KadServer;
import kademlia.dht.KadContent;
import kademlia.dht.StorageEntry;
import kademlia.exceptions.RoutingException;
import kademlia.exceptions.UnknownMessageException;
import kademlia.message.ContentLookupMessage;
@ -42,7 +42,7 @@ public class ContentLookupOperation implements Operation, Receiver
private final KadServer server;
private final Node localNode;
private final GetParameter params;
private final List<KadContent> contentFound;
private final List<StorageEntry> contentFound;
private final int numResultsReq;
private final KadConfiguration config;
@ -250,7 +250,7 @@ public class ContentLookupOperation implements Operation, Receiver
this.localNode.getRoutingTable().insert(msg.getOrigin());
/* 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);
/*@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
*/
public List<KadContent> getContentFound()
public List<StorageEntry> getContentFound()
{
return this.contentFound;
}

View File

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

View File

@ -6,6 +6,7 @@ import kademlia.core.KadConfiguration;
import kademlia.core.KadServer;
import kademlia.dht.DHT;
import kademlia.dht.KadContent;
import kademlia.dht.StorageEntry;
import kademlia.message.Message;
import kademlia.message.StoreContentMessage;
import kademlia.node.Node;
@ -50,7 +51,7 @@ public class StoreOperation implements Operation
List<Node> nodes = ndlo.getClosestNodes();
/* 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*/
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 kad3 = new Kademlia("Shameer", new NodeId("AS84k6789KRNS45KFJ8W"), 8104);
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 */
System.out.println("Connecting Nodes");

View File

@ -4,7 +4,7 @@ import java.io.IOException;
import java.util.List;
import kademlia.core.GetParameter;
import kademlia.Kademlia;
import kademlia.dht.KadContent;
import kademlia.dht.StorageEntry;
import kademlia.node.NodeId;
/**
@ -37,14 +37,15 @@ public class ContentSendingTest
* Lets retrieve the 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.setOwnerId(c.getOwnerId());
System.out.println("Get Parameter: " + gp);
List<KadContent> conte = kad2.get(gp, 1);
for (KadContent cc : conte)
List<StorageEntry> conte = kad2.get(gp, 4);
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;
import com.google.gson.Gson;
import kademlia.dht.KadContent;
import kademlia.node.NodeId;
@ -12,17 +13,20 @@ import kademlia.node.NodeId;
public class DHTContentImpl implements KadContent
{
private final NodeId key;
private NodeId key;
private String data;
private final String ownerId;
private final long createTs, updateTs;
public static final String TYPE = "DHTContentImpl";
private String ownerId;
private long createTs, updateTs;
{
this.createTs = this.updateTs = System.currentTimeMillis() / 1000L;
}
public DHTContentImpl()
{
}
public DHTContentImpl(String ownerId, String data)
{
@ -42,11 +46,6 @@ public class DHTContentImpl implements KadContent
this.data = newData;
}
public String toBytes()
{
return this.data;
}
@Override
public NodeId getKey()
{
@ -76,6 +75,22 @@ public class DHTContentImpl implements KadContent
{
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
public String toString()

View File

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

View File

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