ONOS-4971: Synthetic Link Data -- WIP
- Enhancing UiRegion to capture the hierarchical (parent/child) relationships captured in the UiTopoLayouts.
Change-Id: I152e0d52d4580b14b679f3387402077f16f61e6a
diff --git a/core/api/src/main/java/org/onosproject/ui/UiTopoLayoutService.java b/core/api/src/main/java/org/onosproject/ui/UiTopoLayoutService.java
index 0036521..c6ae247 100644
--- a/core/api/src/main/java/org/onosproject/ui/UiTopoLayoutService.java
+++ b/core/api/src/main/java/org/onosproject/ui/UiTopoLayoutService.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.ui;
+import org.onosproject.net.region.RegionId;
import org.onosproject.ui.model.topo.UiTopoLayout;
import org.onosproject.ui.model.topo.UiTopoLayoutId;
@@ -57,6 +58,15 @@
UiTopoLayout getLayout(UiTopoLayoutId layoutId);
/**
+ * Returns the layout which has the backing region identified by
+ * the given region identifier.
+ *
+ * @param regionId region identifier
+ * @return corresponding layout
+ */
+ UiTopoLayout getLayout(RegionId regionId);
+
+ /**
* Returns the set of peer layouts of the specified layout. That is,
* those layouts that share the same parent.
*
diff --git a/core/api/src/main/java/org/onosproject/ui/model/ServiceBundle.java b/core/api/src/main/java/org/onosproject/ui/model/ServiceBundle.java
index 61cf721..6986cf7 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/ServiceBundle.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/ServiceBundle.java
@@ -24,11 +24,20 @@
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.region.RegionService;
+import org.onosproject.ui.UiTopoLayoutService;
/**
* A bundle of services to pass to elements that might need a reference to them.
*/
public interface ServiceBundle {
+
+ /**
+ * Reference to a UI Topology Layout service implementation.
+ *
+ * @return layout service
+ */
+ UiTopoLayoutService layout();
+
/**
* Reference to a cluster service implementation.
*
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 c478424..b3185f1 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
@@ -61,6 +61,10 @@
private final Region region;
+ // keep track of hierarchy (inferred from UiTopoLayoutService)
+ private RegionId parent;
+ private final Set<RegionId> kids = new HashSet<>();
+
/**
* Constructs a UI region, with a reference to the specified backing region.
*
@@ -103,6 +107,52 @@
return region == null ? NULL_ID : region.id();
}
+ /**
+ * Returns the identity of the parent region.
+ *
+ * @return parent region ID
+ */
+ public RegionId parent() {
+ return parent;
+ }
+
+ /**
+ * Returns true if this is the root (default) region.
+ *
+ * @return true if root region
+ */
+ public boolean isRoot() {
+ return id().equals(parent);
+ }
+
+ /**
+ * Returns the identities of the child regions.
+ *
+ * @return child region IDs
+ */
+ public Set<RegionId> children() {
+ return ImmutableSet.copyOf(kids);
+ }
+
+ /**
+ * Sets the parent ID for this region.
+ *
+ * @param parentId parent ID
+ */
+ public void setParent(RegionId parentId) {
+ parent = parentId;
+ }
+
+ /**
+ * Sets the children IDs for this region.
+ *
+ * @param children children IDs
+ */
+ public void setChildren(Set<RegionId> children) {
+ kids.clear();
+ kids.addAll(children);
+ }
+
@Override
public String idAsString() {
return id().toString();
@@ -138,6 +188,8 @@
return toStringHelper(this)
.add("id", id())
.add("name", name())
+ .add("parent", parent)
+ .add("kids", kids)
.add("devices", deviceIds)
.add("#hosts", hostIds.size())
.add("#links", uiLinkIds.size())
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java
index 12c9de6..ade86e1 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java
@@ -68,13 +68,16 @@
}
/**
- * Returns the identifier of the backing region. Will be null if the
- * region is null.
+ * Returns the identifier of the backing region. If this is the default
+ * layout, the null-region ID will be returned, otherwise the ID of the
+ * backing region for this layout will be returned; null in the case that
+ * there is no backing region.
*
* @return backing region identifier
*/
public RegionId regionId() {
- return region == null ? null : region.id();
+ return isRoot() ? UiRegion.NULL_ID
+ : (region == null ? null : region.id());
}
/**
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopology.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopology.java
index 585e658..708fd18 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopology.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopology.java
@@ -151,7 +151,8 @@
/**
- * Returns all regions in the model.
+ * Returns all regions in the model (except the
+ * {@link #nullRegion() null region}).
*
* @return all regions
*/
@@ -177,7 +178,7 @@
* @return corresponding UI region
*/
public UiRegion findRegion(RegionId id) {
- return regionLookup.get(id);
+ return UiRegion.NULL_ID.equals(id) ? nullRegion() : regionLookup.get(id);
}
/**
diff --git a/core/api/src/test/java/org/onosproject/ui/model/AbstractUiModelTest.java b/core/api/src/test/java/org/onosproject/ui/model/AbstractUiModelTest.java
index 5037832..15b3870 100644
--- a/core/api/src/test/java/org/onosproject/ui/model/AbstractUiModelTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/model/AbstractUiModelTest.java
@@ -28,6 +28,7 @@
import org.onosproject.net.link.LinkService;
import org.onosproject.net.region.RegionService;
import org.onosproject.ui.AbstractUiTest;
+import org.onosproject.ui.UiTopoLayoutService;
/**
* Base class for UI model unit tests.
@@ -42,6 +43,11 @@
protected static final ServiceBundle MOCK_SERVICES =
new ServiceBundle() {
@Override
+ public UiTopoLayoutService layout() {
+ return null;
+ }
+
+ @Override
public ClusterService cluster() {
return MOCK_CLUSTER;
}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java
index fcf4c46..cdd95cf 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java
@@ -24,17 +24,20 @@
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.KryoNamespace;
+import org.onosproject.net.region.RegionId;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
import org.onosproject.ui.UiTopoLayoutService;
+import org.onosproject.ui.model.topo.UiRegion;
import org.onosproject.ui.model.topo.UiTopoLayout;
import org.onosproject.ui.model.topo.UiTopoLayoutId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -111,6 +114,18 @@
}
@Override
+ public UiTopoLayout getLayout(RegionId regionId) {
+ if (regionId == null || regionId.equals(UiRegion.NULL_ID)) {
+ return getRootLayout();
+ }
+
+ List<UiTopoLayout> matchingLayouts = layoutMap.values().stream()
+ .filter(l -> Objects.equals(regionId, l.regionId()))
+ .collect(Collectors.toList());
+ return matchingLayouts.isEmpty() ? null : matchingLayouts.get(0);
+ }
+
+ @Override
public Set<UiTopoLayout> getPeerLayouts(UiTopoLayoutId layoutId) {
checkNotNull(layoutId, ID_NULL);
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/cli/ListRegions.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/cli/ListRegions.java
index cdb8bd5..70e0826 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/cli/ListRegions.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/cli/ListRegions.java
@@ -29,6 +29,7 @@
@Override
protected void execute() {
UiSharedTopologyModel model = get(UiSharedTopologyModel.class);
+ print("%s", model.getNullRegion());
sorted(model.getRegions()).forEach(r -> print("%s", r));
}
}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/ModelCache.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/ModelCache.java
index 4ca6b42..781650d 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/ModelCache.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/ModelCache.java
@@ -29,6 +29,7 @@
import org.onosproject.net.Link;
import org.onosproject.net.region.Region;
import org.onosproject.net.region.RegionId;
+import org.onosproject.ui.UiTopoLayoutService;
import org.onosproject.ui.model.ServiceBundle;
import org.onosproject.ui.model.topo.UiClusterMember;
import org.onosproject.ui.model.topo.UiDevice;
@@ -37,6 +38,8 @@
import org.onosproject.ui.model.topo.UiLink;
import org.onosproject.ui.model.topo.UiLinkId;
import org.onosproject.ui.model.topo.UiRegion;
+import org.onosproject.ui.model.topo.UiTopoLayout;
+import org.onosproject.ui.model.topo.UiTopoLayoutId;
import org.onosproject.ui.model.topo.UiTopology;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -202,6 +205,34 @@
// Make sure the region object refers to the devices
region.reconcileDevices(deviceIds);
+
+ fixupContainmentHierarchy(region);
+ }
+
+ private void fixupContainmentHierarchy(UiRegion region) {
+ UiTopoLayoutService ls = services.layout();
+ RegionId regionId = region.id();
+
+ UiTopoLayout layout = ls.getLayout(regionId);
+ if (layout == null) {
+ // no layout backed by this region
+ log.warn("No layout backed by region {}", regionId);
+ return;
+ }
+
+ UiTopoLayoutId layoutId = layout.id();
+
+ if (!layout.isRoot()) {
+ UiTopoLayoutId parentId = layout.parent();
+ UiTopoLayout parentLayout = ls.getLayout(parentId);
+ RegionId parentRegionId = parentLayout.regionId();
+ region.setParent(parentRegionId);
+ }
+
+ Set<UiTopoLayout> kids = ls.getChildren(layoutId);
+ Set<RegionId> kidRegionIds = new HashSet<>(kids.size());
+ kids.forEach(k -> kidRegionIds.add(k.regionId()));
+ region.setChildren(kidRegionIds);
}
private void loadRegions() {
@@ -478,7 +509,11 @@
public void refresh() {
// fix up internal linkages if they aren't correct
- // at the moment, this is making sure devices are in the correct region
+ // make sure regions reflect layout containment hierarchy
+ fixupContainmentHierarchy(uiTopology.nullRegion());
+ uiTopology.allRegions().forEach(this::fixupContainmentHierarchy);
+
+ // make sure devices are in the correct region
Set<UiDevice> allDevices = uiTopology.allDevices();
services.region().getRegions().forEach(r -> {
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java
index 4a5cc91..a12e34d 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/model/UiSharedTopologyModel.java
@@ -60,6 +60,7 @@
import org.onosproject.net.region.RegionService;
import org.onosproject.net.statistic.StatisticService;
import org.onosproject.net.topology.TopologyService;
+import org.onosproject.ui.UiTopoLayoutService;
import org.onosproject.ui.impl.topo.UiTopoSession;
import org.onosproject.ui.model.ServiceBundle;
import org.onosproject.ui.model.topo.UiClusterMember;
@@ -87,6 +88,9 @@
LoggerFactory.getLogger(UiSharedTopologyModel.class);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private UiTopoLayoutService layoutService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private ClusterService clusterService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private MastershipService mastershipService;
@@ -282,6 +286,11 @@
*/
private class DefaultServiceBundle implements ServiceBundle {
@Override
+ public UiTopoLayoutService layout() {
+ return layoutService;
+ }
+
+ @Override
public ClusterService cluster() {
return clusterService;
}
diff --git a/web/gui/src/test/java/org/onosproject/ui/impl/topo/model/AbstractTopoModelTest.java b/web/gui/src/test/java/org/onosproject/ui/impl/topo/model/AbstractTopoModelTest.java
index 75a405e..de7ec9a 100644
--- a/web/gui/src/test/java/org/onosproject/ui/impl/topo/model/AbstractTopoModelTest.java
+++ b/web/gui/src/test/java/org/onosproject/ui/impl/topo/model/AbstractTopoModelTest.java
@@ -54,8 +54,11 @@
import org.onosproject.net.region.RegionId;
import org.onosproject.net.region.RegionListener;
import org.onosproject.net.region.RegionService;
+import org.onosproject.ui.UiTopoLayoutService;
import org.onosproject.ui.impl.AbstractUiImplTest;
import org.onosproject.ui.model.ServiceBundle;
+import org.onosproject.ui.model.topo.UiTopoLayout;
+import org.onosproject.ui.model.topo.UiTopoLayoutId;
import java.util.ArrayList;
import java.util.Collections;
@@ -69,6 +72,7 @@
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.HostId.hostId;
import static org.onosproject.net.PortNumber.portNumber;
+import static org.onosproject.ui.model.topo.UiTopoLayoutId.layoutId;
/**
* Base class for model test classes.
@@ -90,6 +94,12 @@
Twelve hosts (two per D4 ... D9) H4a, H4b, H5a, H5b, ...
+ Layouts:
+ LROOT : (default)
+ +-- L1 : R1
+ +-- L2 : R2
+ +-- L3 : R3
+
Regions:
R1 : D1, D2, D3
R2 : D4, D5, D6
@@ -136,6 +146,27 @@
protected static final Set<Region> REGION_SET =
ImmutableSet.of(REGION_1, REGION_2, REGION_3);
+ protected static final String LROOT = "LROOT";
+ protected static final String L1 = "L1";
+ protected static final String L2 = "L2";
+ protected static final String L3 = "L3";
+
+ protected static final UiTopoLayout LAYOUT_ROOT = layout(LROOT, null, null);
+ protected static final UiTopoLayout LAYOUT_1 = layout(L1, REGION_1, LROOT);
+ protected static final UiTopoLayout LAYOUT_2 = layout(L2, REGION_2, LROOT);
+ protected static final UiTopoLayout LAYOUT_3 = layout(L3, REGION_3, LROOT);
+
+ protected static final Set<UiTopoLayout> LAYOUT_SET =
+ ImmutableSet.of(LAYOUT_ROOT, LAYOUT_1, LAYOUT_2, LAYOUT_3);
+ protected static final Set<UiTopoLayout> ROOT_KIDS =
+ ImmutableSet.of(LAYOUT_1, LAYOUT_2, LAYOUT_3);
+ protected static final Set<UiTopoLayout> PEERS_OF_1 =
+ ImmutableSet.of(LAYOUT_2, LAYOUT_3);
+ protected static final Set<UiTopoLayout> PEERS_OF_2 =
+ ImmutableSet.of(LAYOUT_1, LAYOUT_3);
+ protected static final Set<UiTopoLayout> PEERS_OF_3 =
+ ImmutableSet.of(LAYOUT_1, LAYOUT_2);
+
protected static final String D1 = "d1";
protected static final String D2 = "d2";
protected static final String D3 = "d3";
@@ -222,6 +253,21 @@
}
/**
+ * Returns UI topology layout instance with the specified parameters.
+ *
+ * @param layoutId the layout ID
+ * @param region the backing region
+ * @param parentId the parent layout ID
+ * @return layout instance
+ */
+ protected static UiTopoLayout layout(String layoutId, Region region,
+ String parentId) {
+ UiTopoLayoutId pid = parentId == null
+ ? UiTopoLayoutId.DEFAULT_ID : layoutId(parentId);
+ return new UiTopoLayout(layoutId(layoutId), region, pid);
+ }
+
+ /**
* Returns a region instance with specified parameters.
*
* @param id region id
@@ -255,6 +301,11 @@
protected static final ServiceBundle MOCK_SERVICES =
new ServiceBundle() {
@Override
+ public UiTopoLayoutService layout() {
+ return MOCK_LAYOUT;
+ }
+
+ @Override
public ClusterService cluster() {
return MOCK_CLUSTER;
}
@@ -297,6 +348,7 @@
private static final ClusterService MOCK_CLUSTER = new MockClusterService();
private static final MastershipService MOCK_MASTER = new MockMasterService();
+ private static final UiTopoLayoutService MOCK_LAYOUT = new MockLayoutService();
private static final RegionService MOCK_REGION = new MockRegionService();
private static final DeviceService MOCK_DEVICE = new MockDeviceService();
private static final LinkService MOCK_LINK = new MockLinkService();
@@ -384,6 +436,71 @@
}
}
+ // TODO: consider implementing UiTopoLayoutServiceAdapter and extending that here
+ private static class MockLayoutService implements UiTopoLayoutService {
+ private final Map<UiTopoLayoutId, UiTopoLayout> map = new HashMap<>();
+ private final Map<UiTopoLayoutId, Set<UiTopoLayout>> peers = new HashMap<>();
+ private final Map<RegionId, UiTopoLayout> byRegion = new HashMap<>();
+
+ MockLayoutService() {
+ map.put(LAYOUT_ROOT.id(), LAYOUT_ROOT);
+ map.put(LAYOUT_1.id(), LAYOUT_1);
+ map.put(LAYOUT_2.id(), LAYOUT_2);
+ map.put(LAYOUT_3.id(), LAYOUT_3);
+
+ peers.put(LAYOUT_ROOT.id(), ImmutableSet.of());
+ peers.put(LAYOUT_1.id(), ImmutableSet.of(LAYOUT_2, LAYOUT_3));
+ peers.put(LAYOUT_2.id(), ImmutableSet.of(LAYOUT_1, LAYOUT_3));
+ peers.put(LAYOUT_3.id(), ImmutableSet.of(LAYOUT_1, LAYOUT_2));
+
+ byRegion.put(REGION_1.id(), LAYOUT_1);
+ byRegion.put(REGION_2.id(), LAYOUT_2);
+ byRegion.put(REGION_3.id(), LAYOUT_3);
+ }
+
+ @Override
+ public UiTopoLayout getRootLayout() {
+ return LAYOUT_ROOT;
+ }
+
+ @Override
+ public Set<UiTopoLayout> getLayouts() {
+ return LAYOUT_SET;
+ }
+
+ @Override
+ public boolean addLayout(UiTopoLayout layout) {
+ return false;
+ }
+
+ @Override
+ public UiTopoLayout getLayout(UiTopoLayoutId layoutId) {
+ return map.get(layoutId);
+ }
+
+ @Override
+ public UiTopoLayout getLayout(RegionId regionId) {
+ return byRegion.get(regionId);
+ }
+
+ @Override
+ public Set<UiTopoLayout> getPeerLayouts(UiTopoLayoutId layoutId) {
+ return peers.get(layoutId);
+ }
+
+ @Override
+ public Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId) {
+ return LAYOUT_ROOT.id().equals(layoutId)
+ ? ROOT_KIDS
+ : Collections.emptySet();
+ }
+
+ @Override
+ public boolean removeLayout(UiTopoLayout layout) {
+ return false;
+ }
+ }
+
// TODO: consider implementing RegionServiceAdapter and extending that here
private static class MockRegionService implements RegionService {