Optical  topology provider for UC1

Change-Id: I1b25c9412b5180f9dce167f8700eb84baba70486
diff --git a/utils/misc/src/main/java/org/onlab/util/HexString.java b/utils/misc/src/main/java/org/onlab/util/HexString.java
new file mode 100644
index 0000000..db12aa3
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/util/HexString.java
@@ -0,0 +1,94 @@
+package org.onlab.util;
+
+public final class HexString {
+
+    private HexString() {
+
+    }
+
+    /**
+     * Convert a string of bytes to a ':' separated hex string.
+     *
+     * @param bytes
+     * @return "0f:ca:fe:de:ad:be:ef"
+     */
+    public static String toHexString(final byte[] bytes) {
+        int i;
+        StringBuilder ret = new StringBuilder();
+        String tmp;
+        for (i = 0; i < bytes.length; i++) {
+            if (i > 0) {
+                ret.append(':');
+            }
+            tmp = Integer.toHexString((bytes[i] & 0xff));
+            if (tmp.length() == 1) {
+                ret.append('0');
+            }
+            ret.append(tmp);
+        }
+        return ret.toString();
+    }
+
+    public static String toHexString(final long val, final int padTo) {
+        char[] arr = Long.toHexString(val).toCharArray();
+        String ret = "";
+        // prepend the right number of leading zeros
+        int i = 0;
+        for (; i < (padTo * 2 - arr.length); i++) {
+            ret += "0";
+            if ((i % 2) != 0) {
+                ret += ":";
+            }
+        }
+        for (int j = 0; j < arr.length; j++) {
+            ret += arr[j];
+            if ((((i + j) % 2) != 0) && (j < (arr.length - 1))) {
+                ret += ":";
+            }
+        }
+        return ret;
+    }
+
+    public static String toHexString(final long val) {
+        return toHexString(val, 8);
+    }
+
+    /**
+     * Convert a string of hex values into a string of bytes.
+     *
+     * @param values
+     *            "0f:ca:fe:de:ad:be:ef"
+     * @return [15, 5 ,2, 5, 17]
+     * @throws NumberFormatException
+     *             If the string can not be parsed
+     */
+    public static byte[] fromHexString(final String values) {
+        String[] octets = values.split(":");
+        byte[] ret = new byte[octets.length];
+
+        for (int i = 0; i < octets.length; i++) {
+            if (octets[i].length() > 2) {
+                throw new NumberFormatException("Invalid octet length");
+            }
+            ret[i] = Integer.valueOf(octets[i], 16).byteValue();
+        }
+        return ret;
+    }
+
+    public static long toLong(String value) {
+        String[] octets = value.split(":");
+        if (octets.length > 8) {
+            throw new NumberFormatException("Input string is too big to fit in long: " + value);
+        }
+        long l = 0;
+        for (String octet: octets) {
+            if (octet.length() > 2) {
+                throw new NumberFormatException(
+                        "Each colon-separated byte component must consist of 1 or 2 hex digits: " + value);
+            }
+            short s = Short.parseShort(octet, 16);
+            l = (l << 8) + s;
+        }
+        return l;
+    }
+}
diff --git a/utils/misc/src/test/java/org/onlab/util/HexStringTest.java b/utils/misc/src/test/java/org/onlab/util/HexStringTest.java
new file mode 100644
index 0000000..c20238f
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/util/HexStringTest.java
@@ -0,0 +1,70 @@
+package org.onlab.util;
+
+import org.junit.Test;
+
+import com.esotericsoftware.minlog.Log;
+
+import junit.framework.TestCase;
+
+/**
+ * Test of the Hexstring.
+ *
+ */
+
+public class HexStringTest extends TestCase {
+
+    @Test
+    public void testMarshalling() throws Exception {
+        String dpidStr = "00:00:00:23:20:2d:16:71";
+        long dpid = HexString.toLong(dpidStr);
+        String testStr = HexString.toHexString(dpid);
+        TestCase.assertEquals(dpidStr, testStr);
+    }
+
+    @Test
+    public void testToLong() {
+        String dpidStr = "3e:1f:01:fc:72:8c:63:31";
+        long valid = 0x3e1f01fc728c6331L;
+        long testLong = HexString.toLong(dpidStr);
+        TestCase.assertEquals(valid, testLong);
+    }
+
+    @Test
+    public void testToLongMSB() {
+        String dpidStr = "ca:7c:5e:d1:64:7a:95:9b";
+        long valid = -3856102927509056101L;
+        long testLong = HexString.toLong(dpidStr);
+        TestCase.assertEquals(valid, testLong);
+    }
+
+    @Test
+    public void testToLongError() {
+        String dpidStr = "09:08:07:06:05:04:03:02:01";
+        try {
+            HexString.toLong(dpidStr);
+            fail("HexString.toLong() should have thrown a NumberFormatException");
+        } catch (NumberFormatException expected) {
+            Log.info("HexString.toLong() have thrown a NumberFormatException");
+        }
+    }
+
+    @Test
+    public void testToStringBytes() {
+        byte[] dpid = {0, 0, 0, 0, 0, 0, 0, -1 };
+        String valid = "00:00:00:00:00:00:00:ff";
+        String testString = HexString.toHexString(dpid);
+        TestCase.assertEquals(valid, testString);
+    }
+
+    @Test
+    public void testFromHexStringError() {
+        String invalidStr = "00:00:00:00:00:00:ffff";
+        try {
+            HexString.fromHexString(invalidStr);
+            fail("HexString.fromHexString() should have thrown a NumberFormatException");
+        } catch (NumberFormatException expected) {
+            Log.info("HexString.toLong() have thrown a NumberFormatException");
+        }
+    }
+}
+