Added getAll methods to each Objects

Change-Id: Icfd557b48ed048ad08a15029730c4d6e60a83353
diff --git a/src/main/java/net/onrc/onos/datastore/RCObject.java b/src/main/java/net/onrc/onos/datastore/RCObject.java
index 4370d00..37bc193 100644
--- a/src/main/java/net/onrc/onos/datastore/RCObject.java
+++ b/src/main/java/net/onrc/onos/datastore/RCObject.java
@@ -8,7 +8,6 @@
 import java.util.Map;
 
 import net.onrc.onos.datastore.RCTable.Entry;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -19,6 +18,7 @@
 import edu.stanford.ramcloud.JRamCloud;
 import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
 import edu.stanford.ramcloud.JRamCloud.ObjectExistsException;
+import edu.stanford.ramcloud.JRamCloud.TableEnumerator;
 import edu.stanford.ramcloud.JRamCloud.WrongVersionException;
 
 /**
@@ -55,10 +55,10 @@
     private Map<Object, Object> propertyMap;
 
     public RCObject(RCTable table, byte[] key) {
-	this(table, key, null);
+	this(table, key, null, VERSION_NONEXISTENT);
     }
 
-    public RCObject(RCTable table, byte[] key, byte[] value) {
+    public RCObject(RCTable table, byte[] key, byte[] value, long version) {
 	if (table == null) {
 	    throw new IllegalArgumentException("table cannot be null");
 	}
@@ -68,7 +68,7 @@
 	this.table = table;
 	this.key = key;
 	this.value = value;
-	this.version = VERSION_NONEXISTENT;
+	this.version = version;
 	this.propertyMap = new HashMap<Object, Object>();
 
 	if (this.value != null) {
@@ -76,6 +76,12 @@
 	}
     }
 
+    public static <T extends RCObject> T createFromKey(byte[] key) {
+	// Equivalent of this method is expected to be implemented by SubClasses
+	throw new UnsupportedOperationException(
+	        "createFromKey() is not expected to be called for RCObject");
+    }
+
     public RCTable getTable() {
 	return table;
     }
@@ -157,6 +163,12 @@
 	return map;
     }
 
+    protected void setValueAndDeserialize(byte[] value, long version) {
+	this.value = value;
+	this.version = version;
+	deserializeObjectFromValue();
+    }
+
     /**
      * Create an Object in DataStore.
      *
@@ -185,11 +197,8 @@
      */
     public void read() throws ObjectDoesntExistException {
 	Entry e = table.read(key);
-	this.value = e.value;
-	this.version = e.version;
-
 	// TODO should we deserialize immediately?
-	deserializeObjectFromValue();
+	setValueAndDeserialize(e.value, e.version);
     }
 
     /**
@@ -218,7 +227,8 @@
      * @throws ObjectDoesntExistException
      * @throws WrongVersionException
      */
-    public void delete() throws ObjectDoesntExistException, WrongVersionException {
+    public void delete() throws ObjectDoesntExistException,
+	    WrongVersionException {
 	this.version = table.delete(key, this.version);
     }
 
@@ -297,14 +307,59 @@
 	return fail_exists;
     }
 
-    /**
-     * Get All of it's kind?
-     */
-    public static Collection<? extends RCObject> getAllObjects() {
-	// TODO implement
-	throw new UnsupportedOperationException("Not implemented yet");
-	// Collection<? extends RCObject> list = new ArrayList<>();
-	// return list;
+    public static Iterable<RCObject> getAllObjects(
+	    RCTable table) {
+	return new ObjectEnumerator(table);
+    }
+
+    public static class ObjectEnumerator implements
+	    Iterable<RCObject> {
+
+	private RCTable table;
+
+	public ObjectEnumerator(RCTable table) {
+	    this.table = table;
+	}
+
+	@Override
+	public Iterator<RCObject> iterator() {
+	    return new ObjectIterator<RCObject>(table);
+	}
+
+    }
+
+    public static class ObjectIterator<E extends RCObject> implements
+	    Iterator<E> {
+
+	protected TableEnumerator enumerator;
+
+	public ObjectIterator(RCTable table) {
+	    // FIXME workaround for JRamCloud bug. It should have been declared
+	    // as static class
+	    JRamCloud c = RCClient.getClient();
+	    this.enumerator = c.new TableEnumerator(table.getTableId());
+	}
+
+	@Override
+	public boolean hasNext() {
+	    return enumerator.hasNext();
+	}
+
+	@Override
+	public E next() {
+	    JRamCloud.Object o = enumerator.next();
+	    RCObject obj = RCObject.createFromKey(o.key);
+	    obj.setValueAndDeserialize(o.value, o.version);
+	    return (E) obj;
+	}
+
+	@Deprecated
+	@Override
+	public void remove() {
+	    // TODO Not implemented, as I cannot find a use-case for it.
+	    throw new UnsupportedOperationException("Not implemented yet");
+	}
+
     }
 
 }
