Added breadcrumbs array to topo2CurrentLayout response.
Included Region name in "closed region" data structures.

Change-Id: I1d4c223255b7ea8239f38c63d4caebe1bdeddf32
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiRegion.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiRegion.java
index 87d5036..40dec55 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/topo/UiRegion.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiRegion.java
@@ -29,6 +29,7 @@
 import java.util.Set;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Strings.isNullOrEmpty;
 import static org.onosproject.net.region.RegionId.regionId;
 
 /**
@@ -36,7 +37,8 @@
  */
 public class UiRegion extends UiNode {
 
-    private static final String NULL_NAME = "<null-region>";
+    private static final String NULL_NAME = "(root)";
+    private static final String NO_NAME = "???";
 
     /**
      * The identifier for the null-region. That is, a container for devices,
@@ -271,4 +273,20 @@
     public List<String> layerOrder() {
         return Collections.unmodifiableList(layerOrder);
     }
+
+    /**
+     * Guarantees to return a string for the name of the specified region.
+     * If region is null, we return the null region name, else we return
+     * the name as configured on the region.
+     *
+     * @param region the region whose name we require
+     * @return the region's name
+     */
+    public static String safeName(Region region) {
+        if (region == null) {
+            return NULL_NAME;
+        }
+        String name = region.name();
+        return isNullOrEmpty(name) ? NO_NAME : name;
+    }
 }
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
index 6d8ae53..6f436a5 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2Jsonifier.java
@@ -34,7 +34,6 @@
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.link.LinkService;
-import org.onosproject.net.region.Region;
 import org.onosproject.net.statistic.StatisticService;
 import org.onosproject.net.topology.TopologyService;
 import org.onosproject.ui.model.topo.UiClusterMember;
@@ -170,21 +169,33 @@
 
     /**
      * Returns a JSON representation of the layout to use for displaying in
-     * the topology view.
+     * the topology view. The identifiers and names of regions from the
+     * current to the root is included, so that the bread-crumb widget can
+     * be rendered.
      *
      * @param layout the layout to transform
+     * @param crumbs list of layouts in bread-crumb order
      * @return a JSON representation of the data
      */
-    ObjectNode layout(UiTopoLayout layout) {
-        return objectNode()
+    ObjectNode layout(UiTopoLayout layout, List<UiTopoLayout> crumbs) {
+        ObjectNode result = objectNode()
                 .put("id", layout.id().toString())
                 .put("parent", nullIsEmpty(layout.parent()))
                 .put("region", nullIsEmpty(layout.regionId()))
-                .put("regionName", regionName(layout.region()));
+                .put("regionName", UiRegion.safeName(layout.region()));
+        addCrumbs(result, crumbs);
+        return result;
     }
 
-    private String regionName(Region region) {
-        return region == null ? "" : region.name();
+    private void addCrumbs(ObjectNode result, List<UiTopoLayout> crumbs) {
+        ArrayNode trail = arrayNode();
+        crumbs.forEach(c -> {
+            ObjectNode n = objectNode()
+                    .put("id", c.regionId().toString())
+                    .put("name", UiRegion.safeName(c.region()));
+            trail.add(n);
+        });
+        result.set("crumbs", trail);
     }
 
     /**
@@ -364,6 +375,7 @@
     private ObjectNode jsonClosedRegion(UiRegion region) {
         return objectNode()
                 .put("id", region.idAsString())
+                .put("name", region.name())
                 .put("nodeType", REGION)
                 .put("nDevs", region.deviceCount());
         // TODO: complete closed-region details
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
index 86d54cc..0d4d6aa 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
@@ -118,7 +118,8 @@
 
             // this is the layout that the user has chosen to display
             UiTopoLayout currentLayout = topoSession.currentLayout();
-            sendMessage(CURRENT_LAYOUT, t2json.layout(currentLayout));
+            List<UiTopoLayout> crumbs = topoSession.breadCrumbs();
+            sendMessage(CURRENT_LAYOUT, t2json.layout(currentLayout, crumbs));
 
             // this is the region that is associated with the current layout
             //   this message includes details of the sub-regions, devices,
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java
index 44ea910..f6552dd 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoSession.java
@@ -30,6 +30,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -134,6 +135,25 @@
     }
 
     /**
+     * Returns the breadcrumb trail from current layout to root. That is,
+     * element 0 of the list will be the current layout; the last element
+     * of the list will be the root layout. This list is guaranteed to have
+     * size of at least 1.
+     *
+     * @return breadcrumb trail
+     */
+    public List<UiTopoLayout> breadCrumbs() {
+        UiTopoLayout current = currentLayout;
+        List<UiTopoLayout> crumbs = new ArrayList<>();
+        crumbs.add(current);
+        while (!current.isRoot()) {
+            current = layoutService.getLayout(current.parent());
+            crumbs.add(current);
+        }
+        return crumbs;
+    }
+
+    /**
      * Changes the current layout context to the specified layout.
      *
      * @param topoLayout new topology layout context