Simon Hunt
Committed by Gerrit Code Review

ONOS-3347 - HostMoved event now processed correctly.

- added new DefaultHashMap utility class
- updated TopoViewMsgHdlrBase for cleaner event translation.

Change-Id: I1c5e8c981e2d617366c25f497dc9336e09684a2e
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onlab.util;
18 +
19 +import java.util.HashMap;
20 +
21 +/**
22 + * HashMap that returns a default value for unmapped keys.
23 + */
24 +public class DefaultHashMap<K, V> extends HashMap<K, V> {
25 +
26 + /** Default value to return when no key binding exists. */
27 + protected V defaultValue;
28 +
29 + /**
30 + * Constructs an empty map with the given default value.
31 + *
32 + * @param defaultValue the default value
33 + */
34 + public DefaultHashMap(V defaultValue) {
35 + this.defaultValue = defaultValue;
36 + }
37 +
38 + @Override
39 + public V get(Object k) {
40 + return containsKey(k) ? super.get(k) : defaultValue;
41 + }
42 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onlab.util;
18 +
19 +import org.junit.Test;
20 +
21 +import static org.junit.Assert.assertEquals;
22 +
23 +/**
24 + * Unit tests for {@link DefaultHashMap}.
25 + */
26 +public class DefaultHashMapTest {
27 +
28 + private static final String ONE = "one";
29 + private static final String TWO = "two";
30 + private static final String THREE = "three";
31 + private static final String FOUR = "four";
32 +
33 + private static final String ALPHA = "Alpha";
34 + private static final String BETA = "Beta";
35 + private static final String OMEGA = "Omega";
36 +
37 + private DefaultHashMap<String, Integer> map;
38 + private DefaultHashMap<String, String> chartis;
39 +
40 + private void loadMap() {
41 + map.put(ONE, 1);
42 + map.put(TWO, 2);
43 + }
44 +
45 + private void fortioCharti() {
46 + chartis.put(ONE, ALPHA);
47 + chartis.put(TWO, BETA);
48 + }
49 +
50 + @Test
51 + public void nullDefaultIsAllowed() {
52 + // but makes this class behave no different than HashMap
53 + map = new DefaultHashMap<>(null);
54 + loadMap();
55 + assertEquals("missing 1", 1, (int) map.get(ONE));
56 + assertEquals("missing 2", 2, (int) map.get(TWO));
57 + assertEquals("three?", null, map.get(THREE));
58 + assertEquals("four?", null, map.get(FOUR));
59 + }
60 +
61 + @Test
62 + public void defaultToFive() {
63 + map = new DefaultHashMap<>(5);
64 + loadMap();
65 + assertEquals("missing 1", 1, (int) map.get(ONE));
66 + assertEquals("missing 2", 2, (int) map.get(TWO));
67 + assertEquals("three?", 5, (int) map.get(THREE));
68 + assertEquals("four?", 5, (int) map.get(FOUR));
69 + }
70 +
71 + @Test
72 + public void defaultToOmega() {
73 + chartis = new DefaultHashMap<>(OMEGA);
74 + fortioCharti();
75 + assertEquals("missing 1", ALPHA, chartis.get(ONE));
76 + assertEquals("missing 2", BETA, chartis.get(TWO));
77 + assertEquals("three?", OMEGA, chartis.get(THREE));
78 + assertEquals("four?", OMEGA, chartis.get(FOUR));
79 + }
80 +
81 +}
...@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode; ...@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
20 import com.fasterxml.jackson.databind.node.ObjectNode; 20 import com.fasterxml.jackson.databind.node.ObjectNode;
21 import org.onlab.osgi.ServiceDirectory; 21 import org.onlab.osgi.ServiceDirectory;
22 import org.onlab.packet.IpAddress; 22 import org.onlab.packet.IpAddress;
23 +import org.onlab.util.DefaultHashMap;
23 import org.onosproject.cluster.ClusterEvent; 24 import org.onosproject.cluster.ClusterEvent;
24 import org.onosproject.cluster.ClusterService; 25 import org.onosproject.cluster.ClusterService;
25 import org.onosproject.cluster.ControllerNode; 26 import org.onosproject.cluster.ControllerNode;
...@@ -80,17 +81,9 @@ import java.util.concurrent.ConcurrentHashMap; ...@@ -80,17 +81,9 @@ import java.util.concurrent.ConcurrentHashMap;
80 81
81 import static com.google.common.base.Preconditions.checkNotNull; 82 import static com.google.common.base.Preconditions.checkNotNull;
82 import static com.google.common.base.Strings.isNullOrEmpty; 83 import static com.google.common.base.Strings.isNullOrEmpty;
83 -import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
84 -import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_REMOVED;
85 import static org.onosproject.cluster.ControllerNode.State.ACTIVE; 84 import static org.onosproject.cluster.ControllerNode.State.ACTIVE;
86 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; 85 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
87 import static org.onosproject.net.PortNumber.portNumber; 86 import static org.onosproject.net.PortNumber.portNumber;
88 -import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
89 -import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED;
90 -import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
91 -import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED;
92 -import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
93 -import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
94 import static org.onosproject.ui.topo.TopoConstants.CoreButtons; 87 import static org.onosproject.ui.topo.TopoConstants.CoreButtons;
95 import static org.onosproject.ui.topo.TopoConstants.Properties; 88 import static org.onosproject.ui.topo.TopoConstants.Properties;
96 import static org.onosproject.ui.topo.TopoUtils.compactLinkString; 89 import static org.onosproject.ui.topo.TopoUtils.compactLinkString;
...@@ -100,6 +93,33 @@ import static org.onosproject.ui.topo.TopoUtils.compactLinkString; ...@@ -100,6 +93,33 @@ import static org.onosproject.ui.topo.TopoUtils.compactLinkString;
100 */ 93 */
101 public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { 94 public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
102 95
96 + // default to an "add" event...
97 + private static final DefaultHashMap<ClusterEvent.Type, String> CLUSTER_EVENT =
98 + new DefaultHashMap<>("addInstance");
99 +
100 + // default to an "update" event...
101 + private static final DefaultHashMap<DeviceEvent.Type, String> DEVICE_EVENT =
102 + new DefaultHashMap<>("updateDevice");
103 + private static final DefaultHashMap<LinkEvent.Type, String> LINK_EVENT =
104 + new DefaultHashMap<>("updateLink");
105 + private static final DefaultHashMap<HostEvent.Type, String> HOST_EVENT =
106 + new DefaultHashMap<>("updateHost");
107 +
108 + // but call out specific events that we care to differentiate...
109 + static {
110 + CLUSTER_EVENT.put(ClusterEvent.Type.INSTANCE_REMOVED, "removeInstance");
111 +
112 + DEVICE_EVENT.put(DeviceEvent.Type.DEVICE_ADDED, "addDevice");
113 + DEVICE_EVENT.put(DeviceEvent.Type.DEVICE_REMOVED, "removeDevice");
114 +
115 + LINK_EVENT.put(LinkEvent.Type.LINK_ADDED, "addLink");
116 + LINK_EVENT.put(LinkEvent.Type.LINK_REMOVED, "removeLink");
117 +
118 + HOST_EVENT.put(HostEvent.Type.HOST_ADDED, "addHost");
119 + HOST_EVENT.put(HostEvent.Type.HOST_REMOVED, "removeHost");
120 + HOST_EVENT.put(HostEvent.Type.HOST_MOVED, "moveHost");
121 + }
122 +
103 protected static final Logger log = 123 protected static final Logger log =
104 LoggerFactory.getLogger(TopologyViewMessageHandlerBase.class); 124 LoggerFactory.getLogger(TopologyViewMessageHandlerBase.class);
105 125
...@@ -204,7 +224,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -204,7 +224,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
204 } 224 }
205 225
206 // Produces a cluster instance message to the client. 226 // Produces a cluster instance message to the client.
207 - protected ObjectNode instanceMessage(ClusterEvent event, String messageType) { 227 + protected ObjectNode instanceMessage(ClusterEvent event, String msgType) {
208 ControllerNode node = event.subject(); 228 ControllerNode node = event.subject();
209 int switchCount = mastershipService.getDevicesOf(node.id()).size(); 229 int switchCount = mastershipService.getDevicesOf(node.id()).size();
210 ObjectNode payload = objectNode() 230 ObjectNode payload = objectNode()
...@@ -222,10 +242,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -222,10 +242,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
222 payload.set("labels", labels); 242 payload.set("labels", labels);
223 addMetaUi(node.id().toString(), payload); 243 addMetaUi(node.id().toString(), payload);
224 244
225 - String type = messageType != null ? messageType : 245 + String type = msgType != null ? msgType : CLUSTER_EVENT.get(event.type());
226 - ((event.type() == INSTANCE_ADDED) ? "addInstance" :
227 - ((event.type() == INSTANCE_REMOVED ? "removeInstance" :
228 - "addInstance")));
229 return JsonUtils.envelope(type, 0, payload); 246 return JsonUtils.envelope(type, 0, payload);
230 } 247 }
231 248
...@@ -251,8 +268,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -251,8 +268,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
251 addGeoLocation(device, payload); 268 addGeoLocation(device, payload);
252 addMetaUi(device.id().toString(), payload); 269 addMetaUi(device.id().toString(), payload);
253 270
254 - String type = (event.type() == DEVICE_ADDED) ? "addDevice" : 271 + String type = DEVICE_EVENT.get(event.type());
255 - ((event.type() == DEVICE_REMOVED) ? "removeDevice" : "updateDevice");
256 return JsonUtils.envelope(type, 0, payload); 272 return JsonUtils.envelope(type, 0, payload);
257 } 273 }
258 274
...@@ -268,8 +284,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -268,8 +284,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
268 .put("srcPort", link.src().port().toString()) 284 .put("srcPort", link.src().port().toString())
269 .put("dst", link.dst().deviceId().toString()) 285 .put("dst", link.dst().deviceId().toString())
270 .put("dstPort", link.dst().port().toString()); 286 .put("dstPort", link.dst().port().toString());
271 - String type = (event.type() == LINK_ADDED) ? "addLink" : 287 + String type = LINK_EVENT.get(event.type());
272 - ((event.type() == LINK_REMOVED) ? "removeLink" : "updateLink");
273 return JsonUtils.envelope(type, 0, payload); 288 return JsonUtils.envelope(type, 0, payload);
274 } 289 }
275 290
...@@ -277,20 +292,24 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { ...@@ -277,20 +292,24 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
277 protected ObjectNode hostMessage(HostEvent event) { 292 protected ObjectNode hostMessage(HostEvent event) {
278 Host host = event.subject(); 293 Host host = event.subject();
279 String hostType = host.annotations().value(AnnotationKeys.TYPE); 294 String hostType = host.annotations().value(AnnotationKeys.TYPE);
295 + HostLocation prevLoc = event.prevLocation();
296 +
280 ObjectNode payload = objectNode() 297 ObjectNode payload = objectNode()
281 .put("id", host.id().toString()) 298 .put("id", host.id().toString())
282 .put("type", isNullOrEmpty(hostType) ? "endstation" : hostType) 299 .put("type", isNullOrEmpty(hostType) ? "endstation" : hostType)
283 .put("ingress", compactLinkString(edgeLink(host, true))) 300 .put("ingress", compactLinkString(edgeLink(host, true)))
284 .put("egress", compactLinkString(edgeLink(host, false))); 301 .put("egress", compactLinkString(edgeLink(host, false)));
285 payload.set("cp", hostConnect(host.location())); 302 payload.set("cp", hostConnect(host.location()));
303 + if (prevLoc != null) {
304 + payload.set("prevCp", hostConnect(event.prevLocation()));
305 + }
286 payload.set("labels", labels(ip(host.ipAddresses()), 306 payload.set("labels", labels(ip(host.ipAddresses()),
287 host.mac().toString())); 307 host.mac().toString()));
288 payload.set("props", props(host.annotations())); 308 payload.set("props", props(host.annotations()));
289 addGeoLocation(host, payload); 309 addGeoLocation(host, payload);
290 addMetaUi(host.id().toString(), payload); 310 addMetaUi(host.id().toString(), payload);
291 311
292 - String type = (event.type() == HOST_ADDED) ? "addHost" : 312 + String type = HOST_EVENT.get(event.type());
293 - ((event.type() == HOST_REMOVED) ? "removeHost" : "updateHost");
294 return JsonUtils.envelope(type, 0, payload); 313 return JsonUtils.envelope(type, 0, payload);
295 } 314 }
296 315
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
55 removeDevice: tfs, 55 removeDevice: tfs,
56 addHost: tfs, 56 addHost: tfs,
57 updateHost: tfs, 57 updateHost: tfs,
58 + moveHost: tfs,
58 removeHost: tfs, 59 removeHost: tfs,
59 addLink: tfs, 60 addLink: tfs,
60 updateLink: tfs, 61 updateLink: tfs,
......
...@@ -187,6 +187,35 @@ ...@@ -187,6 +187,35 @@
187 } 187 }
188 } 188 }
189 189
190 + function moveHost(data) {
191 + var id = data.id,
192 + d = lu[id],
193 + lnk;
194 + if (d) {
195 + // first remove the old host link
196 + removeLinkElement(d.linkData);
197 +
198 + // merge new data
199 + angular.extend(d, data);
200 + if (tms.positionNode(d, true)) {
201 + sendUpdateMeta(d);
202 + }
203 +
204 + // now create a new host link
205 + lnk = tms.createHostLink(data);
206 + if (lnk) {
207 + d.linkData = lnk;
208 + network.links.push(lnk);
209 + lu[d.ingress] = lnk;
210 + lu[d.egress] = lnk;
211 + }
212 +
213 + updateNodes();
214 + updateLinks();
215 + fResume();
216 + }
217 + }
218 +
190 function removeHost(data) { 219 function removeHost(data) {
191 var id = data.id, 220 var id = data.id,
192 d = lu[id]; 221 d = lu[id];
...@@ -1142,6 +1171,7 @@ ...@@ -1142,6 +1171,7 @@
1142 removeDevice: removeDevice, 1171 removeDevice: removeDevice,
1143 addHost: addHost, 1172 addHost: addHost,
1144 updateHost: updateHost, 1173 updateHost: updateHost,
1174 + moveHost: moveHost,
1145 removeHost: removeHost, 1175 removeHost: removeHost,
1146 addLink: addLink, 1176 addLink: addLink,
1147 updateLink: updateLink, 1177 updateLink: updateLink,
......