diff --git a/src/main/java/net/onrc/onos/datastore/RCTable.java b/src/main/java/net/onrc/onos/datastore/RCTable.java
index 55de05a..e74a5a4 100644
--- a/src/main/java/net/onrc/onos/datastore/RCTable.java
+++ b/src/main/java/net/onrc/onos/datastore/RCTable.java
@@ -16,6 +16,7 @@
  *
  */
 public class RCTable {
+    @SuppressWarnings("unused")
     private static final Logger log = LoggerFactory.getLogger(RCTable.class);
 
     private static final ConcurrentHashMap<String, RCTable> table_map = new ConcurrentHashMap<>();
diff --git a/src/main/java/net/onrc/onos/datastore/topology/RCDevice.java b/src/main/java/net/onrc/onos/datastore/topology/RCDevice.java
index 8789492..08fe458 100644
--- a/src/main/java/net/onrc/onos/datastore/topology/RCDevice.java
+++ b/src/main/java/net/onrc/onos/datastore/topology/RCDevice.java
@@ -5,6 +5,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
@@ -14,6 +15,7 @@
 
 import com.esotericsoftware.kryo.Kryo;
 
+import edu.stanford.ramcloud.JRamCloud;
 import net.onrc.onos.datastore.RCObject;
 import net.onrc.onos.datastore.RCTable;
 import net.onrc.onos.datastore.topology.RCLink.STATUS;
@@ -73,8 +75,44 @@
 	this.isPortIdsModified = true;
     }
 
-    public static RCDevice createFromKey(byte[] key) {
-	return new RCDevice(getMacFromKey(key));
+    /**
+     * Get an instance from Key.
+     *
+     * @note You need to call `read()` to get the DB content.
+     * @param key
+     * @return
+     */
+    public static <D extends RCObject> D createFromKey(byte[] key) {
+	@SuppressWarnings("unchecked")
+	D d = (D) new RCDevice(getMacFromKey(key));
+	return d;
+    }
+
+    public static Iterable<RCDevice> getAllDevices() {
+	return new DeviceEnumerator();
+    }
+
+    public static class DeviceEnumerator implements Iterable<RCDevice> {
+
+	@Override
+	public Iterator<RCDevice> iterator() {
+	    return new DeviceIterator();
+	}
+    }
+
+    public static class DeviceIterator extends ObjectIterator<RCDevice> {
+
+	public DeviceIterator() {
+	    super(RCTable.getTable(GLOBAL_DEVICE_TABLE_NAME));
+	}
+
+	@Override
+	public RCDevice next() {
+	    JRamCloud.Object o = enumerator.next();
+	    RCDevice e = RCDevice.createFromKey(o.key);
+	    e.setValueAndDeserialize(o.value, o.version);
+	    return e;
+	}
     }
 
     public byte[] getMac() {
diff --git a/src/main/java/net/onrc/onos/datastore/topology/RCLink.java b/src/main/java/net/onrc/onos/datastore/topology/RCLink.java
index dfc4307..eec6a10 100644
--- a/src/main/java/net/onrc/onos/datastore/topology/RCLink.java
+++ b/src/main/java/net/onrc/onos/datastore/topology/RCLink.java
@@ -2,6 +2,7 @@
 
 import java.nio.ByteBuffer;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
 
 import org.slf4j.Logger;
@@ -9,6 +10,7 @@
 
 import com.esotericsoftware.kryo.Kryo;
 
+import edu.stanford.ramcloud.JRamCloud;
 import net.onrc.onos.datastore.RCObject;
 import net.onrc.onos.datastore.RCTable;
 
@@ -45,7 +47,7 @@
 	}
 
 	public byte[] getSwitchID() {
-	    return RCSwitch.getSwichID(dpid);
+	    return RCSwitch.getSwitchID(dpid);
 	}
 
 	@Override
@@ -113,10 +115,46 @@
 	status = STATUS.INACTIVE;
     }
 
