Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/ClustersListCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/ClustersListCommand.java
index 355825b..6bd444a 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/ClustersListCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/ClustersListCommand.java
@@ -16,7 +16,7 @@
 public class ClustersListCommand extends TopologyCommand {
 
     private static final String FMT =
-            "id=%s, devices=%d, links=%d";
+            "id=%d, devices=%d, links=%d";
 
     protected static final Comparator<TopologyCluster> ID_COMPARATOR =
             new Comparator<TopologyCluster>() {
@@ -33,7 +33,7 @@
         Collections.sort(clusters, ID_COMPARATOR);
 
         for (TopologyCluster cluster : clusters) {
-            print(FMT, cluster.id(), cluster.deviceCount(), cluster.linkCount());
+            print(FMT, cluster.id().index(), cluster.deviceCount(), cluster.linkCount());
         }
         return null;
     }
diff --git a/core/api/src/main/javadoc/org/onlab/onos/net/packet/package.html b/core/api/src/main/javadoc/org/onlab/onos/net/packet/package.html
new file mode 100644
index 0000000..c95ee9b
--- /dev/null
+++ b/core/api/src/main/javadoc/org/onlab/onos/net/packet/package.html
@@ -0,0 +1,4 @@
+<body>
+Mechanism for processing inbound packets intercepted from the data plane and
+for emitting outbound packets onto the data plane.
+</body>
\ No newline at end of file
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyManager.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyManager.java
index 6ad8f4b..6831578 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyManager.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/topology/impl/SimpleTopologyManager.java
@@ -189,8 +189,7 @@
             TopologyEvent event = store.updateTopology(provider().id(),
                                                        topoDescription, reasons);
             if (event != null) {
-                log.info("Topology {} changed due to: {}", event.subject(),
-                         reasons == null ? "initial compute" : reasons);
+                log.info("Topology {} changed", event.subject());
                 eventDispatcher.post(event);
             }
         }
diff --git a/of/api/src/main/java/org/onlab/onos/of/controller/Dpid.java b/of/api/src/main/java/org/onlab/onos/of/controller/Dpid.java
index 02a957e..ca3d8e6 100644
--- a/of/api/src/main/java/org/onlab/onos/of/controller/Dpid.java
+++ b/of/api/src/main/java/org/onlab/onos/of/controller/Dpid.java
@@ -2,11 +2,20 @@
 
 import org.projectfloodlight.openflow.util.HexString;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.onlab.util.Tools.fromHex;
+import static org.onlab.util.Tools.toHex;
+
 /**
  * The class representing a network switch DPID.
  * This class is immutable.
  */
 public final class Dpid {
+
+    private static final String SCHEME = "of";
     private static final long UNKNOWN = 0;
     private final long value;
 
@@ -71,4 +80,40 @@
         hash += 31 * hash + (int) (value ^ value >>> 32);
         return hash;
     }
+
+    /**
+     * Returns DPID created from the given device URI.
+     *
+     * @param uri device URI
+     * @return dpid
+     */
+    public static Dpid dpid(URI uri) {
+        checkArgument(uri.getScheme().equals(SCHEME), "Unsupported URI scheme");
+        return new Dpid(fromHex(uri.getSchemeSpecificPart()));
+    }
+
+    /**
+     * Produces device URI from the given DPID.
+     *
+     * @param dpid device dpid
+     * @return device URI
+     */
+    public static URI uri(Dpid dpid) {
+        return uri(dpid.value);
+    }
+
+    /**
+     * Produces device URI from the given DPID long.
+     *
+     * @param value device dpid as long
+     * @return device URI
+     */
+    public static URI uri(long value) {
+        try {
+            return new URI(SCHEME, toHex(value), null);
+        } catch (URISyntaxException e) {
+            return null;
+        }
+    }
+
 }
diff --git a/providers/of/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/of/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
index 78316da..60e282a 100644
--- a/providers/of/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/of/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -1,13 +1,5 @@
 package org.onlab.onos.provider.of.device.impl;
 
-import static org.onlab.onos.net.DeviceId.deviceId;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -37,6 +29,14 @@
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.slf4j.Logger;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.onlab.onos.net.DeviceId.deviceId;
+import static org.onlab.onos.of.controller.Dpid.dpid;
+import static org.onlab.onos.of.controller.Dpid.uri;
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * Provider which uses an OpenFlow controller to detect network
  * infrastructure devices.
