mirror of
https://github.com/ChronosX88/KademliaDHT.git
synced 2024-12-23 08:11:47 +00:00
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:
parent
5b3e01df4e
commit
9190b122c7
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
117
src/kademlia/dht/StorageEntryMetadata.java
Normal file
117
src/kademlia/dht/StorageEntryMetadata.java
Normal 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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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 -
|
||||
|
@ -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();
|
||||
|
@ -43,7 +43,6 @@ public class JsonSerializer<T> implements KadSerializer<T>
|
||||
|
||||
writer.endArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,7 +42,7 @@ public class DHTContentImpl implements KadContent
|
||||
this.data = newData;
|
||||
}
|
||||
|
||||
public String getData()
|
||||
public String toBytes()
|
||||
{
|
||||
return this.data;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user