package socialkademlia.util.serializer; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.lang.reflect.Type; import java.util.List; import kademlia.util.serializer.KadSerializer; import socialkademlia.dht.JSocialKademliaDHT; import socialkademlia.dht.JSocialKademliaStorageEntryMetadata; import socialkademlia.dht.SocialKademliaDHT; import socialkademlia.dht.SocialKademliaStorageEntryMetadata; /** * A KadSerializer that serializes DHT to JSON format * The generic serializer is not working for DHT * * Why a DHT specific serializer? * The DHT structure: * - DHT * -- StorageEntriesManager * --- Map<NodeId, List<StorageEntry>> * ---- NodeId:KeyBytes * ---- List<StorageEntry> * ----- StorageEntry: Key, OwnerId, Type, Hash * * The above structure seems to be causing some problem for Gson, especially at the Map part. * * Solution * - Make the StorageEntriesManager transient * - Simply store all StorageEntry in the serialized object * - When reloading, re-add all StorageEntry to the DHT * * @author Joshua Kissoon * * @since 20140310 */ public class JsonSocialKademliaDHTSerializer implements KadSerializer<SocialKademliaDHT> { private final Gson gson; private final Type storageEntriesCollectionType; { gson = new Gson(); storageEntriesCollectionType = new TypeToken<List<JSocialKademliaStorageEntryMetadata>>() { }.getType(); } @Override public void write(SocialKademliaDHT data, DataOutputStream out) throws IOException { try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(out))) { writer.beginArray(); /* Write the basic DHT */ gson.toJson(data, JSocialKademliaDHT.class, writer); /* Now Store the Entries */ gson.toJson(data.getStorageEntries(), this.storageEntriesCollectionType, writer); writer.endArray(); } } @Override public SocialKademliaDHT read(DataInputStream in) throws IOException, ClassNotFoundException { try (DataInputStream din = new DataInputStream(in); JsonReader reader = new JsonReader(new InputStreamReader(in))) { reader.beginArray(); /* Read the basic DHT */ SocialKademliaDHT dht = gson.fromJson(reader, JSocialKademliaDHT.class); dht.initialize(); /* Now get the entries and add them back to the DHT */ List<SocialKademliaStorageEntryMetadata> entries = gson.fromJson(reader, this.storageEntriesCollectionType); dht.putStorageEntries(entries); reader.endArray(); return dht; } } }