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
Showing
5 changed files
with
192 additions
and
19 deletions
| 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, | ... | ... |
-
Please register or login to post a comment