@@ -76,8 +76,7 @@
     @Deactivate
     public void deactivate() {
         for (OpenFlowSwitch sw : controller.getSwitches()) {
-            providerService.deviceDisconnected(DeviceId.deviceId("of:"
-                    + Long.toHexString(sw.getId())));
+            providerService.deviceDisconnected(DeviceId.deviceId(uri(sw.getId())));
         }
         providerRegistry.unregister(this);
         controller.removeListener(listener);
@@ -94,20 +93,17 @@
     @Override
     public void roleChanged(Device device, MastershipRole newRole) {
         switch (newRole) {
-        case MASTER:
-            controller.setRole(new Dpid(device.id().uri().getSchemeSpecificPart()),
-                    RoleState.MASTER);
-            break;
-        case STANDBY:
-            controller.setRole(new Dpid(device.id().uri().getSchemeSpecificPart()),
-                    RoleState.EQUAL);
-            break;
-        case NONE:
-            controller.setRole(new Dpid(device.id().uri().getSchemeSpecificPart()),
-                    RoleState.SLAVE);
-            break;
-        default:
-            LOG.error("Unknown Mastership state : {}", newRole);
+            case MASTER:
+                controller.setRole(dpid(device.id().uri()), RoleState.MASTER);
+                break;
+            case STANDBY:
+                controller.setRole(dpid(device.id().uri()), RoleState.EQUAL);
+                break;
+            case NONE:
+                controller.setRole(dpid(device.id().uri()), RoleState.SLAVE);
+                break;
+            default:
+                LOG.error("Unknown Mastership state : {}", newRole);
 
         }
         LOG.info("Accepting mastership role change for device {}", device.id());
@@ -119,17 +115,17 @@
             if (providerService == null) {
                 return;
             }
-            URI uri = buildURI(dpid);
+            DeviceId did = deviceId(uri(dpid));
             OpenFlowSwitch sw = controller.getSwitch(dpid);
 
             DeviceDescription description =
-                    new DefaultDeviceDescription(buildURI(dpid), Device.Type.SWITCH,
-                            sw.manfacturerDescription(),
-                            sw.hardwareDescription(),
-                            sw.softwareDescription(),
-                            sw.serialNumber());
-            providerService.deviceConnected(deviceId(uri), description);
-            providerService.updatePorts(deviceId(uri), buildPortDescriptions(sw.getPorts()));
+                    new DefaultDeviceDescription(did.uri(), Device.Type.SWITCH,
+                                                 sw.manfacturerDescription(),
+                                                 sw.hardwareDescription(),
+                                                 sw.softwareDescription(),
+                                                 sw.serialNumber());
+            providerService.deviceConnected(did, description);
+            providerService.updatePorts(did, buildPortDescriptions(sw.getPorts()));
         }
 
         @Override
@@ -137,31 +133,13 @@
             if (providerService == null) {
                 return;
             }
-            URI uri = buildURI(dpid);
-            providerService.deviceDisconnected(deviceId(uri));
+            providerService.deviceDisconnected(deviceId(uri(dpid)));
         }
 
         @Override
         public void portChanged(Dpid dpid, OFPortStatus status) {
-            final PortDescription portDescription = buildPortDescription(status.getDesc());
-            final URI uri = buildURI(dpid);
-            providerService.portStatusChanged(deviceId(uri), portDescription);
-        }
-
-        /**
-         * Given a dpid builds a URI for the device.
-         *
-         * @param dpid the dpid to build the uri from
-         * @return returns a uri of the form of:<dpidHexForm>
-         */
-        private URI buildURI(Dpid dpid) {
-            URI uri = null;
-            try {
-                uri = new URI("of", Long.toHexString(dpid.value()), null);
-            } catch (URISyntaxException e) {
-                LOG.warn("URI construction for device {} failed.", dpid);
-            }
-            return uri;
+            PortDescription portDescription = buildPortDescription(status.getDesc());
+            providerService.portStatusChanged(deviceId(uri(dpid)), portDescription);
         }
 
         /**
@@ -172,7 +150,7 @@
          */
         private List<PortDescription> buildPortDescriptions(
                 List<OFPortDesc> ports) {
-            final List<PortDescription> portDescs = new ArrayList<PortDescription>();
+            final List<PortDescription> portDescs = new ArrayList<>();
             for (OFPortDesc port : ports) {
                 portDescs.add(buildPortDescription(port));
             }
diff --git a/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/LinkDiscovery.java b/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/LinkDiscovery.java
index da89681..9f8a4d8 100644
--- a/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/LinkDiscovery.java
+++ b/providers/of/link/src/main/java/org/onlab/onos/provider/of/link/impl/LinkDiscovery.java
@@ -15,6 +15,7 @@
  ******************************************************************************/
 package org.onlab.onos.provider.of.link.impl;
 
+import static org.onlab.onos.of.controller.Dpid.uri;
 import static org.slf4j.LoggerFactory.getLogger;
 
 import java.util.Collections;
@@ -188,7 +189,7 @@
             }
         }
         ConnectPoint cp = new ConnectPoint(
-                DeviceId.deviceId("of:" + Long.toHexString(sw.getId())),
+                DeviceId.deviceId(uri(sw.getId())),
                 PortNumber.portNumber(port.getPortNo().getPortNumber()));
         linkProvider.linksVanished(cp);
 
