Simon Hunt
Committed by Gerrit Code Review

ONOS-4326: Working on topology topo2start processing.

- Added getPeers() to UiTopoLayoutService.
- Fixed wipe-out command to leave the default layout alone.
- Fixed handling of null-region (associated with default layout).
- Added refresh() method to model cache.
- Fixed regions-topo-2 device IDs

Change-Id: Iee49b47ff6702bed9751be7b63392577422d4763
...@@ -115,7 +115,12 @@ public class WipeOutCommand extends ClustersListCommand { ...@@ -115,7 +115,12 @@ public class WipeOutCommand extends ClustersListCommand {
115 private void wipeOutLayouts() { 115 private void wipeOutLayouts() {
116 print("Wiping UI layouts"); 116 print("Wiping UI layouts");
117 UiTopoLayoutService service = get(UiTopoLayoutService.class); 117 UiTopoLayoutService service = get(UiTopoLayoutService.class);
118 - service.getLayouts().forEach(service::removeLayout); 118 + // wipe out all layouts except the default, which should always be there
119 + service.getLayouts().forEach(l -> {
120 + if (!l.id().isDefault()) {
121 + service.removeLayout(l);
122 + }
123 + });
119 } 124 }
120 125
121 private void wipeOutRegions() { 126 private void wipeOutRegions() {
......
...@@ -57,6 +57,15 @@ public interface UiTopoLayoutService { ...@@ -57,6 +57,15 @@ public interface UiTopoLayoutService {
57 UiTopoLayout getLayout(UiTopoLayoutId layoutId); 57 UiTopoLayout getLayout(UiTopoLayoutId layoutId);
58 58
59 /** 59 /**
60 + * Returns the set of peer layouts of the specified layout. That is,
61 + * those layouts that share the same parent.
62 + *
63 + * @param layoutId layout identifier
64 + * @return set of peer layouts; empty set if layout has no peers
65 + */
66 + Set<UiTopoLayout> getPeers(UiTopoLayoutId layoutId);
67 +
68 + /**
60 * Returns the set of the child layouts of the specified layout. 69 * Returns the set of the child layouts of the specified layout.
61 * 70 *
62 * @param layoutId layout identifier 71 * @param layoutId layout identifier
......
...@@ -29,12 +29,27 @@ import java.util.List; ...@@ -29,12 +29,27 @@ import java.util.List;
29 import java.util.Set; 29 import java.util.Set;
30 30
31 import static com.google.common.base.MoreObjects.toStringHelper; 31 import static com.google.common.base.MoreObjects.toStringHelper;
32 +import static org.onosproject.net.region.RegionId.regionId;
32 33
33 /** 34 /**
34 * Represents a region. 35 * Represents a region.
35 */ 36 */
36 public class UiRegion extends UiNode { 37 public class UiRegion extends UiNode {
37 38
39 + private static final String NULL_NAME = "<null-region>";
40 +
41 + /**
42 + * The identifier for the null-region. That is, a container for devices,
43 + * hosts, and links for those that belong to no region.
44 + */
45 + public static final RegionId NULL_ID = regionId(NULL_NAME);
46 +
47 + private static final String[] DEFAULT_LAYER_TAGS = {
48 + UiNode.LAYER_OPTICAL,
49 + UiNode.LAYER_PACKET,
50 + UiNode.LAYER_DEFAULT
51 + };
52 +
38 // loose bindings to things in this region 53 // loose bindings to things in this region
39 private final Set<DeviceId> deviceIds = new HashSet<>(); 54 private final Set<DeviceId> deviceIds = new HashSet<>();
40 private final Set<HostId> hostIds = new HashSet<>(); 55 private final Set<HostId> hostIds = new HashSet<>();
...@@ -53,10 +68,12 @@ public class UiRegion extends UiNode { ...@@ -53,10 +68,12 @@ public class UiRegion extends UiNode {
53 * @param region backing region 68 * @param region backing region
54 */ 69 */
55 public UiRegion(UiTopology topology, Region region) { 70 public UiRegion(UiTopology topology, Region region) {
71 + // Implementation Note: if region is null, this UiRegion is being used
72 + // as a container for devices, hosts, links that belong to no region.
56 this.topology = topology; 73 this.topology = topology;
57 this.region = region; 74 this.region = region;
58 - // unless told otherwise, we'll use a single, default layer 75 +
59 - layerOrder.add(UiNode.LAYER_DEFAULT); 76 + setLayerOrder(DEFAULT_LAYER_TAGS);
60 } 77 }
61 78
62 @Override 79 @Override
...@@ -83,7 +100,7 @@ public class UiRegion extends UiNode { ...@@ -83,7 +100,7 @@ public class UiRegion extends UiNode {
83 * @return region ID 100 * @return region ID
84 */ 101 */
85 public RegionId id() { 102 public RegionId id() {
86 - return region.id(); 103 + return region == null ? NULL_ID : region.id();
87 } 104 }
88 105
89 @Override 106 @Override
...@@ -93,11 +110,12 @@ public class UiRegion extends UiNode { ...@@ -93,11 +110,12 @@ public class UiRegion extends UiNode {
93 110
94 @Override 111 @Override
95 public String name() { 112 public String name() {
96 - return region.name(); 113 + return region == null ? NULL_NAME : region.name();
97 } 114 }
98 115
99 /** 116 /**
100 - * Returns the region instance backing this UI region. 117 + * Returns the region instance backing this UI region. If this instance
118 + * represents the "null-region", the value returned will be null.
101 * 119 *
102 * @return the backing region instance 120 * @return the backing region instance
103 */ 121 */
...@@ -132,7 +150,17 @@ public class UiRegion extends UiNode { ...@@ -132,7 +150,17 @@ public class UiRegion extends UiNode {
132 * @return region type 150 * @return region type
133 */ 151 */
134 public Region.Type type() { 152 public Region.Type type() {
135 - return region.type(); 153 + return region == null ? null : region.type();
154 + }
155 +
156 +
157 + /**
158 + * Returns the count of devices in this region.
159 + *
160 + * @return the device count
161 + */
162 + public int deviceCount() {
163 + return deviceIds.size();
136 } 164 }
137 165
138 /** 166 /**
...@@ -195,7 +223,7 @@ public class UiRegion extends UiNode { ...@@ -195,7 +223,7 @@ public class UiRegion extends UiNode {
195 * optical layer should be rendered "below" nodes in the packet layer, 223 * optical layer should be rendered "below" nodes in the packet layer,
196 * this method should return: 224 * this method should return:
197 * <pre> 225 * <pre>
198 - * [UiNode.LAYER_OPTICAL, UiNode.LAYER_PACKET] 226 + * [UiNode.LAYER_OPTICAL, UiNode.LAYER_PACKET, UiNode.LAYER_DEFAULT]
199 * </pre> 227 * </pre>
200 * 228 *
201 * @return layer ordering 229 * @return layer ordering
......
...@@ -23,10 +23,13 @@ import org.onlab.util.Identifier; ...@@ -23,10 +23,13 @@ import org.onlab.util.Identifier;
23 */ 23 */
24 public final class UiTopoLayoutId extends Identifier<String> { 24 public final class UiTopoLayoutId extends Identifier<String> {
25 25
26 + private static final String DEFAULT_STR = "_default_";
27 +
26 /** 28 /**
27 * Default topology layout identifier. 29 * Default topology layout identifier.
28 */ 30 */
29 - public static final UiTopoLayoutId DEFAULT_ID = UiTopoLayoutId.layoutId("_default_"); 31 + public static final UiTopoLayoutId DEFAULT_ID =
32 + UiTopoLayoutId.layoutId(DEFAULT_STR);
30 33
31 // For serialization 34 // For serialization
32 private UiTopoLayoutId() { 35 private UiTopoLayoutId() {
...@@ -45,4 +48,13 @@ public final class UiTopoLayoutId extends Identifier<String> { ...@@ -45,4 +48,13 @@ public final class UiTopoLayoutId extends Identifier<String> {
45 public static UiTopoLayoutId layoutId(String value) { 48 public static UiTopoLayoutId layoutId(String value) {
46 return new UiTopoLayoutId(value); 49 return new UiTopoLayoutId(value);
47 } 50 }
51 +
52 + /**
53 + * Returns true if this is the identifier for the default layout.
54 + *
55 + * @return true if this is the default layout identifier
56 + */
57 + public boolean isDefault() {
58 + return DEFAULT_STR.equals(identifier);
59 + }
48 } 60 }
......
...@@ -61,6 +61,9 @@ public class UiTopology extends UiElement { ...@@ -61,6 +61,9 @@ public class UiTopology extends UiElement {
61 private final Map<HostId, UiHost> hostLookup = new HashMap<>(); 61 private final Map<HostId, UiHost> hostLookup = new HashMap<>();
62 private final Map<UiLinkId, UiLink> linkLookup = new HashMap<>(); 62 private final Map<UiLinkId, UiLink> linkLookup = new HashMap<>();
63 63
64 + // a container for devices, hosts, etc. belonging to no region
65 + private final UiRegion nullRegion = new UiRegion(this, null);
66 +
64 67
65 @Override 68 @Override
66 public String toString() { 69 public String toString() {
...@@ -89,6 +92,8 @@ public class UiTopology extends UiElement { ...@@ -89,6 +92,8 @@ public class UiTopology extends UiElement {
89 deviceLookup.clear(); 92 deviceLookup.clear();
90 hostLookup.clear(); 93 hostLookup.clear();
91 linkLookup.clear(); 94 linkLookup.clear();
95 +
96 + nullRegion.destroy();
92 } 97 }
93 98
94 99
...@@ -145,6 +150,16 @@ public class UiTopology extends UiElement { ...@@ -145,6 +150,16 @@ public class UiTopology extends UiElement {
145 } 150 }
146 151
147 /** 152 /**
153 + * Returns a reference to the null-region. That is, the container for
154 + * devices, hosts, and links that belong to no region.
155 + *
156 + * @return the null-region
157 + */
158 + public UiRegion nullRegion() {
159 + return nullRegion;
160 + }
161 +
162 + /**
148 * Returns the region with the specified identifier, or null if 163 * Returns the region with the specified identifier, or null if
149 * no such region exists. 164 * no such region exists.
150 * 165 *
...@@ -186,6 +201,15 @@ public class UiTopology extends UiElement { ...@@ -186,6 +201,15 @@ public class UiTopology extends UiElement {
186 } 201 }
187 202
188 /** 203 /**
204 + * Returns all devices in the model.
205 + *
206 + * @return all devices
207 + */
208 + public Set<UiDevice> allDevices() {
209 + return new HashSet<>(deviceLookup.values());
210 + }
211 +
212 + /**
189 * Returns the device with the specified identifier, or null if 213 * Returns the device with the specified identifier, or null if
190 * no such device exists. 214 * no such device exists.
191 * 215 *
......
...@@ -41,18 +41,18 @@ region-add r2 Region2 METRO ${host} ...@@ -41,18 +41,18 @@ region-add r2 Region2 METRO ${host}
41 region-add r3 Region3 CAMPUS ${host} 41 region-add r3 Region3 CAMPUS ${host}
42 42
43 region-add-devices r1 \ 43 region-add-devices r1 \
44 - of:0000000000000002 \ 44 + null:0000000000000002 \
45 - of:0000000000000003 \ 45 + null:0000000000000003 \
46 - of:0000000000000004 46 + null:0000000000000004
47 47
48 region-add-devices r2 \ 48 region-add-devices r2 \
49 - of:0000000000000005 \ 49 + null:0000000000000005 \
50 - of:0000000000000006 50 + null:0000000000000006
51 51
52 region-add-devices r3 \ 52 region-add-devices r3 \
53 - of:0000000000000007 \ 53 + null:0000000000000007 \
54 - of:0000000000000008 \ 54 + null:0000000000000008 \
55 - of:0000000000000009 55 + null:0000000000000009
56 56
57 regions 57 regions
58 58
......
...@@ -181,7 +181,9 @@ class Topo2Jsonifier { ...@@ -181,7 +181,9 @@ class Topo2Jsonifier {
181 return payload; 181 return payload;
182 } 182 }
183 payload.put("id", region.idAsString()); 183 payload.put("id", region.idAsString());
184 + if (subRegions != null) {
184 payload.set("subregions", jsonSubRegions(subRegions)); 185 payload.set("subregions", jsonSubRegions(subRegions));
186 + }
185 187
186 List<String> layerTags = region.layerOrder(); 188 List<String> layerTags = region.layerOrder();
187 List<Set<UiNode>> splitDevices = splitByLayer(layerTags, region.devices()); 189 List<Set<UiNode>> splitDevices = splitByLayer(layerTags, region.devices());
...@@ -226,31 +228,6 @@ class Topo2Jsonifier { ...@@ -226,31 +228,6 @@ class Topo2Jsonifier {
226 return result; 228 return result;
227 } 229 }
228 230
229 - /**
230 - * Returns a JSON payload that encapsulates the devices, hosts, links that
231 - * do not belong to any region.
232 - *
233 - * @param oDevices orphan devices
234 - * @param oHosts orphan hosts
235 - * @param oLinks orphan links
236 - * @param layerTags layer tags
237 - * @return a JSON representation of the data
238 - */
239 - ObjectNode orphans(Set<UiDevice> oDevices, Set<UiHost> oHosts,
240 - Set<UiLink> oLinks, List<String> layerTags) {
241 -
242 - ObjectNode payload = objectNode();
243 -
244 - List<Set<UiNode>> splitDevices = splitByLayer(layerTags, oDevices);
245 - List<Set<UiNode>> splitHosts = splitByLayer(layerTags, oHosts);
246 -
247 - payload.set("devices", jsonGrouped(splitDevices));
248 - payload.set("hosts", jsonGrouped(splitHosts));
249 - payload.set("links", jsonLinks(oLinks));
250 - payload.set("layerOrder", jsonStrings(layerTags));
251 -
252 - return payload;
253 - }
254 231
255 private ObjectNode json(UiNode node) { 232 private ObjectNode json(UiNode node) {
256 if (node instanceof UiRegion) { 233 if (node instanceof UiRegion) {
...@@ -270,7 +247,7 @@ class Topo2Jsonifier { ...@@ -270,7 +247,7 @@ class Topo2Jsonifier {
270 .put("id", device.idAsString()) 247 .put("id", device.idAsString())
271 .put("type", device.type()) 248 .put("type", device.type())
272 .put("online", device.isOnline()) 249 .put("online", device.isOnline())
273 - .put("master", device.master().toString()) 250 + .put("master", nullIsEmpty(device.master()))
274 .put("layer", device.layer()); 251 .put("layer", device.layer());
275 252
276 // TODO: complete device details 253 // TODO: complete device details
...@@ -303,7 +280,8 @@ class Topo2Jsonifier { ...@@ -303,7 +280,8 @@ class Topo2Jsonifier {
303 280
304 private ObjectNode jsonClosedRegion(UiRegion region) { 281 private ObjectNode jsonClosedRegion(UiRegion region) {
305 return objectNode() 282 return objectNode()
306 - .put("id", region.idAsString()); 283 + .put("id", region.idAsString())
284 + .put("nDevs", region.deviceCount());
307 // TODO: complete closed-region details 285 // TODO: complete closed-region details
308 } 286 }
309 287
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
17 package org.onosproject.ui.impl.topo; 17 package org.onosproject.ui.impl.topo;
18 18
19 import com.fasterxml.jackson.databind.node.ObjectNode; 19 import com.fasterxml.jackson.databind.node.ObjectNode;
20 -import com.google.common.collect.ImmutableList;
21 import com.google.common.collect.ImmutableSet; 20 import com.google.common.collect.ImmutableSet;
22 import org.onlab.osgi.ServiceDirectory; 21 import org.onlab.osgi.ServiceDirectory;
23 import org.onosproject.ui.RequestHandler; 22 import org.onosproject.ui.RequestHandler;
...@@ -25,9 +24,6 @@ import org.onosproject.ui.UiConnection; ...@@ -25,9 +24,6 @@ import org.onosproject.ui.UiConnection;
25 import org.onosproject.ui.UiMessageHandler; 24 import org.onosproject.ui.UiMessageHandler;
26 import org.onosproject.ui.impl.UiWebSocket; 25 import org.onosproject.ui.impl.UiWebSocket;
27 import org.onosproject.ui.model.topo.UiClusterMember; 26 import org.onosproject.ui.model.topo.UiClusterMember;
28 -import org.onosproject.ui.model.topo.UiDevice;
29 -import org.onosproject.ui.model.topo.UiHost;
30 -import org.onosproject.ui.model.topo.UiLink;
31 import org.onosproject.ui.model.topo.UiRegion; 27 import org.onosproject.ui.model.topo.UiRegion;
32 import org.onosproject.ui.model.topo.UiTopoLayout; 28 import org.onosproject.ui.model.topo.UiTopoLayout;
33 import org.slf4j.Logger; 29 import org.slf4j.Logger;
...@@ -37,8 +33,6 @@ import java.util.Collection; ...@@ -37,8 +33,6 @@ import java.util.Collection;
37 import java.util.List; 33 import java.util.List;
38 import java.util.Set; 34 import java.util.Set;
39 35
40 -import static org.onosproject.ui.model.topo.UiNode.LAYER_DEFAULT;
41 -
42 /* 36 /*
43 NOTES: 37 NOTES:
44 38
...@@ -69,7 +63,6 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { ...@@ -69,7 +63,6 @@ public class Topo2ViewMessageHandler extends UiMessageHandler {
69 private static final String CURRENT_LAYOUT = "topo2CurrentLayout"; 63 private static final String CURRENT_LAYOUT = "topo2CurrentLayout";
70 private static final String CURRENT_REGION = "topo2CurrentRegion"; 64 private static final String CURRENT_REGION = "topo2CurrentRegion";
71 private static final String PEER_REGIONS = "topo2PeerRegions"; 65 private static final String PEER_REGIONS = "topo2PeerRegions";
72 - private static final String ORPHANS = "topo2Orphans";
73 private static final String TOPO_START_DONE = "topo2StartDone"; 66 private static final String TOPO_START_DONE = "topo2StartDone";
74 67
75 68
...@@ -109,6 +102,12 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { ...@@ -109,6 +102,12 @@ public class Topo2ViewMessageHandler extends UiMessageHandler {
109 102
110 log.debug("topo2Start: {}", payload); 103 log.debug("topo2Start: {}", payload);
111 104
105 + // this may be a little heavyweight, but it might be safer to do
106 + // this than make assumptions about the order in which devices
107 + // and regions are added... and thus internal linkages set up
108 + // correctly
109 + topoSession.refreshModel();
110 +
112 // this is the list of ONOS cluster members 111 // this is the list of ONOS cluster members
113 List<UiClusterMember> instances = topoSession.getAllInstances(); 112 List<UiClusterMember> instances = topoSession.getAllInstances();
114 sendMessage(ALL_INSTANCES, t2json.instances(instances)); 113 sendMessage(ALL_INSTANCES, t2json.instances(instances));
...@@ -131,14 +130,7 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { ...@@ -131,14 +130,7 @@ public class Topo2ViewMessageHandler extends UiMessageHandler {
131 peersPayload.set("peers", t2json.closedRegions(peers)); 130 peersPayload.set("peers", t2json.closedRegions(peers));
132 sendMessage(PEER_REGIONS, peersPayload); 131 sendMessage(PEER_REGIONS, peersPayload);
133 132
134 - // return devices, hosts, links belonging to no region 133 + // finally, tell the UI that we are done : TODO review / delete??
135 - Set<UiDevice> oDevices = topoSession.getOrphanDevices();
136 - Set<UiHost> oHosts = topoSession.getOrphanHosts();
137 - Set<UiLink> oLinks = topoSession.getOrphanLinks();
138 - List<String> oLayers = getOrphanLayerOrder();
139 - sendMessage(ORPHANS, t2json.orphans(oDevices, oHosts, oLinks, oLayers));
140 -
141 - // finally, tell the UI that we are done
142 sendMessage(TOPO_START_DONE, null); 134 sendMessage(TOPO_START_DONE, null);
143 135
144 136
...@@ -154,14 +146,6 @@ public class Topo2ViewMessageHandler extends UiMessageHandler { ...@@ -154,14 +146,6 @@ public class Topo2ViewMessageHandler extends UiMessageHandler {
154 146
155 } 147 }
156 148
157 - // TODO: we need to decide on how this should really get populated.
158 - // For example, to be "backward compatible", this should really be
159 - // [ LAYER_OPTICAL, LAYER_PACKET, LAYER_DEFAULT ]
160 - private List<String> getOrphanLayerOrder() {
161 - // NOTE that LAYER_DEFAULT must always be last in the array
162 - return ImmutableList.of(LAYER_DEFAULT);
163 - }
164 -
165 private final class Topo2Stop extends RequestHandler { 149 private final class Topo2Stop extends RequestHandler {
166 private Topo2Stop() { 150 private Topo2Stop() {
167 super(TOPO2_STOP); 151 super(TOPO2_STOP);
......
...@@ -34,6 +34,7 @@ import org.onosproject.ui.model.topo.UiTopoLayoutId; ...@@ -34,6 +34,7 @@ import org.onosproject.ui.model.topo.UiTopoLayoutId;
34 import org.slf4j.Logger; 34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory; 35 import org.slf4j.LoggerFactory;
36 36
37 +import java.util.Collections;
37 import java.util.Map; 38 import java.util.Map;
38 import java.util.Objects; 39 import java.util.Objects;
39 import java.util.Set; 40 import java.util.Set;
...@@ -110,6 +111,21 @@ public class UiTopoLayoutManager implements UiTopoLayoutService { ...@@ -110,6 +111,21 @@ public class UiTopoLayoutManager implements UiTopoLayoutService {
110 } 111 }
111 112
112 @Override 113 @Override
114 + public Set<UiTopoLayout> getPeers(UiTopoLayoutId layoutId) {
115 + checkNotNull(layoutId, ID_NULL);
116 + UiTopoLayout layout = layoutMap.get(layoutId);
117 + if (layout == null) {
118 + return Collections.emptySet();
119 + }
120 +
121 + UiTopoLayoutId parentId = layout.parent();
122 + return layoutMap.values().stream()
123 + .filter(l -> !Objects.equals(l.id(), layoutId) &&
124 + Objects.equals(l.parent(), parentId))
125 + .collect(Collectors.toSet());
126 + }
127 +
128 + @Override
113 public Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId) { 129 public Set<UiTopoLayout> getChildren(UiTopoLayoutId layoutId) {
114 checkNotNull(layoutId, ID_NULL); 130 checkNotNull(layoutId, ID_NULL);
115 return layoutMap.values().stream() 131 return layoutMap.values().stream()
......
...@@ -16,21 +16,19 @@ ...@@ -16,21 +16,19 @@
16 16
17 package org.onosproject.ui.impl.topo; 17 package org.onosproject.ui.impl.topo;
18 18
19 +import org.onosproject.net.region.RegionId;
19 import org.onosproject.ui.UiTopoLayoutService; 20 import org.onosproject.ui.UiTopoLayoutService;
20 import org.onosproject.ui.impl.UiWebSocket; 21 import org.onosproject.ui.impl.UiWebSocket;
21 import org.onosproject.ui.impl.topo.model.UiModelEvent; 22 import org.onosproject.ui.impl.topo.model.UiModelEvent;
22 import org.onosproject.ui.impl.topo.model.UiModelListener; 23 import org.onosproject.ui.impl.topo.model.UiModelListener;
23 import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel; 24 import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
24 import org.onosproject.ui.model.topo.UiClusterMember; 25 import org.onosproject.ui.model.topo.UiClusterMember;
25 -import org.onosproject.ui.model.topo.UiDevice;
26 -import org.onosproject.ui.model.topo.UiHost;
27 -import org.onosproject.ui.model.topo.UiLink;
28 import org.onosproject.ui.model.topo.UiRegion; 26 import org.onosproject.ui.model.topo.UiRegion;
29 import org.onosproject.ui.model.topo.UiTopoLayout; 27 import org.onosproject.ui.model.topo.UiTopoLayout;
30 import org.slf4j.Logger; 28 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory; 29 import org.slf4j.LoggerFactory;
32 30
33 -import java.util.Collections; 31 +import java.util.HashSet;
34 import java.util.List; 32 import java.util.List;
35 import java.util.Set; 33 import java.util.Set;
36 34
...@@ -167,23 +165,23 @@ public class UiTopoSession implements UiModelListener { ...@@ -167,23 +165,23 @@ public class UiTopoSession implements UiModelListener {
167 * @return region that the layout is based upon 165 * @return region that the layout is based upon
168 */ 166 */
169 public UiRegion getRegion(UiTopoLayout layout) { 167 public UiRegion getRegion(UiTopoLayout layout) {
170 - return sharedModel.getRegion(layout.regionId()); 168 + RegionId rid = layout.regionId();
169 + return rid == null ? sharedModel.getNullRegion() : sharedModel.getRegion(rid);
171 } 170 }
172 171
173 /** 172 /**
174 * Returns the regions that are "peers" to this region. That is, based on 173 * Returns the regions that are "peers" to this region. That is, based on
175 * the layout the user is viewing, all the regions that are associated with 174 * the layout the user is viewing, all the regions that are associated with
176 - * layouts that are children of the parent layout to this layout. 175 + * layouts that share the same parent layout as this layout.
177 * 176 *
178 * @param layout the layout being viewed 177 * @param layout the layout being viewed
179 * @return all regions that are "siblings" to this layout's region 178 * @return all regions that are "siblings" to this layout's region
180 */ 179 */
181 public Set<UiRegion> getPeerRegions(UiTopoLayout layout) { 180 public Set<UiRegion> getPeerRegions(UiTopoLayout layout) {
182 - UiRegion currentRegion = getRegion(layout); 181 + Set<UiTopoLayout> peerLayouts = layoutService.getPeers(layout.id());
183 - 182 + Set<UiRegion> peers = new HashSet<>();
184 - // TODO: consult topo layout service to get hierarchy info... 183 + peerLayouts.forEach(l -> peers.add(sharedModel.getRegion(l.regionId())));
185 - // TODO: then consult shared model to get regions 184 + return peers;
186 - return Collections.emptySet();
187 } 185 }
188 186
189 /** 187 /**
...@@ -193,42 +191,16 @@ public class UiTopoSession implements UiModelListener { ...@@ -193,42 +191,16 @@ public class UiTopoSession implements UiModelListener {
193 * @return all regions that are "contained within" this layout's region 191 * @return all regions that are "contained within" this layout's region
194 */ 192 */
195 public Set<UiRegion> getSubRegions(UiTopoLayout layout) { 193 public Set<UiRegion> getSubRegions(UiTopoLayout layout) {
196 - UiRegion currentRegion = getRegion(layout); 194 + Set<UiTopoLayout> kidLayouts = layoutService.getChildren(layout.id());
197 - 195 + Set<UiRegion> kids = new HashSet<>();
198 - // TODO: consult topo layout service to get child layouts... 196 + kidLayouts.forEach(l -> kids.add(sharedModel.getRegion(l.regionId())));
199 - // TODO: then consult shared model to get regions 197 + return kids;
200 - return Collections.emptySet();
201 } 198 }
202 199
203 -
204 /** 200 /**
205 - * Returns all devices that are not in a region. 201 + * Refreshes the model's internal state.
206 - *
207 - * @return all devices not in a region
208 */ 202 */
209 - public Set<UiDevice> getOrphanDevices() { 203 + public void refreshModel() {
210 - // TODO: get devices with no region 204 + sharedModel.refresh();
211 - return Collections.emptySet();
212 } 205 }
213 -
214 - /**
215 - * Returns all hosts that are not in a region.
216 - *
217 - * @return all hosts not in a region
218 - */
219 - public Set<UiHost> getOrphanHosts() {
220 - // TODO: get hosts with no region
221 - return Collections.emptySet();
222 - }
223 -
224 - /**
225 - * Returns all links that are not in a region.
226 - *
227 - * @return all links not in a region
228 - */
229 - public Set<UiLink> getOrphanLinks() {
230 - // TODO: get links with no region
231 - return Collections.emptySet();
232 - }
233 -
234 } 206 }
......
...@@ -41,6 +41,7 @@ import org.onosproject.ui.model.topo.UiTopology; ...@@ -41,6 +41,7 @@ import org.onosproject.ui.model.topo.UiTopology;
41 import org.slf4j.Logger; 41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory; 42 import org.slf4j.LoggerFactory;
43 43
44 +import java.util.HashSet;
44 import java.util.List; 45 import java.util.List;
45 import java.util.Set; 46 import java.util.Set;
46 47
...@@ -169,18 +170,38 @@ class ModelCache { ...@@ -169,18 +170,38 @@ class ModelCache {
169 // TODO: post event 170 // TODO: post event
170 } 171 }
171 172
173 + // === THE NULL REGION
174 +
175 + UiRegion nullRegion() {
176 + return uiTopology.nullRegion();
177 + }
172 178
173 // === REGIONS 179 // === REGIONS
174 180
175 private UiRegion addNewRegion(Region r) { 181 private UiRegion addNewRegion(Region r) {
176 UiRegion region = new UiRegion(uiTopology, r); 182 UiRegion region = new UiRegion(uiTopology, r);
177 uiTopology.add(region); 183 uiTopology.add(region);
184 + log.debug("Region {} added to topology", region);
178 return region; 185 return region;
179 } 186 }
180 187
181 private void updateRegion(UiRegion region) { 188 private void updateRegion(UiRegion region) {
182 - Set<DeviceId> devs = services.region().getRegionDevices(region.id()); 189 + RegionId rid = region.id();
183 - region.reconcileDevices(devs); 190 + Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
191 +
192 + // Make sure device objects refer to their region
193 + deviceIds.forEach(d -> {
194 + UiDevice dev = uiTopology.findDevice(d);
195 + if (dev != null) {
196 + dev.setRegionId(rid);
197 + } else {
198 + // if we don't have the UiDevice in the topology, what can we do?
199 + log.warn("Region device {}, but we don't have UiDevice in topology", d);
200 + }
201 + });
202 +
203 + // Make sure the region object refers to the devices
204 + region.reconcileDevices(deviceIds);
184 } 205 }
185 206
186 private void loadRegions() { 207 private void loadRegions() {
...@@ -224,21 +245,22 @@ class ModelCache { ...@@ -224,21 +245,22 @@ class ModelCache {
224 245
225 private UiDevice addNewDevice(Device d) { 246 private UiDevice addNewDevice(Device d) {
226 UiDevice device = new UiDevice(uiTopology, d); 247 UiDevice device = new UiDevice(uiTopology, d);
248 + updateDevice(device);
227 uiTopology.add(device); 249 uiTopology.add(device);
250 + log.debug("Device {} added to topology", device);
228 return device; 251 return device;
229 } 252 }
230 253
254 + // make sure the UiDevice is tagged with the region it belongs to
231 private void updateDevice(UiDevice device) { 255 private void updateDevice(UiDevice device) {
232 - Region regionForDevice = services.region().getRegionForDevice(device.id()); 256 + Region r = services.region().getRegionForDevice(device.id());
233 - if (regionForDevice != null) { 257 + RegionId rid = r == null ? UiRegion.NULL_ID : r.id();
234 - device.setRegionId(regionForDevice.id()); 258 + device.setRegionId(rid);
235 - }
236 } 259 }
237 260
238 private void loadDevices() { 261 private void loadDevices() {
239 for (Device d : services.device().getDevices()) { 262 for (Device d : services.device().getDevices()) {
240 - UiDevice device = addNewDevice(d); 263 + addNewDevice(d);
241 - updateDevice(device);
242 } 264 }
243 } 265 }
244 266
...@@ -248,8 +270,9 @@ class ModelCache { ...@@ -248,8 +270,9 @@ class ModelCache {
248 UiDevice uiDevice = uiTopology.findDevice(id); 270 UiDevice uiDevice = uiTopology.findDevice(id);
249 if (uiDevice == null) { 271 if (uiDevice == null) {
250 uiDevice = addNewDevice(device); 272 uiDevice = addNewDevice(device);
251 - } 273 + } else {
252 updateDevice(uiDevice); 274 updateDevice(uiDevice);
275 + }
253 276
254 postEvent(DEVICE_ADDED_OR_UPDATED, uiDevice); 277 postEvent(DEVICE_ADDED_OR_UPDATED, uiDevice);
255 } 278 }
...@@ -434,6 +457,43 @@ class ModelCache { ...@@ -434,6 +457,43 @@ class ModelCache {
434 } 457 }
435 458
436 459
460 + /**
461 + * Refreshes the internal state.
462 + */
463 + public void refresh() {
464 + // fix up internal linkages if they aren't correct
465 +
466 + // at the moment, this is making sure devices are in the correct region
467 + Set<UiDevice> allDevices = uiTopology.allDevices();
468 +
469 + services.region().getRegions().forEach(r -> {
470 + RegionId rid = r.id();
471 + UiRegion region = uiTopology.findRegion(rid);
472 + if (region != null) {
473 + Set<DeviceId> deviceIds = services.region().getRegionDevices(rid);
474 + region.reconcileDevices(deviceIds);
475 +
476 + deviceIds.forEach(devId -> {
477 + UiDevice dev = uiTopology.findDevice(devId);
478 + if (dev != null) {
479 + dev.setRegionId(r.id());
480 + allDevices.remove(dev);
481 + } else {
482 + log.warn("Region device ID {} but no UiDevice in topology",
483 + devId);
484 + }
485 + });
486 + } else {
487 + log.warn("No UiRegion in topology for ID {}", rid);
488 + }
489 + });
490 +
491 + // what is left over, must belong to the null-region
492 + Set<DeviceId> leftOver = new HashSet<>(allDevices.size());
493 + allDevices.forEach(d -> leftOver.add(d.id()));
494 + uiTopology.nullRegion().reconcileDevices(leftOver);
495 + }
496 +
437 // === CACHE STATISTICS 497 // === CACHE STATISTICS
438 498
439 /** 499 /**
......
...@@ -217,6 +217,22 @@ public final class UiSharedTopologyModel ...@@ -217,6 +217,22 @@ public final class UiSharedTopologyModel
217 return cache.accessRegion(id); 217 return cache.accessRegion(id);
218 } 218 }
219 219
220 + /**
221 + * Returns the null region.
222 + *
223 + * @return the null region
224 + */
225 + public UiRegion getNullRegion() {
226 + return cache.nullRegion();
227 + }
228 +
229 + /**
230 + * Refreshes the cache's internal state.
231 + */
232 + public void refresh() {
233 + cache.refresh();
234 + }
235 +
220 // ===================================================================== 236 // =====================================================================
221 237
222 238
......
1 { 1 {
2 "event": "topo2CurrentRegion", 2 "event": "topo2CurrentRegion",
3 "payload": { 3 "payload": {
4 - "note": "no-region" 4 + "id": "<null-region>",
5 + "subregions": [{
6 + "id": "r2",
7 + "nDevs": 2
8 + }, {
9 + "id": "r1",
10 + "nDevs": 3
11 + }],
12 + "devices": [
13 + [],
14 + [],
15 + [{
16 + "id": "null:0000000000000001",
17 + "type": "switch",
18 + "online": false,
19 + "master": "",
20 + "layer": "def"
21 + }]
22 + ],
23 + "hosts": [
24 + [],
25 + [],
26 + []
27 + ],
28 + "links": [],
29 + "layerOrder": ["opt", "pkt", "def"]
5 } 30 }
6 } 31 }
......
1 -{
2 - "event": "topo2Orphans",
3 - "payload": {
4 - "devices": [
5 - []
6 - ],
7 - "hosts": [
8 - []
9 - ],
10 - "links": [],
11 - "layerOrder": ["def"]
12 - }
13 -}