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 */
try
{
StorageEntry sEntry = this.entriesManager.put(content);
StorageEntryMetadata sEntry = this.entriesManager.put(content);
/* Now we store the content locally in a file */
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)
{
@ -105,11 +111,15 @@ public class DHT
*
* @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);
DataInputStream in = new DataInputStream(new FileInputStream(folder + File.separator + hashCode + ".kct"));
return getContentSerializer().read(in);
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;
}
/**
@ -133,7 +143,7 @@ public class DHT
*
* @throws java.io.IOException
*/
public KadContent get(StorageEntry entry) throws IOException, NoSuchElementException
public byte[] get(StorageEntryMetadata entry) throws IOException, NoSuchElementException
{
try
{
@ -162,12 +172,12 @@ public class DHT
*
* @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 */
try
{
StorageEntry e = this.entriesManager.get(param);
StorageEntryMetadata e = this.entriesManager.get(param);
return this.retrieve(e.getKey(), e.hashCode());
}
catch (FileNotFoundException e)
@ -193,10 +203,10 @@ public class DHT
*/
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());
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
*/
public List<StorageEntry> getStorageEntries()
public List<StorageEntryMetadata> getStorageEntries()
{
return entriesManager.getAllEntries();
}
@ -253,9 +263,9 @@ public class DHT
*
* @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
{

View File

@ -41,4 +41,14 @@ public interface KadContent
* @return The ID of the owner of this content
*/
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;
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
* A StorageEntry class that is used to store a content on the DHT
*
* @author Joshua Kissoon
* @since 20140226
* @since 20140402
*/
public class StorageEntry
{
private final NodeId key;
private final String ownerId;
private final String type;
private final int contentHash;
private final long lastUpdated;
private byte[] content;
private StorageEntryMetadata metadata;
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()
{
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)
public StorageEntry(KadContent content, StorageEntryMetadata metadata)
{
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();
this.content = content.g
}
}

View File

@ -21,7 +21,7 @@ import kademlia.node.NodeId;
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
*/
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
*/
public StorageEntry put(StorageEntry entry) throws ContentExistException
public StorageEntryMetadata put(StorageEntryMetadata entry) throws ContentExistException
{
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 */
@ -78,7 +78,7 @@ class StorageEntryManager
{
System.out.println("Does contain the key");
/* 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 (e.satisfiesParameters(param))
@ -100,13 +100,13 @@ class StorageEntryManager
*/
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
*/
private boolean contains(StorageEntry entry)
private boolean contains(StorageEntryMetadata entry)
{
if (this.entries.containsKey(entry.getKey()))
{
@ -125,12 +125,12 @@ class StorageEntryManager
*
* @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()))
{
/* 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 (e.satisfiesParameters(param))
@ -151,11 +151,11 @@ class StorageEntryManager
/**
* @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)
{
@ -168,10 +168,10 @@ class StorageEntryManager
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))
{
@ -187,14 +187,14 @@ class StorageEntryManager
public String toString()
{
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)
{
continue;
}
for (StorageEntry e : es)
for (StorageEntryMetadata e : es)
{
sb.append(e);
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;
private KadContent content;
private byte[] content;
private Node origin;
/**
@ -26,7 +26,7 @@ public class ContentMessage implements Message
* @param content The content to be stored
*
*/
public ContentMessage(Node origin, KadContent content)
public ContentMessage(Node origin, byte[] content)
{
this.content = content;
this.origin = origin;
@ -43,7 +43,8 @@ public class ContentMessage implements Message
this.origin.toStream(out);
/* Serialize the KadContent, then send it to the stream */
new JsonSerializer<KadContent>().write(content, out);
out.writeInt(content.length);
out.write(content);
}
@Override
@ -51,14 +52,9 @@ public class ContentMessage implements Message
{
this.origin = new Node(in);
try
{
this.content = new JsonSerializer<KadContent>().read(in);
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
final int length = in.readInt();
this.content = new byte[length];
in.read(content);
}
public Node getOrigin()
@ -66,7 +62,7 @@ public class ContentMessage implements Message
return this.origin;
}
public KadContent getContent()
public byte[] getContent()
{
return this.content;
}

View File

@ -6,7 +6,7 @@ import kademlia.core.DefaultConfiguration;
import kademlia.core.KadConfiguration;
import kademlia.core.KadServer;
import kademlia.dht.DHT;
import kademlia.dht.StorageEntry;
import kademlia.dht.StorageEntryMetadata;
import kademlia.exceptions.ContentNotFoundException;
import kademlia.message.Message;
import kademlia.message.StoreContentMessage;
@ -46,10 +46,10 @@ public class ContentRefreshOperation implements Operation
public void execute() throws IOException
{
/* 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 (StorageEntry e : entries)
for (StorageEntryMetadata e : entries)
{
/**
* @todo - Paper improvement 1 -

View File

@ -12,7 +12,7 @@ import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.util.List;
import kademlia.dht.DHT;
import kademlia.dht.StorageEntry;
import kademlia.dht.StorageEntryMetadata;
/**
* A KadSerializer that serializes DHT to JSON format
@ -48,7 +48,7 @@ public class JsonDHTSerializer implements KadSerializer<DHT>
{
gson = new Gson();
storageEntriesCollectionType = new TypeToken<List<StorageEntry>>()
storageEntriesCollectionType = new TypeToken<List<StorageEntryMetadata>>()
{
}.getType();
}
@ -84,7 +84,7 @@ public class JsonDHTSerializer implements KadSerializer<DHT>
dht.initialize();
/* 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);
reader.endArray();

View File

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

View File

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