WIP: adding utility methods

Change-Id: I078a33e67e4b424dd2f1c4eff362550fb3be3424
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 0e8afe4..8789492 100644
--- a/src/main/java/net/onrc/onos/datastore/topology/RCDevice.java
+++ b/src/main/java/net/onrc/onos/datastore/topology/RCDevice.java
@@ -18,6 +18,7 @@
 import net.onrc.onos.datastore.RCTable;
 import net.onrc.onos.datastore.topology.RCLink.STATUS;
 import net.onrc.onos.datastore.utils.ByteArrayComparator;
+import net.onrc.onos.datastore.utils.ByteArrayUtil;
 
 public class RCDevice extends RCObject {
     @SuppressWarnings("unused")
@@ -147,6 +148,12 @@
 	return map;
     }
 
+    @Override
+    public String toString() {
+	// TODO OUTPUT ALL?
+	return "[RCDevice " + ByteArrayUtil.toHexStringBuffer(mac, ":") + "]";
+    }
+
     public static void main(String[] args) {
 	// TODO Auto-generated method stub
 
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 957ef88..dfc4307 100644
--- a/src/main/java/net/onrc/onos/datastore/topology/RCLink.java
+++ b/src/main/java/net/onrc/onos/datastore/topology/RCLink.java
@@ -47,6 +47,12 @@
 	public byte[] getSwitchID() {
 	    return RCSwitch.getSwichID(dpid);
 	}
+
+	@Override
+	public String toString() {
+	    return "(" + Long.toHexString(dpid) + "@" + number + ")";
+	}
+
     }
 
     public static final String GLOBAL_LINK_TABLE_NAME = "G:Link";
@@ -76,6 +82,27 @@
 	        .put(RCPort.getPortID(dst_dpid, dst_port_no)).array();
     }
 