@@ -228,7 +229,6 @@
      *
      * @param port the port
      * @return Packet_out message with LLDP data
-     * @throws PortMappingException
      */
     private OFPacketOut createLLDPPacketOut(final OFPortDesc port) {
         OFPacketOut.Builder packetOut = this.ofFactory.buildPacketOut();
@@ -249,7 +249,6 @@
      *
      * @param port the port
      * @return Packet_out message with LLDP data
-     * @throws PortMappingException
      */
     private OFPacketOut createBDDPPacketOut(final OFPortDesc port) {
         OFPacketOut.Builder packetOut = sw.factory().buildPacketOut();
@@ -295,11 +294,11 @@
             }
             this.ackProbe(srcPort);
             ConnectPoint src = new ConnectPoint(
-                    DeviceId.deviceId("of:" + Long.toHexString(srcSwitch.getId())),
+                    DeviceId.deviceId(uri(srcSwitch.getId())),
                     PortNumber.portNumber(srcPort));
 
             ConnectPoint dst = new ConnectPoint(
-                    DeviceId.deviceId("of:" + Long.toHexString(sw.getId())),
+                    DeviceId.deviceId(uri(sw.getId())),
                     PortNumber.portNumber(dstPort));
             LinkDescription ld;
             if (ethType == Ethernet.TYPE_BSN) {
@@ -357,7 +356,7 @@
                     final OFPortDesc srcPort = port;
 
                     ConnectPoint cp = new ConnectPoint(
-                            DeviceId.deviceId("of:" + Long.toHexString(sw.getId())),
+                            DeviceId.deviceId(uri(sw.getId())),
                             PortNumber.portNumber(srcPort.getPortNo().getPortNumber()));
                     linkProvider.linksVanished(cp);
                 }
diff --git a/utils/misc/src/main/java/org/onlab/util/Tools.java b/utils/misc/src/main/java/org/onlab/util/Tools.java
index e1e9ed7..5e63b84 100644
--- a/utils/misc/src/main/java/org/onlab/util/Tools.java
+++ b/utils/misc/src/main/java/org/onlab/util/Tools.java
@@ -1,5 +1,7 @@
 package org.onlab.util;
 
+import com.google.common.base.Strings;
+import com.google.common.primitives.UnsignedLongs;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
 import java.util.concurrent.ThreadFactory;
@@ -20,4 +22,34 @@
         return new ThreadFactoryBuilder().setNameFormat(pattern).build();
     }
 
+    /**
+     * Converts a string from hex to long.
+     *
+     * @param string hex number in string form; sans 0x
+     * @return long value
+     */
+    public static long fromHex(String string) {
+        return UnsignedLongs.parseUnsignedLong(string, 16);
+    }
+
+    /**
+     * Converts a long value to hex string; 16 wide and sans 0x.
+     *
+     * @param value long value
+     * @return hex string
+     */
+    public static String toHex(long value) {
+        return Strings.padStart(UnsignedLongs.toString(value, 16), 16, '0');
+    }
+
+    /**
+     * Converts a long value to hex string; 16 wide and sans 0x.
+     *
+     * @param value long value
+     * @param width string width; zero padded
+     * @return hex string
+     */
+    public static String toHex(long value, int width) {
+        return Strings.padStart(UnsignedLongs.toString(value, 16), width, '0');
+    }
 }
diff --git a/utils/misc/src/test/java/org/onlab/util/ToolsTest.java b/utils/misc/src/test/java/org/onlab/util/ToolsTest.java
new file mode 100644
index 0000000..c384176
--- /dev/null
+++ b/utils/misc/src/test/java/org/onlab/util/ToolsTest.java
@@ -0,0 +1,30 @@
+package org.onlab.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test of the miscellaneous tools.
+ */
+public class ToolsTest {
+
+    @Test
+    public void fromHex() throws Exception {
+        assertEquals(15, Tools.fromHex("0f"));
+        assertEquals(16, Tools.fromHex("10"));
+        assertEquals(65535, Tools.fromHex("ffff"));
+        assertEquals(4096, Tools.fromHex("1000"));
+        assertEquals(0xffffffffffffffffL, Tools.fromHex("ffffffffffffffff"));
+    }
+
+    @Test
+    public void toHex() throws Exception {
+        assertEquals("0f", Tools.toHex(15, 2));
+        assertEquals("ffff", Tools.toHex(65535, 4));
+        assertEquals("1000", Tools.toHex(4096, 4));
+        assertEquals("000000000000000f", Tools.toHex(15));
+        assertEquals("ffffffffffffffff", Tools.toHex(0xffffffffffffffffL));
+
+    }
+}