-    public static RCLink createFromKey(byte[] key) {
+    /**
+     * Get an instance from Key.
+     *
+     * @note You need to call `read()` to get the DB content.
+     * @param key
+     * @return RCLink instance
+     */
+    public static <L extends RCObject> L createFromKey(byte[] key) {
 	long linkTuple[] = getLinkTupleFromKey(key);
-	return new RCLink(linkTuple[0], linkTuple[1], linkTuple[2],
+	@SuppressWarnings("unchecked")
+	L l = (L) new RCLink(linkTuple[0], linkTuple[1], linkTuple[2],
 	        linkTuple[3]);
+	return l;
+    }
+
+    public static Iterable<RCLink> getAllLinks() {
+	return new LinkEnumerator();
+    }
+
+    public static class LinkEnumerator implements Iterable<RCLink> {
+
+	@Override
+	public Iterator<RCLink> iterator() {
+	    return new LinkIterator();
+	}
+    }
+
+    public static class LinkIterator extends ObjectIterator<RCLink> {
+
+	public LinkIterator() {
+	    super(RCTable.getTable(GLOBAL_LINK_TABLE_NAME));
+	}
+
+	@Override
+	public RCLink next() {
+	    JRamCloud.Object o = enumerator.next();
+	    RCLink e = RCLink.createFromKey(o.key);
+	    e.setValueAndDeserialize(o.value, o.version);
+	    return e;
+	}
     }
 
     public STATUS getStatus() {
diff --git a/src/main/java/net/onrc/onos/datastore/topology/RCPort.java b/src/main/java/net/onrc/onos/datastore/topology/RCPort.java
index 5a13e3e..894e2d2 100644
--- a/src/main/java/net/onrc/onos/datastore/topology/RCPort.java
+++ b/src/main/java/net/onrc/onos/datastore/topology/RCPort.java
@@ -5,6 +5,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
@@ -14,6 +15,7 @@
 
 import com.esotericsoftware.kryo.Kryo;
 
+import edu.stanford.ramcloud.JRamCloud;
 import net.onrc.onos.datastore.RCObject;
 import net.onrc.onos.datastore.RCTable;
 import net.onrc.onos.datastore.utils.ByteArrayComparator;
@@ -122,9 +124,45 @@
 	this.isDeviceIdsModified = true;
     }
 
-    public static RCPort createFromKey(byte[] key) {
+    /**
+     * Get an instance from Key.
+     *
+     * @note You need to call `read()` to get the DB content.
+     * @param key
+     * @return RCPort instance
+     */
+    public static <P extends RCObject> P createFromKey(byte[] key) {
 	long[] pair = getPortPairFromKey(key);
-	return new RCPort(pair[0], pair[1]);
+	@SuppressWarnings("unchecked")
+	P p = (P) new RCPort(pair[0], pair[1]);
+	return p;
+    }
+
+    public static Iterable<RCPort> getAllPorts() {
+	return new PortEnumerator();
+    }
+
+    public static class PortEnumerator implements Iterable<RCPort> {
+
+	@Override
+	public Iterator<RCPort> iterator() {
+	    return new PortIterator();
+	}
+    }
+
+    public static class PortIterator extends ObjectIterator<RCPort> {
+
+	public PortIterator() {
+	    super(RCTable.getTable(GLOBAL_PORT_TABLE_NAME));
+	}
+
+	@Override
+	public RCPort next() {
+	    JRamCloud.Object o = enumerator.next();
+	    RCPort e = RCPort.createFromKey(o.key);
+	    e.setValueAndDeserialize(o.value, o.version);
+	    return e;
+	}
     }
 
     public STATUS getStatus() {
diff --git a/src/main/java/net/onrc/onos/datastore/topology/RCSwitch.java b/src/main/java/net/onrc/onos/datastore/topology/RCSwitch.java
index 175209d..aee9c7e 100644
--- a/src/main/java/net/onrc/onos/datastore/topology/RCSwitch.java
+++ b/src/main/java/net/onrc/onos/datastore/topology/RCSwitch.java
@@ -4,6 +4,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Set;
@@ -18,6 +19,7 @@
 
 import com.esotericsoftware.kryo.Kryo;
 
+import edu.stanford.ramcloud.JRamCloud;
 import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
 import edu.stanford.ramcloud.JRamCloud.ObjectExistsException;
 import edu.stanford.ramcloud.JRamCloud.WrongVersionException;
@@ -66,7 +68,7 @@
 
     public static final int SWITCHID_BYTES = 2 + 8;
 
-    public static byte[] getSwichID(Long dpid) {
+    public static byte[] getSwitchID(Long dpid) {
 	if (dpid == null) {
 	    throw new IllegalArgumentException("dpid cannot be null");
 	}
@@ -88,7 +90,7 @@
     // FIXME specify DPID here, or Should caller specify the key it self?
     // In other words, should layer above have the control of the ID?
     public RCSwitch(Long dpid) {
-	super(RCTable.getTable(GLOBAL_SWITCH_TABLE_NAME), getSwichID(dpid));
+	super(RCTable.getTable(GLOBAL_SWITCH_TABLE_NAME), getSwitchID(dpid));
 
 	this.dpid = dpid;
 	this.status = STATUS.INACTIVE;
@@ -96,8 +98,44 @@
 	this.isPortIdsModified = true;
     }
 
-    public static RCSwitch createFromKey(byte[] key) {
-	return new RCSwitch(getDpidFromKey(key));
+    /**
+     * Get an instance from Key.
+     *
+     * @note You need to call `read()` to get the DB content.
+     * @param key
+     * @return RCSwitch instance
+     */
+    public static <SW extends RCObject> SW createFromKey(byte[] key) {
+	@SuppressWarnings("unchecked")
+	SW sw = (SW) new RCSwitch(getDpidFromKey(key));
+	return sw;
+    }
+
+    public static Iterable<RCSwitch> getAllSwitches() {
+	return new SwitchEnumerator();
+    }
+
+    public static class SwitchEnumerator implements Iterable<RCSwitch> {
+
+	@Override
+	public Iterator<RCSwitch> iterator() {
+	    return new SwitchIterator();
+	}
+    }
+
+    public static class SwitchIterator extends ObjectIterator<RCSwitch> {
+
+	public SwitchIterator() {
+	    super(RCTable.getTable(GLOBAL_SWITCH_TABLE_NAME));
+	}
+
+	@Override
+	public RCSwitch next() {
+	    JRamCloud.Object o = enumerator.next();
+	    RCSwitch e = RCSwitch.createFromKey(o.key);
+	    e.setValueAndDeserialize(o.value, o.version);
+	    return e;
+	}
     }
 
     public STATUS getStatus() {
@@ -255,6 +293,7 @@
 	topology_delete();
     }
 
+    @Deprecated
     private static void topology_setup() {
 	log.debug("topology_setup start.");
 
@@ -361,9 +400,17 @@
 	log.debug("topology_setup end.");
     }
 
+    @Deprecated
     private static void topology_walk() {
 	log.debug("topology_walk start.");
 
+	Iterable<RCSwitch> swIt = RCSwitch.getAllSwitches();
+	log.debug("Enumerating Switches start");
+	for (RCSwitch sw : swIt) {
+	    log.debug("{}", sw);
+	}
+	log.debug("Enumerating Switches end");
+
 	RCSwitch sw1 = new RCSwitch(0x1L);
 	try {
 	    sw1.read();
@@ -459,6 +506,7 @@
 	log.debug("topology_walk end.");
     }
 
+    @Deprecated
     private static void topology_delete() {
 	log.debug("topology_delete start.");