+    public static long[] getLinkTupleFromKey(byte[] key) {
+	return getLinkTupleFromKey(ByteBuffer.wrap(key));
+    }
+
+    public static long[] getLinkTupleFromKey(ByteBuffer keyBuf) {
+	long tuple[] = new long[4];
+	if (keyBuf.getChar() != 'L') {
+	    throw new IllegalArgumentException("Invalid Link key");
+	}
+	long src_port_pair[] = RCPort.getPortPairFromKey(keyBuf.slice());
+	keyBuf.position(2 + RCPort.PORTID_BYTES);
+	long dst_port_pair[] = RCPort.getPortPairFromKey(keyBuf.slice());
+
+	tuple[0] = src_port_pair[0];
+	tuple[1] = src_port_pair[1];
+	tuple[2] = dst_port_pair[0];
+	tuple[3] = dst_port_pair[1];
+
+	return tuple;
+    }
+
     public RCLink(Long src_dpid, Long src_port_no, Long dst_dpid,
 	    Long dst_port_no) {
 	super(RCTable.getTable(GLOBAL_LINK_TABLE_NAME), getLinkID(src_dpid,
@@ -86,6 +113,12 @@
 	status = STATUS.INACTIVE;
     }
 
+    public static RCLink createFromKey(byte[] key) {
+	long linkTuple[] = getLinkTupleFromKey(key);
+	return new RCLink(linkTuple[0], linkTuple[1], linkTuple[2],
+	        linkTuple[3]);
+    }
+
     public STATUS getStatus() {
 	return status;
     }
@@ -127,6 +160,11 @@
 	return map;
     }
 
+    @Override
+    public String toString() {
+	return "[RCLink " + src + "->" + dst + " STATUS:" + status + "]";
+    }
+
     public static void main(String[] args) {
 	// TODO Auto-generated method stub
 
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 cdaf383..5a13e3e 100644
--- a/src/main/java/net/onrc/onos/datastore/topology/RCPort.java
+++ b/src/main/java/net/onrc/onos/datastore/topology/RCPort.java
@@ -17,6 +17,7 @@
 import net.onrc.onos.datastore.RCObject;
 import net.onrc.onos.datastore.RCTable;
 import net.onrc.onos.datastore.utils.ByteArrayComparator;
+import net.onrc.onos.datastore.utils.ByteArrayUtil;
 
 public class RCPort extends RCObject {
     private static final Logger log = LoggerFactory.getLogger(RCPort.class);
@@ -74,21 +75,35 @@
 	        .putChar('P').putLong(number).array();
     }
 
-    public static long getDpidFromKey(byte[] key) {
-	ByteBuffer keyBuf = ByteBuffer.wrap(key);
+    public static long[] getPortPairFromKey(byte[] key) {
+	return getPortPairFromKey(ByteBuffer.wrap(key));
+
+    }
+
+    public static long[] getPortPairFromKey(ByteBuffer keyBuf) {
+	long[] pair = new long[2];
 	if (keyBuf.getChar() != 'S') {
-	    throw new IllegalArgumentException("Invalid Port key");
+	    throw new IllegalArgumentException("Invalid Port key:" + keyBuf
+		    + " "
+		    + ByteArrayUtil.toHexStringBuffer(keyBuf.array(), ":"));
 	}
-	return keyBuf.getLong();
+	pair[0] = keyBuf.getLong();
+	if (keyBuf.getChar() != 'P') {
+	    throw new IllegalArgumentException("Invalid Port key:" + keyBuf
+		    + " "
+		    + ByteArrayUtil.toHexStringBuffer(keyBuf.array(), ":"));
+	}
+	pair[1] = keyBuf.getLong();
+	return pair;
+
+    }
+
+    public static long getDpidFromKey(byte[] key) {
+	return getPortPairFromKey(key)[0];
     }
 
     public static long getNumberFromKey(byte[] key) {
-	ByteBuffer keyBuf = ByteBuffer.wrap(key);
-	keyBuf.position(RCSwitch.SWITCHID_BYTES);
-	if (keyBuf.getChar() != 'P') {
-	    throw new IllegalArgumentException("Invalid Port key");
-	}
-	return keyBuf.getLong();
+	return getPortPairFromKey(key)[1];
     }
 
     // FIXME specify DPID,number here, or Should caller specify the key it self?
@@ -108,7 +123,8 @@
     }
 
     public static RCPort createFromKey(byte[] key) {
-	return new RCPort(getDpidFromKey(key), getNumberFromKey(key));
+	long[] pair = getPortPairFromKey(key);
+	return new RCPort(pair[0], pair[1]);
     }
 
     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 16ff01b..de9d5a4 100644
--- a/src/main/java/net/onrc/onos/datastore/topology/RCSwitch.java
+++ b/src/main/java/net/onrc/onos/datastore/topology/RCSwitch.java
@@ -75,7 +75,10 @@
     }
 
     public static long getDpidFromKey(byte[] key) {
-	ByteBuffer keyBuf = ByteBuffer.wrap(key);
+	return getDpidFromKey(ByteBuffer.wrap(key));
+    }
+
+    public static long getDpidFromKey(ByteBuffer keyBuf) {
 	if (keyBuf.getChar() != 'S') {
 	    throw new IllegalArgumentException("Invalid Switch key");
 	}
@@ -255,10 +258,13 @@
     private static void topology_setup() {
 	log.debug("topology_setup start.");
 
+	// d1 - s1p1 - s1 - s1p2 - s2p1 - s2 - s2p2
+
 	RCSwitch sw1 = new RCSwitch(0x1L);
 	sw1.setStatus(STATUS.ACTIVE);
 	try {
 	    sw1.create();
+	    log.debug("Create {}", sw1);
 	} catch (ObjectExistsException e) {
 	    log.error("Switch creation failed", e);
 	}
@@ -269,7 +275,9 @@
 	sw1p2.setStatus(RCPort.STATUS.ACTIVE);
 	try {
 	    sw1p1.create();
+	    log.debug("Create {}", sw1p1);
 	    sw1p2.create();
+	    log.debug("Create {}", sw1p2);
 	} catch (ObjectExistsException e) {
 	    log.error("Port creation failed", e);
 	}
@@ -279,14 +287,24 @@
 	sw1.addPortId(sw1p2.getId());
 	try {
 	    sw1.update();
+	    log.debug("Update {} - {}", sw1, sw1.getAllPortIds());
 	} catch (ObjectDoesntExistException | WrongVersionException e) {
 	    log.error("Switch update failed", e);
 	}
 
 	RCDevice d1 = new RCDevice(new byte[] { 0, 1, 2, 3, 4, 5, 6 });
 	d1.addPortId(sw1p1.getId());
+	sw1p1.addDeviceId(d1.getId());
+
 	try {
 	    d1.create();
+	    log.debug("Create {}", d1);
+	    try {
+		sw1p1.update();
+	    } catch (ObjectDoesntExistException | WrongVersionException e) {
+		log.error("Link update failed", e);
+	    }
+	    log.debug("Create {}", sw1p1);
 	} catch (ObjectExistsException e) {
 	    log.error("Device creation failed", e);
 	}
@@ -305,31 +323,51 @@
 
 	RCDevice d2 = new RCDevice(new byte[] { 6, 5, 4, 3, 2, 1, 0 });
 	d2.addPortId(sw2p2.getId());
+	sw2p2.addDeviceId(d2.getId());
 
 	try {
 	    sw2.create();
+	    log.debug("Create {}", sw2);
 	    sw2p1.create();
+	    log.debug("Create {}", sw2p1);
 	    sw2p2.create();
+	    log.debug("Create {}", sw2p2);
 	    d2.create();
+	    log.debug("Create {}", d2);
 	} catch (ObjectExistsException e) {
 	    log.error("One of Switch/Port/Device creation failed", e);
 	}
 
 	RCLink l1 = new RCLink(0x1L, 2L, 0x2L, 1L);
 	l1.setStatus(RCLink.STATUS.ACTIVE);
+
+	sw1p2.addLinkId(l1.getId());
+	sw2p1.addLinkId(l1.getId());
 	try {
 	    l1.create();
+	    log.debug("Create {}", l1);
+	    try {
+		sw1p2.update();
+		log.debug("Update {}", sw1p2);
+		sw2p1.update();
+		log.debug("Update {}", sw2p1);
+	    } catch (ObjectDoesntExistException | WrongVersionException e) {
+		log.error("Port update failed", e);
+	    }
 	} catch (ObjectExistsException e) {
 	    log.error("Link creation failed", e);
 	}
+
 	log.debug("topology_setup end.");
     }
 
     private static void topology_walk() {
 	log.debug("topology_walk start.");
+
 	RCSwitch sw1 = new RCSwitch(0x1L);
 	try {
 	    sw1.read();
+	    log.debug("{}", sw1);
 	} catch (ObjectDoesntExistException e) {
 	    log.error("Reading switch failed", e);
 	}
@@ -338,6 +376,84 @@
 	assert (sw1.getStatus() == STATUS.ACTIVE);
 	assert (sw1.getAllPortIds().size() == 2);
 	for (byte[] portId : sw1.getAllPortIds()) {
+	    RCPort port = RCPort.createFromKey(portId);
+	    try {
+		port.read();
+		assert (port.getDpid() == 0x1L);
+		log.debug("Port 0x1:{} - LinkIDs:{} DeviceIDs:{}",
+		        port.getNumber(), port.getAllLinkIds(),
+		        port.getAllDeviceIds());
+
+		for (byte[] deviceId : port.getAllDeviceIds()) {
+		    RCDevice device = RCDevice.createFromKey(deviceId);
+		    try {
+			device.read();
+			log.debug("Device {} - PortIDs:{}", device.getMac(),
+			        device.getAllPortIds());
+		    } catch (ObjectDoesntExistException e) {
+			log.error("Reading Device failed", e);
+		    }
+		}
+
+		for (byte[] linkId : port.getAllLinkIds()) {
+		    RCLink link = RCLink.createFromKey(linkId);
+		    try {
+			link.read();
+			log.debug("Link {}", link);
+		    } catch (ObjectDoesntExistException e) {
+			log.error("Reading Link failed", e);
+		    }
+		}
+
+	    } catch (ObjectDoesntExistException e) {
+		log.error("Reading Port failed", e);
+	    }
+	}
+
+	RCSwitch sw2 = new RCSwitch(0x1L);
+	try {
+	    sw2.read();
+	    log.debug("{}", sw2);
+	} catch (ObjectDoesntExistException e) {
+	    log.error("Reading switch failed", e);
+	}
+
+	assert (sw2.getDpid() == 0x2L);
+	assert (sw2.getStatus() == STATUS.ACTIVE);
+	assert (sw2.getAllPortIds().size() == 2);
+	for (byte[] portId : sw2.getAllPortIds()) {
+	    RCPort port = RCPort.createFromKey(portId);
+	    try {
+		port.read();
+		assert (port.getDpid() == 0x1L);
+		log.debug("Port 0x2:{} - LinkIDs:{} DeviceIDs:{}",
+		        port.getNumber(), port.getAllLinkIds(),
+		        port.getAllDeviceIds());
+
+		for (byte[] deviceId : port.getAllDeviceIds()) {
+		    RCDevice device = RCDevice.createFromKey(deviceId);
+		    try {
+			device.read();
+			log.debug("Device {} - PortIDs:{}", device,
+			        device.getAllPortIds());
+		    } catch (ObjectDoesntExistException e) {
+			log.error("Reading Device failed", e);
+		    }
+		}
+
+		for (byte[] linkId : port.getAllLinkIds()) {
+		    RCLink link = RCLink.createFromKey(linkId);
+		    try {
+			link.read();
+			log.debug("Link {}", link);
+		    } catch (ObjectDoesntExistException e) {
+			log.error("Reading Link failed", e);
+		    }
+		}
+
+	    } catch (ObjectDoesntExistException e) {
+		log.error("Reading Port failed", e);
+	    }
 	}
 
 	log.debug("topology_walk end.");
@@ -345,6 +461,75 @@
 
     private static void topology_delete() {
 	log.debug("topology_delete start.");
+
+	// TODO implement get all kind of API
+	RCSwitch sw1 = new RCSwitch(0x1L);
+	RCPort sw1p1 = new RCPort(0x1L, 1L);
+	RCPort sw1p2 = new RCPort(0x1L, 2L);
+	RCDevice d1 = new RCDevice(new byte[] { 0, 1, 2, 3, 4, 5, 6 });
+	RCLink l1 = new RCLink(0x1L, 2L, 0x2L, 1L);
+	RCSwitch sw2 = new RCSwitch(0x2L);
+	RCPort sw2p1 = new RCPort(0x2L, 1L);
+	RCPort sw2p2 = new RCPort(0x2L, 2L);
+	RCDevice d2 = new RCDevice(new byte[] { 6, 5, 4, 3, 2, 1, 0 });
+
+	try {
+	    sw1.read();
+	    sw1.delete();
+	} catch (ObjectDoesntExistException e) {
+	    log.debug("Delete Switch Failed", e);
+	}
+	try {
+	    sw1p1.read();
+	    sw1p1.delete();
+	} catch (ObjectDoesntExistException e) {
+	    log.debug("Delete Port Failed", e);
+	}
+	try {
+	    sw1p2.read();
+	    sw1p2.delete();
+	} catch (ObjectDoesntExistException e) {
+	    log.debug("Delete Port Failed", e);
+	}
+	try {
+	    d1.read();
+	    d1.delete();
+	} catch (ObjectDoesntExistException e) {
+	    log.debug("Delete Device Failed", e);
+	}
+
+	try {
+	    l1.read();
+	    l1.delete();
+	} catch (ObjectDoesntExistException e) {
+	    log.debug("Delete Link Failed", e);
+	}
+
+	try {
+	    sw2.read();
+	    sw2.delete();
+	} catch (ObjectDoesntExistException e) {
+	    log.debug("Delete Switch Failed", e);
+	}
+	try {
+	    sw2p1.read();
+	    sw2p1.delete();
+	} catch (ObjectDoesntExistException e) {
+	    log.debug("Delete Port Failed", e);
+	}
+	try {
+	    sw2p2.read();
+	    sw2p2.delete();
+	} catch (ObjectDoesntExistException e) {
+	    log.debug("Delete Port Failed", e);
+	}
+	try {
+	    d2.read();
+	    d2.delete();
+	} catch (ObjectDoesntExistException e) {
+	    log.debug("Delete Device Failed", e);
+	}
+
 	log.debug("topology_delete end.");
     }
 
diff --git a/src/main/java/net/onrc/onos/datastore/utils/ByteArrayUtil.java b/src/main/java/net/onrc/onos/datastore/utils/ByteArrayUtil.java
new file mode 100644
index 0000000..96f8743
--- /dev/null
+++ b/src/main/java/net/onrc/onos/datastore/utils/ByteArrayUtil.java
@@ -0,0 +1,31 @@
+package net.onrc.onos.datastore.utils;
+
+import java.nio.ByteBuffer;
+
+public class ByteArrayUtil {
+
+    public static StringBuffer toHexStringBuffer(final byte[] bytes,
+	    final String sep) {
+	return toHexStringBuffer(bytes, sep, new StringBuffer());
+    }
+
+    public static StringBuffer toHexStringBuffer(final byte[] bytes,
+	    final String sep, StringBuffer buf) {
+	if (bytes == null) {
+	    return buf;
+	}
+
+	ByteBuffer wrap = ByteBuffer.wrap(bytes);
+
+	boolean hasWritten = false;
+	while (wrap.hasRemaining()) {
+	    if (hasWritten) {
+		buf.append(sep);
+	    }
+	    buf.append(Integer.toHexString(wrap.get()));
+	    hasWritten = true;
+	}
+
+	return buf;
+    }
+}