Added a number of demo-related artifacts. Enhanced GUI a bit.

Change-Id: I4501cb338f9eab07420fb60e347167deda5074be
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/statistic/impl/DistributedStatisticStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/statistic/impl/DistributedStatisticStore.java
index 85cc66a..718c68e 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/statistic/impl/DistributedStatisticStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/statistic/impl/DistributedStatisticStore.java
@@ -15,11 +15,7 @@
  */
 package org.onlab.onos.store.statistic.impl;
 
-import static org.onlab.onos.store.statistic.impl.StatisticStoreMessageSubjects.*;
-import static org.slf4j.LoggerFactory.getLogger;
-
 import com.google.common.collect.Sets;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -57,6 +53,10 @@
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import static org.onlab.onos.store.statistic.impl.StatisticStoreMessageSubjects.GET_CURRENT;
+import static org.onlab.onos.store.statistic.impl.StatisticStoreMessageSubjects.GET_PREVIOUS;
+import static org.slf4j.LoggerFactory.getLogger;
+
 
 /**
  * Maintains statistics using RPC calls to collect stats from remote instances
@@ -69,13 +69,13 @@
     private final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    private ReplicaInfoService replicaInfoManager;
+    protected ReplicaInfoService replicaInfoManager;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    private ClusterCommunicationService clusterCommunicator;
+    protected ClusterCommunicationService clusterCommunicator;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    private ClusterService clusterService;
+    protected ClusterService clusterService;
 
     private Map<ConnectPoint, InternalStatisticRepresentation> representations =
             new ConcurrentHashMap<>();
@@ -197,9 +197,7 @@
         ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId);
         if (!replicaInfo.master().isPresent()) {
             log.warn("No master for {}", deviceId);
-            // TODO: revisit if this should be returning empty collection.
-            // FIXME: throw a StatsStoreException
-            throw new RuntimeException("No master for " + deviceId);
+            return Collections.emptySet();
         }
         if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
             return getCurrentStatisticInternal(connectPoint);
@@ -215,8 +213,8 @@
                 return SERIALIZER.decode(response.get(STATISTIC_STORE_TIMEOUT_MILLIS,
                                                       TimeUnit.MILLISECONDS));
             } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
-                // FIXME: throw a StatsStoreException
-                throw new RuntimeException(e);
+                log.warn("Unable to communicate with peer {}", replicaInfo.master().get());
+                return Collections.emptySet();
             }
         }
 
@@ -232,9 +230,7 @@
         ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId);
         if (!replicaInfo.master().isPresent()) {
             log.warn("No master for {}", deviceId);
-            // TODO: revisit if this should be returning empty collection.
-            // FIXME: throw a StatsStoreException
-            throw new RuntimeException("No master for " + deviceId);
+            return Collections.emptySet();
         }
         if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
             return getPreviousStatisticInternal(connectPoint);
@@ -250,8 +246,8 @@
                 return SERIALIZER.decode(response.get(STATISTIC_STORE_TIMEOUT_MILLIS,
                                                       TimeUnit.MILLISECONDS));
             } catch (IOException | TimeoutException | ExecutionException | InterruptedException e) {
-                // FIXME: throw a StatsStoreException
-                throw new RuntimeException(e);
+                log.warn("Unable to communicate with peer {}", replicaInfo.master().get());
+                return Collections.emptySet();
             }
         }
 
diff --git a/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
index efb76ab..617b0ba 100644
--- a/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -20,11 +20,13 @@
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.onos.net.DefaultAnnotations;
 import org.onlab.onos.net.Device;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.MastershipRole;
 import org.onlab.onos.net.Port;
 import org.onlab.onos.net.PortNumber;
+import org.onlab.onos.net.SparseAnnotations;
 import org.onlab.onos.net.device.DefaultDeviceDescription;
 import org.onlab.onos.net.device.DefaultPortDescription;
 import org.onlab.onos.net.device.DeviceDescription;
@@ -206,13 +208,15 @@
             Device.Type deviceType = sw.isOptical() ? Device.Type.ROADM :
                     Device.Type.SWITCH;
             ChassisId cId = new ChassisId(dpid.value());
+            SparseAnnotations annotations = DefaultAnnotations.builder()
+                    .set("protocol", sw.factory().getVersion().toString()).build();
             DeviceDescription description =
                     new DefaultDeviceDescription(did.uri(), deviceType,
                                                  sw.manfacturerDescription(),
                                                  sw.hardwareDescription(),
                                                  sw.softwareDescription(),
                                                  sw.serialNumber(),
-                                                 cId);
+                                                 cId, annotations);
             providerService.deviceConnected(did, description);
             providerService.updatePorts(did, buildPortDescriptions(sw.getPorts()));
         }
diff --git a/tools/test/topos/att-onos-ext.py b/tools/test/topos/att-onos-ext.py
new file mode 100644
index 0000000..a058b64
--- /dev/null
+++ b/tools/test/topos/att-onos-ext.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+import sys
+
+from mininet.net import Mininet
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+from mininet.node import RemoteController
+from mininet.link import TCLink
+
+from attmplsext import AttMplsTopoExt
+
+setLogLevel( 'info' )
+
+def run(controllers=[ '127.0.0.1' ]):
+    net = Mininet( topo=AttMplsTopoExt(), link=TCLink, build=False, autoSetMacs=True )
+    ctrl_count = 0
+    for controllerIP in controllers:
+        net.addController( 'c%d' % ctrl_count, RemoteController, ip=controllerIP )
+    net.build()
+    net.start()
+    CLI( net )
+    net.stop()
+
+if __name__ == '__main__':
+    if len( sys.argv ) > 1:
+        controllers = sys.argv[ 1: ]
+    else:
+        print 'Usage: att-onos-ext.py <c0 IP> <c1 IP> ...'
+        exit( 1 )
+    run( controllers )
diff --git a/tools/test/topos/att-onos.py b/tools/test/topos/att-onos.py
index 930cd37..c19b0f1 100644
--- a/tools/test/topos/att-onos.py
+++ b/tools/test/topos/att-onos.py
@@ -12,7 +12,16 @@
 
 setLogLevel( 'info' )
 
+def pingloop( net ):
+    setLogLevel( 'error' )
+    try:
+        while True:
+            net.ping()
+    finally:
+        setLogLevel( 'info' )
+
 def run(controllers=[ '127.0.0.1' ]):
+    Mininet.pingloop = pingloop
     net = Mininet( topo=AttMplsTopo(), link=TCLink, build=False, autoSetMacs=True )
     ctrl_count = 0
     for controllerIP in controllers:
diff --git a/tools/test/topos/attmpls-intents b/tools/test/topos/attmpls-intents
new file mode 100755
index 0000000..f462459
--- /dev/null
+++ b/tools/test/topos/attmpls-intents
@@ -0,0 +1,8 @@
+#!/bin/bash
+# Creates some sample intents
+onos $OCI add-host-intent 00:00:00:00:00:15/-1 00:00:00:00:00:0b/-1
+onos $OCI add-host-intent 00:00:00:00:00:15/-1 00:00:00:00:00:0e/-1
+onos $OCI add-host-intent 00:00:00:00:00:10/-1 00:00:00:00:00:0a/-1
+onos $OCI add-host-intent 00:00:00:00:00:09/-1 00:00:00:00:00:0c/-1
+onos $OCI add-host-intent 00:00:00:00:00:02/-1 00:00:00:00:00:0e/-1
+onos $OCI add-host-intent 00:00:00:00:00:11/-1 00:00:00:00:00:05/-1
diff --git a/tools/test/topos/attmpls.py b/tools/test/topos/attmpls.py
index 1119042..8b75df7 100644
--- a/tools/test/topos/attmpls.py
+++ b/tools/test/topos/attmpls.py
@@ -24,14 +24,14 @@
         # add nodes, switches first...
         NY54 = self.addSwitch( 's25' ) # 40.728270, -73.994483
         CMBR = self.addSwitch( 's1' )  # 42.373730, -71.109734
-        CHCG = self.addSwitch( 's2' )  # 41.877461, -87.642892
+        CHCG = self.addSwitch( 's2', protocols='OpenFlow13' )  # 41.877461, -87.642892
         CLEV = self.addSwitch( 's3' )  # 41.498928, -81.695217
         RLGH = self.addSwitch( 's4' )  # 35.780150, -78.644026
         ATLN = self.addSwitch( 's5' )  # 33.749017, -84.394168
         PHLA = self.addSwitch( 's6' )  # 39.952906, -75.172278
         WASH = self.addSwitch( 's7' )  # 38.906696, -77.035509
         NSVL = self.addSwitch( 's8' )  # 36.166410, -86.787305
-        STLS = self.addSwitch( 's9' )  # 38.626418, -90.198143
+        STLS = self.addSwitch( 's9', protocols='OpenFlow13' )  # 38.626418, -90.198143
         NWOR = self.addSwitch( 's10' ) # 29.951475, -90.078434
         HSTN = self.addSwitch( 's11' ) # 29.763249, -95.368332
         SNAN = self.addSwitch( 's12' ) # 29.424331, -98.491745
@@ -44,7 +44,7 @@
         PTLD = self.addSwitch( 's19' ) # 45.523317, -122.677768
         STTL = self.addSwitch( 's20' ) # 47.607326, -122.331786
         SLKC = self.addSwitch( 's21' ) # 40.759577, -111.895079
-        LA03 = self.addSwitch( 's22' ) # 34.056346, -118.235951
+        LA03 = self.addSwitch( 's22', protocols='OpenFlow13' ) # 34.056346, -118.235951
         SNDG = self.addSwitch( 's23' ) # 32.714564, -117.153528
         PHNX = self.addSwitch( 's24' ) # 33.448289, -112.076299
 
diff --git a/tools/test/topos/attmplsext.json b/tools/test/topos/attmplsext.json
new file mode 100644
index 0000000..f94e7bc
--- /dev/null
+++ b/tools/test/topos/attmplsext.json
@@ -0,0 +1,18 @@
+{
+  "devices": [
+    { "alias": "s11", "uri": "of:0000001000000001", "mac": "001000000001", "annotations": { "name": "MINE", "latitude": 44.977862, "longitude":  -93.265427 }, "type": "SWITCH" },
+    { "alias": "s12", "uri": "of:0000001000000002", "mac": "001000000002", "annotations": { "name": "BISM", "latitude": 46.817887, "longitude": -100.786109 }, "type": "SWITCH" },
+    { "alias": "s13", "uri": "of:0000001000000003", "mac": "001000000003", "annotations": { "name": "BOIS", "latitude": 43.617834, "longitude": -116.216903 }, "type": "SWITCH" },
+    { "alias": "s14", "uri": "of:0000001000000004", "mac": "001000000004", "annotations": { "name": "RENO", "latitude": 39.533310, "longitude": -119.796940 }, "type": "SWITCH" },
+    { "alias": "s15", "uri": "of:0000001000000005", "mac": "001000000005", "annotations": { "name": "ALBU", "latitude": 35.109657, "longitude": -106.626698 }, "type": "SWITCH" }
+  ],
+
+  "hosts": [
+    { "alias": "h31", "mac": "00:10:00:00:00:01", "vlan": -1, "location": "of:0000001000000001/1", "ip": "10.0.0.31", "annotations": { "name": "MINE", "latitude": 46.509021, "longitude":  -93.820777 } },
+    { "alias": "h32", "mac": "00:10:00:00:00:02", "vlan": -1, "location": "of:0000001000000002/1", "ip": "10.0.0.32", "annotations": { "name": "BISM", "latitude": 48.169551, "longitude": -101.866954 } },
+    { "alias": "h33", "mac": "00:10:00:00:00:03", "vlan": -1, "location": "of:0000001000000003/1", "ip": "10.0.0.33", "annotations": { "name": "BOIS", "latitude": 44.617834, "longitude": -117.216903 } },
+    { "alias": "h34", "mac": "00:10:00:00:00:04", "vlan": -1, "location": "of:0000001000000004/1", "ip": "10.0.0.34", "annotations": { "name": "RENO", "latitude": 40.686744, "longitude": -117.886514 } },
+    { "alias": "h35", "mac": "00:10:00:00:00:05", "vlan": -1, "location": "of:0000001000000005/1", "ip": "10.0.0.35", "annotations": { "name": "ALBU", "latitude": 35.486729, "longitude": -104.231201 } }
+  ]
+
+}
diff --git a/tools/test/topos/attmplsext.py b/tools/test/topos/attmplsext.py
new file mode 100644
index 0000000..c658f52
--- /dev/null
+++ b/tools/test/topos/attmplsext.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+"""
+"""
+from mininet.topo import Topo
+from mininet.net import Mininet
+from mininet.node import RemoteController
+from mininet.node import Node
+from mininet.node import CPULimitedHost
+from mininet.link import TCLink
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+from mininet.util import dumpNodeConnections
+
+class AttMplsTopoExt( Topo ):
+    "Internet Topology Zoo Specimen."
+
+    def __init__( self ):
+        "Create a topology."
+
+        # Initialize Topology
+        Topo.__init__( self )
+
+        # add nodes, switches first...
+        MINE = self.addSwitch( 's31', dpid='0000001000000001')  # 44.977862, -93.265427
+        BISM = self.addSwitch( 's32', dpid='0000001000000002')  # 46.817887, -100.786109
+        BOIS = self.addSwitch( 's33', dpid='0000001000000003')  # 43.617834, -116.216903
+        RENO = self.addSwitch( 's34', dpid='0000001000000004')  # 39.533310, -119.796940
+        ALBU = self.addSwitch( 's35', dpid='0000001000000005')  # 35.109657, -106.626698
+
+        # ... and now hosts
+        MINE_host = self.addHost( 'h31', mac='00:10:00:00:00:01' )
+        BISM_host = self.addHost( 'h32', mac='00:10:00:00:00:02'  )
+        BOIS_host = self.addHost( 'h33', mac='00:10:00:00:00:03'  )
+        RENO_host = self.addHost( 'h34', mac='00:10:00:00:00:04'  )
+        ALBU_host = self.addHost( 'h35', mac='00:10:00:00:00:05'  )
+
+        # add edges between switch and corresponding host
+        self.addLink( MINE , MINE_host )
+        self.addLink( BISM , BISM_host )
+        self.addLink( BOIS , BOIS_host )
+        self.addLink( RENO , RENO_host )
+        self.addLink( ALBU , ALBU_host )
+
+        # add edges between switches
+        self.addLink( MINE , BISM, bw=10, delay='0.979030824185ms')
+        self.addLink( BISM , BOIS, bw=10, delay='0.806374975652ms')
+        self.addLink( BOIS , RENO, bw=10, delay='0.686192970166ms')
+        self.addLink( BOIS , ALBU, bw=10, delay='0.605826192092ms')
+        self.addLink( RENO , ALBU, bw=10, delay='1.4018238197ms')
+        self.addLink( RENO , MINE, bw=10, delay='0.232315346482ms')
+        self.addLink( BISM , ALBU, bw=10, delay='1.07297714274ms')
+
+topos = { 'att': ( lambda: AttMplsTopoExt() ) }
diff --git a/tools/test/topos/attmplsopt.json b/tools/test/topos/attmplsopt.json
new file mode 100644
index 0000000..f8a1d72
--- /dev/null
+++ b/tools/test/topos/attmplsopt.json
@@ -0,0 +1,112 @@
+{
+    "devices" : [
+        {
+            "uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": { "name": "SFO", "latitude": 37.779751, "longitude": -122.409791, "optical.regens": 0 },
+            "ports": [ { "port": 10, "speed": 100000, "type": "FIBER" },
+            { "port": 20, "speed": 0, "type": "FIBER" },
+            { "port": 50, "speed":100000, "type": "FIBER" } ]
+        },
+        {
+            "uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": { "name": "SAC", "latitude": 38.581001, "longitude": -121.497844, "optical.regens": 0 },
+            "ports": [ { "port": 20, "speed": 100000, "type": "FIBER" },
+            { "port": 30, "speed": 0, "type": "FIBER" },
+            { "port": 50, "speed": 0, "type": "FIBER" } ]
+        },
+        {
+            "uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": { "name": "LAX", "latitude": 34.056346, "longitude": -118.235951, "optical.regens": 0 },
+            "ports": [ { "port": 30, "speed": 0, "type": "FIBER" },
+            { "port": 50, "speed": 0, "type": "FIBER" },
+            { "port": 20, "speed": 0, "type": "FIBER" } ]
+        },
+        {
+            "uri": "of:0000ffffffffff04", "mac": "ffffffffffff04", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": { "name": "SDG", "latitude": 32.714564, "longitude": -117.153528, "optical.regens": 3 },
+            "ports": [ { "port": 30, "speed": 0, "type": "FIBER" },
+            { "port":50, "speed": 0, "type": "FIBER" },
+             { "port":20, "speed": 0, "type": "FIBER" }]
+        },
+        {
+            "uri": "of:0000ffffffffff05", "mac": "ffffffffffff05", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": { "name": "MSP", "latitude": 44.8, "longitude": -93.1, "optical.regens": 3 },
+            "ports": [ { "port": 20, "speed": 0, "type": "FIBER" },
+             { "port": 30, "speed": 0, "type": "FIBER" },
+             { "port": 40, "speed": 0, "type": "FIBER" },
+             { "port": 50, "speed": 0, "type": "FIBER" }]
+        },
+        {
+            "uri": "of:0000ffffffffff06", "mac": "ffffffffffff06", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": { "name": "DFW", "latitude": 32.777665, "longitude": -96.802064, "optical.regens": 3 },
+            "ports": [ { "port": 10, "speed": 0, "type": "FIBER" },
+            { "port": 20, "speed": 0, "type": "FIBER" },
+             { "port": 30, "speed": 0, "type": "FIBER" },
+             { "port": 40, "speed": 0, "type": "FIBER" },
+             { "port": 50, "speed": 0, "type": "FIBER" }]
+        },
+        {
+            "uri": "of:0000ffffffffff07", "mac": "ffffffffffff07", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": {  "name": "CHG", "latitude": 41.877461, "longitude": -87.642892, "optical.regens": 3 },
+            "ports": [ { "port": 10, "speed": 0, "type": "FIBER" },
+            { "port": 20, "speed": 0, "type": "FIBER" },
+             { "port": 30, "speed": 0, "type": "FIBER" },
+             { "port": 50, "speed": 0, "type": "FIBER" }]
+        },
+        {
+            "uri": "of:0000ffffffffff08", "mac": "ffffffffffff08", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": {  "name": "IAD", "latitude": 38.8, "longitude": -77.1, "optical.regens": 3 },
+            "ports": [ { "port": 20, "speed": 0, "type": "FIBER" },
+             { "port": 30, "speed": 0, "type": "FIBER" },
+             { "port": 50, "speed": 0, "type": "FIBER" }]
+        },
+        {
+            "uri": "of:0000ffffffffff09", "mac": "ffffffffffff09", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": { "name": "JFK", "latitude": 40.728270, "longitude": -73.994483, "optical.regens": 0 },
+            "ports": [ { "port": 10, "speed": 0, "type": "FIBER" },
+            { "port": 20, "speed": 0, "type": "FIBER" },
+            { "port": 50, "speed": 0, "type": "FIBER" }]
+        },
+        {
+            "uri": "of:0000ffffffffff0A", "mac": "ffffffffffff0A", "type": "ROADM",
+            "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
+            "annotations": { "name": "ATL", "latitude": 33.749017, "longitude": -84.394168, "optical.regens": 0 },
+            "ports": [ { "port": 10, "speed": 0, "type": "FIBER" },
+            { "port": 20, "speed": 0, "type": "FIBER" },
+            { "port": 50, "speed": 0, "type": "FIBER" }]
+        }
+    ],
+
+    "links" : [
+        { "src": "of:0000ffffffffff01/50", "dst": "of:0000ffffffffff02/30", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 48, "durable": "true" } },
+        { "src": "of:0000ffffffffff02/50", "dst": "of:0000ffffffffff03/30", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 493, "durable": "true" } },
+        { "src": "of:0000ffffffffff03/50", "dst": "of:0000ffffffffff04/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 171, "durable": "true" } },
+        { "src": "of:0000ffffffffff01/20", "dst": "of:0000ffffffffff05/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 2555, "durable": "true" } },
+        { "src": "of:0000ffffffffff02/20", "dst": "of:0000ffffffffff05/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 2539, "durable": "true" } },
+        { "src": "of:0000ffffffffff03/20", "dst": "of:0000ffffffffff06/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1979, "durable": "true" } },
+        { "src": "of:0000ffffffffff04/20", "dst": "of:0000ffffffffff06/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1867, "durable": "true" } },
+        { "src": "of:0000ffffffffff05/30", "dst": "of:0000ffffffffff06/40", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1378, "durable": "true" } },
+        { "src": "of:0000ffffffffff05/40", "dst": "of:0000ffffffffff07/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 2200, "durable": "true" } },
+        { "src": "of:0000ffffffffff06/30", "dst": "of:0000ffffffffff08/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1918, "durable": "true" } },
+        { "src": "of:0000ffffffffff07/20", "dst": "of:0000ffffffffff08/30", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 3625, "durable": "true" } },
+        { "src": "of:0000ffffffffff07/30", "dst": "of:0000ffffffffff09/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 3880, "durable": "true" } },
+        { "src": "of:0000ffffffffff08/20", "dst": "of:0000ffffffffff0A/50", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 838, "durable": "true" } },
+        { "src": "of:0000ffffffffff09/20", "dst": "of:0000ffffffffff0A/20", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM", "optical.kms": 1245, "durable": "true" } },
+
+        { "src": "of:0000000000000011/52", "dst": "of:0000ffffffffff01/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+        { "src": "of:0000000000000016/52", "dst": "of:0000ffffffffff04/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+        { "src": "of:000000000000000d/52", "dst": "of:0000ffffffffff06/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+        { "src": "of:0000000000000002/52", "dst": "of:0000ffffffffff07/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+        { "src": "of:0000000000000019/52", "dst": "of:0000ffffffffff09/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } },
+        { "src": "of:0000000000000005/52", "dst": "of:0000ffffffffff0A/10", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect", "durable": "true" } }
+    ]
+}
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewMessages.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewMessages.java
index e4f0aed..30b9da8 100644
--- a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewMessages.java
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewMessages.java
@@ -475,6 +475,7 @@
                              new Prop("H/W Version", device.hwVersion()),
                              new Prop("S/W Version", device.swVersion()),
                              new Prop("Serial Number", device.serialNumber()),
+                             new Prop("Protocol", annot.value("protocol")),
                              new Separator(),
                              new Prop("Master", master(deviceId)),
                              new Prop("Latitude", annot.value("latitude")),
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewWebSocket.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewWebSocket.java
index 7477e60..9e46da3 100644
--- a/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewWebSocket.java
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyViewWebSocket.java
@@ -263,15 +263,31 @@
 
     // Sends all devices to the client as device-added messages.
     private void sendAllDevices() {
+        // Send optical first, others later for layered rendering
         for (Device device : deviceService.getDevices()) {
-            sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
+            if (device.type() == Device.Type.ROADM) {
+                sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
+            }
+        }
+        for (Device device : deviceService.getDevices()) {
+            if (device.type() != Device.Type.ROADM) {
+                sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
+            }
         }
     }
 
     // Sends all links to the client as link-added messages.
     private void sendAllLinks() {
+        // Send optical first, others later for layered rendering
         for (Link link : linkService.getLinks()) {
-            sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
+            if (link.type() == Link.Type.OPTICAL) {
+                sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
+            }
+        }
+        for (Link link : linkService.getLinks()) {
+            if (link.type() != Link.Type.OPTICAL) {
+                sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
+            }
         }
     }
 
@@ -564,6 +580,7 @@
                 }
             } catch (Exception e) {
                 log.warn("Unable to handle traffic request due to {}", e.getMessage());
+                log.warn("Boom!", e);
             }
         }
     }