package kademlia.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 kademlia.routing.JKademliaRoutingTable; import java.lang.reflect.Type; import java.util.List; import kademlia.KadConfiguration; import kademlia.routing.Contact; import kademlia.routing.KademliaRoutingTable; /** * A KadSerializer that serializes routing tables to JSON format The generic serializer is not working for routing tables Why a JKademliaRoutingTable specific serializer? The routing table structure: - JKademliaRoutingTable -- Buckets[] --- Map<NodeId, Node> * ---- NodeId:KeyBytes * ---- Node: NodeId, InetAddress, Port * * The above structure seems to be causing some problem for Gson, * especially at the Map part. * * Solution - Make the Buckets[] transient - Simply store all Nodes in the serialized object - When reloading, re-add all nodes to the JKademliaRoutingTable * * @author Joshua Kissoon * * @since 20140310 */ public class JsonRoutingTableSerializer implements KadSerializer<KademliaRoutingTable> { private final Gson gson; Type contactCollectionType = new TypeToken<List<Contact>>() { }.getType(); private final KadConfiguration config; { gson = new Gson(); } /** * Initialize the class * * @param config */ public JsonRoutingTableSerializer(KadConfiguration config) { this.config = config; } @Override public void write(KademliaRoutingTable data, DataOutputStream out) throws IOException { try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(out))) { writer.beginArray(); /* Write the basic JKademliaRoutingTable */ gson.toJson(data, JKademliaRoutingTable.class, writer); /* Now Store the Contacts */ gson.toJson(data.getAllContacts(), contactCollectionType, writer); writer.endArray(); } } @Override public KademliaRoutingTable read(DataInputStream in) throws IOException, ClassNotFoundException { try (DataInputStream din = new DataInputStream(in); JsonReader reader = new JsonReader(new InputStreamReader(in))) { reader.beginArray(); /* Read the basic JKademliaRoutingTable */ KademliaRoutingTable tbl = gson.fromJson(reader, KademliaRoutingTable.class); tbl.setConfiguration(config); /* Now get the Contacts and add them back to the JKademliaRoutingTable */ List<Contact> contacts = gson.fromJson(reader, contactCollectionType); tbl.initialize(); for (Contact c : contacts) { tbl.insert(c); } reader.endArray(); /* Read and return the Content*/ return tbl; } } }