The current mechanism for serializing content will not work for complex content types.

Now we need to add methods to KadContent objects to provide the byte[] format of their content and to re-read the byte format of their content.
This commit is contained in:
Joshua Kissoon 2014-04-02 16:35:08 +05:30
parent 5b3e01df4e
commit 9190b122c7
10 changed files with 191 additions and 153 deletions

View File

@ -84,12 +84,18 @@ public class DHT
/* Keep track of this content in the entries manager */ /* Keep track of this content in the entries manager */
try try
{ {
StorageEntry sEntry = this.entriesManager.put(content); StorageEntryMetadata sEntry = this.entriesManager.put(content);
/* 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.getKey());
DataOutputStream dout = new DataOutputStream(new FileOutputStream(contentStorageFolder + File.separator + sEntry.hashCode() + ".kct"));
getContentSerializer().write(content, dout); 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);
}
} }
catch (ContentExistException e) catch (ContentExistException e)
{ {
@ -105,11 +111,15 @@ public class DHT
* *
* @return A KadContent object * @return A KadContent object
*/ */
private KadContent retrieve(NodeId key, int hashCode) throws FileNotFoundException, IOException, ClassNotFoundException private byte[] retrieve(NodeId key, int hashCode) throws FileNotFoundException, IOException, ClassNotFoundException
{ {
String folder = this.getContentStorageFolderName(key); String folder = this.getContentStorageFolderName(key);
DataInputStream in = new DataInputStream(new FileInputStream(folder + File.separator + hashCode + ".kct")); DataInputStream din = new DataInputStream(new FileInputStream(folder + File.separator + hashCode + ".kct"));
return getContentSerializer().read(in); int length = din.readInt();
byte[] data = new byte[length];
din.read(data);
return data;
} }
/** /**
@ -133,7 +143,7 @@ public class DHT
* *
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public KadContent get(StorageEntry entry) throws IOException, NoSuchElementException public byte[] get(StorageEntryMetadata entry) throws IOException, NoSuchElementException
{ {
try try
{ {
@ -162,12 +172,12 @@ public class DHT
* *
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public KadContent get(GetParameter param) throws NoSuchElementException, IOException public byte[] 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
{ {
StorageEntry e = this.entriesManager.get(param); StorageEntryMetadata e = this.entriesManager.get(param);
return this.retrieve(e.getKey(), e.hashCode()); return this.retrieve(e.getKey(), e.hashCode());
} }
catch (FileNotFoundException e) catch (FileNotFoundException e)
@ -193,10 +203,10 @@ public class DHT
*/ */
public void remove(KadContent content) throws ContentNotFoundException public void remove(KadContent content) throws ContentNotFoundException
{ {
this.remove(new StorageEntry(content)); this.remove(new StorageEntryMetadata(content));
} }
public void remove(StorageEntry entry) throws ContentNotFoundException public void remove(StorageEntryMetadata entry) throws ContentNotFoundException
{ {
String folder = this.getContentStorageFolderName(entry.getKey()); String folder = this.getContentStorageFolderName(entry.getKey());
File file = new File(folder + File.separator + entry.hashCode() + ".kct"); File file = new File(folder + File.separator + entry.hashCode() + ".kct");
@ -242,7 +252,7 @@ public class DHT
/** /**
* @return A List of all StorageEntries for this node * @return A List of all StorageEntries for this node
*/ */
public List<StorageEntry> getStorageEntries() public List<StorageEntryMetadata> getStorageEntries()
{ {
return entriesManager.getAllEntries(); return entriesManager.getAllEntries();
} }
@ -253,9 +263,9 @@ public class DHT
* *
* @param ientries The entries to add * @param ientries The entries to add
*/ */
public void putStorageEntries(List<StorageEntry> ientries) public void putStorageEntries(List<StorageEntryMetadata> ientries)
{ {
for (StorageEntry e : ientries) for (StorageEntryMetadata e : ientries)
{ {
try try
{ {

View File

@ -41,4 +41,14 @@ public interface KadContent
* @return The ID of the owner of this content * @return The ID of the owner of this content
*/ */
public String getOwnerId(); public String getOwnerId();
public default byte[] toBytes()
{
return new byte[2];
}
public default void fromBytes(byte[] data)
{
}
} }

View File

@ -1,117 +1,23 @@
package kademlia.dht; package kademlia.dht;
import java.util.Objects;
import kademlia.core.GetParameter;
import kademlia.node.NodeId;
/** /**
* Keeps track of data for a Content stored in the DHT * A StorageEntry class that is used to store a content on the DHT
* Used by the StorageEntryManager class
* *
* @author Joshua Kissoon * @author Joshua Kissoon
* @since 20140226 * @since 20140402
*/ */
public class StorageEntry public class StorageEntry
{ {
private byte[] content;
private final NodeId key; private StorageEntryMetadata metadata;
private final String ownerId;
private final String type;
private final int contentHash;
private final long lastUpdated;
public StorageEntry(KadContent content) public StorageEntry(KadContent content)
{ {
this.key = content.getKey();
this.ownerId = content.getOwnerId();
this.type = content.getType();
this.contentHash = content.hashCode();
this.lastUpdated = content.getLastUpdatedTimestamp();
} }
public NodeId getKey() public StorageEntry(KadContent content, StorageEntryMetadata metadata)
{ {
return this.key; this.content = content.g
}
public String getOwnerId()
{
return this.ownerId;
}
public String getType()
{
return this.type;
}
public int getContentHash()
{
return this.contentHash;
}
/**
* When a node is looking for content, he sends the search criteria in a GetParameter object
* Here we take this GetParameter object and check if this StorageEntry satisfies the given parameters
*
* @param params
*
* @return boolean Whether this content satisfies the parameters
*/
public boolean satisfiesParameters(GetParameter params)
{
/* Check that owner id matches */
if ((params.getOwnerId() != null) && (!params.getOwnerId().equals(this.ownerId)))
{
return false;
}
/* Check that type matches */
if ((params.getType() != null) && (!params.getType().equals(this.type)))
{
return false;
}
/* Check that key matches */
return (params.getKey() != null) && (params.getKey().equals(this.key));
}
@Override
public boolean equals(Object o)
{
if (o instanceof StorageEntry)
{
return this.hashCode() == o.hashCode();
}
return false;
}
@Override
public int hashCode()
{
int hash = 3;
hash = 23 * hash + Objects.hashCode(this.key);
hash = 23 * hash + Objects.hashCode(this.ownerId);
hash = 23 * hash + Objects.hashCode(this.type);
return hash;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder("[StorageEntry: ");
sb.append("{Key: ");
sb.append(this.key);
sb.append("} ");
sb.append("{Owner: ");
sb.append(this.ownerId);
sb.append("} ");
sb.append("{Type: ");
sb.append(this.type);
sb.append("} ");
sb.append("]");
return sb.toString();
} }
} }

View File

@ -21,7 +21,7 @@ import kademlia.node.NodeId;
class StorageEntryManager class StorageEntryManager
{ {
private final Map<NodeId, List<StorageEntry>> entries; private final Map<NodeId, List<StorageEntryMetadata>> entries;
{ {
@ -33,9 +33,9 @@ class StorageEntryManager
* *
* @param content The content to store a reference to * @param content The content to store a reference to
*/ */
public StorageEntry put(KadContent content) throws ContentExistException public StorageEntryMetadata put(KadContent content) throws ContentExistException
{ {
return this.put(new StorageEntry(content)); return this.put(new StorageEntryMetadata(content));
} }
/** /**
@ -43,11 +43,11 @@ class StorageEntryManager
* *
* @param entry The StorageEntry to store * @param entry The StorageEntry to store
*/ */
public StorageEntry put(StorageEntry entry) throws ContentExistException public StorageEntryMetadata put(StorageEntryMetadata entry) throws ContentExistException
{ {
if (!this.entries.containsKey(entry.getKey())) if (!this.entries.containsKey(entry.getKey()))
{ {
this.entries.put(entry.getKey(), new ArrayList<StorageEntry>()); this.entries.put(entry.getKey(), new ArrayList<>());
} }
/* If this entry doesn't already exist, then we add it */ /* If this entry doesn't already exist, then we add it */
@ -78,7 +78,7 @@ class StorageEntryManager
{ {
System.out.println("Does contain the key"); System.out.println("Does contain the key");
/* Content with this key exist, check if any match the rest of the search criteria */ /* Content with this key exist, check if any match the rest of the search criteria */
for (StorageEntry e : this.entries.get(param.getKey())) for (StorageEntryMetadata e : this.entries.get(param.getKey()))
{ {
/* If any entry satisfies the given parameters, return true */ /* If any entry satisfies the given parameters, return true */
if (e.satisfiesParameters(param)) if (e.satisfiesParameters(param))
@ -100,13 +100,13 @@ class StorageEntryManager
*/ */
public boolean contains(KadContent content) public boolean contains(KadContent content)
{ {
return this.contains(new StorageEntry(content)); return this.contains(new StorageEntryMetadata(content));
} }
/** /**
* Check if a StorageEntry exist on this DHT * Check if a StorageEntry exist on this DHT
*/ */
private boolean contains(StorageEntry entry) private boolean contains(StorageEntryMetadata entry)
{ {
if (this.entries.containsKey(entry.getKey())) if (this.entries.containsKey(entry.getKey()))
{ {
@ -125,12 +125,12 @@ class StorageEntryManager
* *
* @return List of content for the specific search parameters * @return List of content for the specific search parameters
*/ */
public StorageEntry get(GetParameter param) throws NoSuchElementException public StorageEntryMetadata get(GetParameter param) throws NoSuchElementException
{ {
if (this.entries.containsKey(param.getKey())) if (this.entries.containsKey(param.getKey()))
{ {
/* Content with this key exist, check if any match the rest of the search criteria */ /* Content with this key exist, check if any match the rest of the search criteria */
for (StorageEntry e : this.entries.get(param.getKey())) for (StorageEntryMetadata e : this.entries.get(param.getKey()))
{ {
/* If any entry satisfies the given parameters, return true */ /* If any entry satisfies the given parameters, return true */
if (e.satisfiesParameters(param)) if (e.satisfiesParameters(param))
@ -151,11 +151,11 @@ class StorageEntryManager
/** /**
* @return A list of all storage entries * @return A list of all storage entries
*/ */
public List<StorageEntry> getAllEntries() public List<StorageEntryMetadata> getAllEntries()
{ {
List<StorageEntry> entriesRet = new ArrayList<>(); List<StorageEntryMetadata> entriesRet = new ArrayList<>();
for (List<StorageEntry> entrySet : this.entries.values()) for (List<StorageEntryMetadata> entrySet : this.entries.values())
{ {
if (entrySet.size() > 0) if (entrySet.size() > 0)
{ {
@ -168,10 +168,10 @@ class StorageEntryManager
public void remove(KadContent content) throws ContentNotFoundException public void remove(KadContent content) throws ContentNotFoundException
{ {
this.remove(new StorageEntry(content)); this.remove(new StorageEntryMetadata(content));
} }
public void remove(StorageEntry entry) throws ContentNotFoundException public void remove(StorageEntryMetadata entry) throws ContentNotFoundException
{ {
if (contains(entry)) if (contains(entry))
{ {
@ -187,14 +187,14 @@ class StorageEntryManager
public String toString() public String toString()
{ {
StringBuilder sb = new StringBuilder("Stored Content: \n"); StringBuilder sb = new StringBuilder("Stored Content: \n");
for (List<StorageEntry> es : this.entries.values()) for (List<StorageEntryMetadata> es : this.entries.values())
{ {
if (entries.size() < 1) if (entries.size() < 1)
{ {
continue; continue;
} }
for (StorageEntry e : es) for (StorageEntryMetadata e : es)
{ {
sb.append(e); sb.append(e);
sb.append("\n"); sb.append("\n");

View File

@ -0,0 +1,117 @@
package kademlia.dht;
import java.util.Objects;
import kademlia.core.GetParameter;
import kademlia.node.NodeId;
/**
* Keeps track of data for a Content stored in the DHT
* Used by the StorageEntryManager class
*
* @author Joshua Kissoon
* @since 20140226
*/
public class StorageEntryMetadata
{
private final NodeId key;
private final String ownerId;
private final String type;
private final int contentHash;
private final long lastUpdated;
public StorageEntryMetadata(KadContent content)
{
this.key = content.getKey();
this.ownerId = content.getOwnerId();
this.type = content.getType();
this.contentHash = content.hashCode();
this.lastUpdated = content.getLastUpdatedTimestamp();
}
public NodeId getKey()
{
return this.key;
}
public String getOwnerId()
{
return this.ownerId;
}
public String getType()
{
return this.type;
}
public int getContentHash()
{
return this.contentHash;
}
/**
* When a node is looking for content, he sends the search criteria in a GetParameter object
* Here we take this GetParameter object and check if this StorageEntry satisfies the given parameters
*
* @param params
*
* @return boolean Whether this content satisfies the parameters
*/
public boolean satisfiesParameters(GetParameter params)
{
/* Check that owner id matches */
if ((params.getOwnerId() != null) && (!params.getOwnerId().equals(this.ownerId)))
{
return false;
}
/* Check that type matches */
if ((params.getType() != null) && (!params.getType().equals(this.type)))
{
return false;
}
/* Check that key matches */
return (params.getKey() != null) && (params.getKey().equals(this.key));
}
@Override
public boolean equals(Object o)
{
if (o instanceof StorageEntryMetadata)
{
return this.hashCode() == o.hashCode();
}
return false;
}
@Override
public int hashCode()
{
int hash = 3;
hash = 23 * hash + Objects.hashCode(this.key);
hash = 23 * hash + Objects.hashCode(this.ownerId);
hash = 23 * hash + Objects.hashCode(this.type);
return hash;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder("[StorageEntry: ");
sb.append("{Key: ");
sb.append(this.key);
sb.append("} ");
sb.append("{Owner: ");
sb.append(this.ownerId);
sb.append("} ");
sb.append("{Type: ");
sb.append(this.type);
sb.append("} ");
sb.append("]");
return sb.toString();
}
}

View File

@ -18,7 +18,7 @@ public class ContentMessage implements Message
public static final byte CODE = 0x04; public static final byte CODE = 0x04;
private KadContent content; private byte[] 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, KadContent content) public ContentMessage(Node origin, byte[] content)
{ {
this.content = content; this.content = content;
this.origin = origin; this.origin = origin;
@ -43,7 +43,8 @@ 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 */
new JsonSerializer<KadContent>().write(content, out); out.writeInt(content.length);
out.write(content);
} }
@Override @Override
@ -51,14 +52,9 @@ public class ContentMessage implements Message
{ {
this.origin = new Node(in); this.origin = new Node(in);
try final int length = in.readInt();
{ this.content = new byte[length];
this.content = new JsonSerializer<KadContent>().read(in); in.read(content);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
} }
public Node getOrigin() public Node getOrigin()
@ -66,7 +62,7 @@ public class ContentMessage implements Message
return this.origin; return this.origin;
} }
public KadContent getContent() public byte[] getContent()
{ {
return this.content; return this.content;
} }

View File

@ -6,7 +6,7 @@ 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;
import kademlia.dht.StorageEntry; import kademlia.dht.StorageEntryMetadata;
import kademlia.exceptions.ContentNotFoundException; import kademlia.exceptions.ContentNotFoundException;
import kademlia.message.Message; import kademlia.message.Message;
import kademlia.message.StoreContentMessage; import kademlia.message.StoreContentMessage;
@ -46,10 +46,10 @@ public class ContentRefreshOperation implements Operation
public void execute() throws IOException public void execute() throws IOException
{ {
/* Get a list of all storage entries for content */ /* Get a list of all storage entries for content */
List<StorageEntry> entries = this.dht.getStorageEntries(); List<StorageEntryMetadata> entries = this.dht.getStorageEntries();
/* For each storage entry, distribute it */ /* For each storage entry, distribute it */
for (StorageEntry e : entries) for (StorageEntryMetadata e : entries)
{ {
/** /**
* @todo - Paper improvement 1 - * @todo - Paper improvement 1 -

View File

@ -12,7 +12,7 @@ import java.io.OutputStreamWriter;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import kademlia.dht.DHT; import kademlia.dht.DHT;
import kademlia.dht.StorageEntry; import kademlia.dht.StorageEntryMetadata;
/** /**
* A KadSerializer that serializes DHT to JSON format * A KadSerializer that serializes DHT to JSON format
@ -48,7 +48,7 @@ public class JsonDHTSerializer implements KadSerializer<DHT>
{ {
gson = new Gson(); gson = new Gson();
storageEntriesCollectionType = new TypeToken<List<StorageEntry>>() storageEntriesCollectionType = new TypeToken<List<StorageEntryMetadata>>()
{ {
}.getType(); }.getType();
} }
@ -84,7 +84,7 @@ public class JsonDHTSerializer implements KadSerializer<DHT>
dht.initialize(); dht.initialize();
/* Now get the entries and add them back to the DHT */ /* Now get the entries and add them back to the DHT */
List<StorageEntry> entries = gson.fromJson(reader, this.storageEntriesCollectionType); List<StorageEntryMetadata> entries = gson.fromJson(reader, this.storageEntriesCollectionType);
dht.putStorageEntries(entries); dht.putStorageEntries(entries);
reader.endArray(); reader.endArray();

View File

@ -43,7 +43,6 @@ public class JsonSerializer<T> implements KadSerializer<T>
writer.endArray(); writer.endArray();
} }
} }
@Override @Override

View File

@ -42,7 +42,7 @@ public class DHTContentImpl implements KadContent
this.data = newData; this.data = newData;
} }
public String getData() public String toBytes()
{ {
return this.data; return this.data;
} }