Adding GUI server-side code.
Change-Id: Iaa8452a315762f9a57c5bdaec2de4ec60877d928
Showing
1 changed file
with
314 additions
and
97 deletions
| ... | @@ -20,30 +20,40 @@ import com.fasterxml.jackson.databind.ObjectMapper; | ... | @@ -20,30 +20,40 @@ import com.fasterxml.jackson.databind.ObjectMapper; |
| 20 | import com.fasterxml.jackson.databind.node.ArrayNode; | 20 | import com.fasterxml.jackson.databind.node.ArrayNode; |
| 21 | import com.fasterxml.jackson.databind.node.ObjectNode; | 21 | import com.fasterxml.jackson.databind.node.ObjectNode; |
| 22 | import org.eclipse.jetty.websocket.WebSocket; | 22 | import org.eclipse.jetty.websocket.WebSocket; |
| 23 | -import org.onlab.onos.event.Event; | 23 | +import org.onlab.onos.mastership.MastershipEvent; |
| 24 | +import org.onlab.onos.mastership.MastershipListener; | ||
| 25 | +import org.onlab.onos.mastership.MastershipService; | ||
| 24 | import org.onlab.onos.net.Annotations; | 26 | import org.onlab.onos.net.Annotations; |
| 25 | import org.onlab.onos.net.Device; | 27 | import org.onlab.onos.net.Device; |
| 26 | import org.onlab.onos.net.DeviceId; | 28 | import org.onlab.onos.net.DeviceId; |
| 29 | +import org.onlab.onos.net.Host; | ||
| 30 | +import org.onlab.onos.net.HostId; | ||
| 31 | +import org.onlab.onos.net.HostLocation; | ||
| 27 | import org.onlab.onos.net.Link; | 32 | import org.onlab.onos.net.Link; |
| 28 | import org.onlab.onos.net.Path; | 33 | import org.onlab.onos.net.Path; |
| 29 | import org.onlab.onos.net.device.DeviceEvent; | 34 | import org.onlab.onos.net.device.DeviceEvent; |
| 35 | +import org.onlab.onos.net.device.DeviceListener; | ||
| 30 | import org.onlab.onos.net.device.DeviceService; | 36 | import org.onlab.onos.net.device.DeviceService; |
| 37 | +import org.onlab.onos.net.host.HostEvent; | ||
| 38 | +import org.onlab.onos.net.host.HostListener; | ||
| 39 | +import org.onlab.onos.net.host.HostService; | ||
| 40 | +import org.onlab.onos.net.intent.IntentId; | ||
| 31 | import org.onlab.onos.net.link.LinkEvent; | 41 | import org.onlab.onos.net.link.LinkEvent; |
| 32 | -import org.onlab.onos.net.topology.Topology; | 42 | +import org.onlab.onos.net.link.LinkListener; |
| 33 | -import org.onlab.onos.net.topology.TopologyEdge; | 43 | +import org.onlab.onos.net.link.LinkService; |
| 34 | -import org.onlab.onos.net.topology.TopologyEvent; | 44 | +import org.onlab.onos.net.topology.PathService; |
| 35 | -import org.onlab.onos.net.topology.TopologyGraph; | ||
| 36 | -import org.onlab.onos.net.topology.TopologyListener; | ||
| 37 | -import org.onlab.onos.net.topology.TopologyService; | ||
| 38 | -import org.onlab.onos.net.topology.TopologyVertex; | ||
| 39 | import org.onlab.osgi.ServiceDirectory; | 45 | import org.onlab.osgi.ServiceDirectory; |
| 46 | +import org.onlab.packet.IpAddress; | ||
| 40 | 47 | ||
| 41 | import java.io.IOException; | 48 | import java.io.IOException; |
| 42 | import java.util.HashMap; | 49 | import java.util.HashMap; |
| 50 | +import java.util.Iterator; | ||
| 43 | import java.util.Map; | 51 | import java.util.Map; |
| 44 | import java.util.Set; | 52 | import java.util.Set; |
| 45 | 53 | ||
| 54 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 46 | import static org.onlab.onos.net.DeviceId.deviceId; | 55 | import static org.onlab.onos.net.DeviceId.deviceId; |
| 56 | +import static org.onlab.onos.net.HostId.hostId; | ||
| 47 | import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_ADDED; | 57 | import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_ADDED; |
| 48 | import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_REMOVED; | 58 | import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_REMOVED; |
| 49 | import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED; | 59 | import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED; |
| ... | @@ -52,16 +62,24 @@ import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED; | ... | @@ -52,16 +62,24 @@ import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED; |
| 52 | /** | 62 | /** |
| 53 | * Web socket capable of interacting with the GUI topology view. | 63 | * Web socket capable of interacting with the GUI topology view. |
| 54 | */ | 64 | */ |
| 55 | -public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListener { | 65 | +public class TopologyWebSocket implements WebSocket.OnTextMessage { |
| 56 | 66 | ||
| 57 | private final ServiceDirectory directory; | 67 | private final ServiceDirectory directory; |
| 58 | - private final TopologyService topologyService; | ||
| 59 | - private final DeviceService deviceService; | ||
| 60 | 68 | ||
| 61 | private final ObjectMapper mapper = new ObjectMapper(); | 69 | private final ObjectMapper mapper = new ObjectMapper(); |
| 62 | 70 | ||
| 63 | private Connection connection; | 71 | private Connection connection; |
| 64 | 72 | ||
| 73 | + private final DeviceService deviceService; | ||
| 74 | + private final LinkService linkService; | ||
| 75 | + private final HostService hostService; | ||
| 76 | + private final MastershipService mastershipService; | ||
| 77 | + | ||
| 78 | + private final DeviceListener deviceListener = new InternalDeviceListener(); | ||
| 79 | + private final LinkListener linkListener = new InternalLinkListener(); | ||
| 80 | + private final HostListener hostListener = new InternalHostListener(); | ||
| 81 | + private final MastershipListener mastershipListener = new InternalMastershipListener(); | ||
| 82 | + | ||
| 65 | // TODO: extract into an external & durable state; good enough for now and demo | 83 | // TODO: extract into an external & durable state; good enough for now and demo |
| 66 | private static Map<String, ObjectNode> metaUi = new HashMap<>(); | 84 | private static Map<String, ObjectNode> metaUi = new HashMap<>(); |
| 67 | 85 | ||
| ... | @@ -74,81 +92,219 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe | ... | @@ -74,81 +92,219 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe |
| 74 | * @param directory service directory | 92 | * @param directory service directory |
| 75 | */ | 93 | */ |
| 76 | public TopologyWebSocket(ServiceDirectory directory) { | 94 | public TopologyWebSocket(ServiceDirectory directory) { |
| 77 | - this.directory = directory; | 95 | + this.directory = checkNotNull(directory, "Directory cannot be null"); |
| 78 | - topologyService = directory.get(TopologyService.class); | ||
| 79 | deviceService = directory.get(DeviceService.class); | 96 | deviceService = directory.get(DeviceService.class); |
| 97 | + linkService = directory.get(LinkService.class); | ||
| 98 | + hostService = directory.get(HostService.class); | ||
| 99 | + mastershipService = directory.get(MastershipService.class); | ||
| 80 | } | 100 | } |
| 81 | 101 | ||
| 82 | @Override | 102 | @Override |
| 83 | public void onOpen(Connection connection) { | 103 | public void onOpen(Connection connection) { |
| 84 | this.connection = connection; | 104 | this.connection = connection; |
| 105 | + deviceService.addListener(deviceListener); | ||
| 106 | + linkService.addListener(linkListener); | ||
| 107 | + hostService.addListener(hostListener); | ||
| 108 | + mastershipService.addListener(mastershipListener); | ||
| 85 | 109 | ||
| 86 | - // Register for topology events... | 110 | + sendAllDevices(); |
| 87 | - if (topologyService != null && deviceService != null) { | 111 | + sendAllLinks(); |
| 88 | - topologyService.addListener(this); | 112 | + } |
| 89 | - | ||
| 90 | - Topology topology = topologyService.currentTopology(); | ||
| 91 | - TopologyGraph graph = topologyService.getGraph(topology); | ||
| 92 | - for (TopologyVertex vertex : graph.getVertexes()) { | ||
| 93 | - sendMessage(message(new DeviceEvent(DEVICE_ADDED, | ||
| 94 | - deviceService.getDevice(vertex.deviceId())))); | ||
| 95 | - } | ||
| 96 | 113 | ||
| 97 | - for (TopologyEdge edge : graph.getEdges()) { | 114 | + private void sendAllDevices() { |
| 98 | - sendMessage(message(new LinkEvent(LINK_ADDED, edge.link()))); | 115 | + for (Device device : deviceService.getDevices()) { |
| 99 | - } | 116 | + sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device))); |
| 117 | + } | ||
| 118 | + } | ||
| 100 | 119 | ||
| 101 | - } else { | 120 | + private void sendAllLinks() { |
| 102 | - sendMessage(message("error", "No topology service!!!")); | 121 | + for (Link link : linkService.getLinks()) { |
| 122 | + sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link))); | ||
| 103 | } | 123 | } |
| 104 | } | 124 | } |
| 105 | 125 | ||
| 106 | @Override | 126 | @Override |
| 107 | public void onClose(int closeCode, String message) { | 127 | public void onClose(int closeCode, String message) { |
| 108 | - TopologyService topologyService = directory.get(TopologyService.class); | 128 | + deviceService.removeListener(deviceListener); |
| 109 | - if (topologyService != null) { | 129 | + linkService.removeListener(linkListener); |
| 110 | - topologyService.removeListener(this); | 130 | + hostService.removeListener(hostListener); |
| 111 | - } | 131 | + mastershipService.removeListener(mastershipListener); |
| 112 | } | 132 | } |
| 113 | 133 | ||
| 114 | @Override | 134 | @Override |
| 115 | public void onMessage(String data) { | 135 | public void onMessage(String data) { |
| 116 | try { | 136 | try { |
| 117 | ObjectNode event = (ObjectNode) mapper.reader().readTree(data); | 137 | ObjectNode event = (ObjectNode) mapper.reader().readTree(data); |
| 118 | - String type = event.path("event").asText("unknown"); | 138 | + String type = string(event, "event", "unknown"); |
| 119 | - ObjectNode payload = (ObjectNode) event.path("payload"); | 139 | + if (type.equals("showDetails")) { |
| 120 | - | 140 | + showDetails(event); |
| 121 | - switch (type) { | 141 | + } else if (type.equals("updateMeta")) { |
| 122 | - case "updateMeta": | 142 | + updateMetaInformation(event); |
| 123 | - metaUi.put(payload.path("id").asText(), payload); | 143 | + } else if (type.equals("requestPath")) { |
| 124 | - break; | 144 | + sendPath(event); |
| 125 | - case "requestPath": | 145 | + } else if (type.equals("requestTraffic")) { |
| 126 | - findPath(deviceId(payload.path("one").asText()), | 146 | + sendTraffic(event); |
| 127 | - deviceId(payload.path("two").asText())); | 147 | + } else if (type.equals("cancelTraffic")) { |
| 128 | - default: | 148 | + cancelTraffic(event); |
| 129 | - break; | ||
| 130 | } | 149 | } |
| 131 | } catch (IOException e) { | 150 | } catch (IOException e) { |
| 132 | System.out.println("Received: " + data); | 151 | System.out.println("Received: " + data); |
| 133 | } | 152 | } |
| 134 | } | 153 | } |
| 135 | 154 | ||
| 136 | - private void findPath(DeviceId one, DeviceId two) { | 155 | + // Sends the specified data to the client. |
| 137 | - Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(), | 156 | + private void sendMessage(ObjectNode data) { |
| 138 | - one, two); | 157 | + try { |
| 139 | - if (!paths.isEmpty()) { | 158 | + connection.sendMessage(data.toString()); |
| 140 | - ObjectNode payload = mapper.createObjectNode(); | 159 | + } catch (IOException e) { |
| 141 | - ArrayNode links = mapper.createArrayNode(); | 160 | + e.printStackTrace(); |
| 161 | + } | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + // Retrieves the payload from the specified event. | ||
| 165 | + private ObjectNode payload(ObjectNode event) { | ||
| 166 | + return (ObjectNode) event.path("payload"); | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + // Returns the specified node property as a number | ||
| 170 | + private long number(ObjectNode node, String name) { | ||
| 171 | + return node.path(name).asLong(); | ||
| 172 | + } | ||
| 142 | 173 | ||
| 143 | - Path path = paths.iterator().next(); | 174 | + // Returns the specified node property as a string. |
| 144 | - for (Link link : path.links()) { | 175 | + private String string(ObjectNode node, String name) { |
| 145 | - links.add(compactLinkString(link)); | 176 | + return node.path(name).asText(); |
| 146 | - } | 177 | + } |
| 178 | + | ||
| 179 | + // Returns the specified node property as a string. | ||
| 180 | + private String string(ObjectNode node, String name, String defaultValue) { | ||
| 181 | + return node.path(name).asText(defaultValue); | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + // Returns the specified set of IP addresses as a string. | ||
| 185 | + private String ip(Set<IpAddress> ipAddresses) { | ||
| 186 | + Iterator<IpAddress> it = ipAddresses.iterator(); | ||
| 187 | + return it.hasNext() ? it.next().toString() : "unknown"; | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + // Encodes the specified host location into a JSON object. | ||
| 191 | + private ObjectNode location(ObjectMapper mapper, HostLocation location) { | ||
| 192 | + return mapper.createObjectNode() | ||
| 193 | + .put("device", location.deviceId().toString()) | ||
| 194 | + .put("port", location.port().toLong()); | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + // Encodes the specified list of labels a JSON array. | ||
| 198 | + private ArrayNode labels(ObjectMapper mapper, String... labels) { | ||
| 199 | + ArrayNode json = mapper.createArrayNode(); | ||
| 200 | + for (String label : labels) { | ||
| 201 | + json.add(label); | ||
| 202 | + } | ||
| 203 | + return json; | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + // Produces JSON structure from annotations. | ||
| 207 | + private JsonNode props(Annotations annotations) { | ||
| 208 | + ObjectNode props = mapper.createObjectNode(); | ||
| 209 | + for (String key : annotations.keys()) { | ||
| 210 | + props.put(key, annotations.value(key)); | ||
| 211 | + } | ||
| 212 | + return props; | ||
| 213 | + } | ||
| 214 | + | ||
| 215 | + // Produces a log message event bound to the client. | ||
| 216 | + private ObjectNode message(String severity, long id, String message) { | ||
| 217 | + return envelope("message", id, | ||
| 218 | + mapper.createObjectNode() | ||
| 219 | + .put("severity", severity) | ||
| 220 | + .put("message", message)); | ||
| 221 | + } | ||
| 147 | 222 | ||
| 148 | - payload.set("links", links); | 223 | + // Puts the payload into an envelope and returns it. |
| 149 | - sendMessage(envelope("showPath", payload)); | 224 | + private ObjectNode envelope(String type, long sid, ObjectNode payload) { |
| 225 | + ObjectNode event = mapper.createObjectNode(); | ||
| 226 | + event.put("event", type); | ||
| 227 | + if (sid > 0) { | ||
| 228 | + event.put("sid", sid); | ||
| 150 | } | 229 | } |
| 151 | - // TODO: when no path, send a message to the client | 230 | + event.set("payload", payload); |
| 231 | + return event; | ||
| 232 | + } | ||
| 233 | + | ||
| 234 | + // Sends back device or host details. | ||
| 235 | + private void showDetails(ObjectNode event) { | ||
| 236 | + ObjectNode payload = payload(event); | ||
| 237 | + String type = string(payload, "type", "unknown"); | ||
| 238 | + if (type.equals("device")) { | ||
| 239 | + sendMessage(deviceDetails(deviceId(string(payload, "id")), | ||
| 240 | + number(event, "sid"))); | ||
| 241 | + } else if (type.equals("host")) { | ||
| 242 | + sendMessage(hostDetails(hostId(string(payload, "id")), | ||
| 243 | + number(event, "sid"))); | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + // Updates device/host meta information. | ||
| 248 | + private void updateMetaInformation(ObjectNode event) { | ||
| 249 | + ObjectNode payload = payload(event); | ||
| 250 | + metaUi.put(string(payload, "id"), payload); | ||
| 251 | + } | ||
| 252 | + | ||
| 253 | + // Sends path message. | ||
| 254 | + private void sendPath(ObjectNode event) { | ||
| 255 | + ObjectNode payload = payload(event); | ||
| 256 | + long id = number(event, "sid"); | ||
| 257 | + DeviceId one = deviceId(string(payload, "one")); | ||
| 258 | + DeviceId two = deviceId(string(payload, "two")); | ||
| 259 | + | ||
| 260 | + ObjectNode response = findPath(one, two); | ||
| 261 | + if (response != null) { | ||
| 262 | + sendMessage(envelope("showPath", id, response)); | ||
| 263 | + } else { | ||
| 264 | + sendMessage(message("warn", id, "No path found")); | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + // Sends traffic message. | ||
| 269 | + private void sendTraffic(ObjectNode event) { | ||
| 270 | + ObjectNode payload = payload(event); | ||
| 271 | + long id = number(event, "sid"); | ||
| 272 | + IntentId intentId = IntentId.valueOf(payload.path("intentId").asLong()); | ||
| 273 | + | ||
| 274 | + if (payload != null) { | ||
| 275 | + payload.put("traffic", true); | ||
| 276 | + sendMessage(envelope("showPath", id, payload)); | ||
| 277 | + } else { | ||
| 278 | + sendMessage(message("warn", id, "No path found")); | ||
| 279 | + } | ||
| 280 | + } | ||
| 281 | + | ||
| 282 | + // Cancels sending traffic messages. | ||
| 283 | + private void cancelTraffic(ObjectNode event) { | ||
| 284 | + // TODO: implement this | ||
| 285 | + } | ||
| 286 | + | ||
| 287 | + // Finds the path between the specified devices. | ||
| 288 | + private ObjectNode findPath(DeviceId one, DeviceId two) { | ||
| 289 | + PathService pathService = directory.get(PathService.class); | ||
| 290 | + Set<Path> paths = pathService.getPaths(one, two); | ||
| 291 | + if (paths.isEmpty()) { | ||
| 292 | + return null; | ||
| 293 | + } else { | ||
| 294 | + return pathMessage(paths.iterator().next()); | ||
| 295 | + } | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + // Produces a path message to the client. | ||
| 299 | + private ObjectNode pathMessage(Path path) { | ||
| 300 | + ObjectNode payload = mapper.createObjectNode(); | ||
| 301 | + ArrayNode links = mapper.createArrayNode(); | ||
| 302 | + for (Link link : path.links()) { | ||
| 303 | + links.add(compactLinkString(link)); | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + payload.set("links", links); | ||
| 307 | + return payload; | ||
| 152 | } | 308 | } |
| 153 | 309 | ||
| 154 | /** | 310 | /** |
| ... | @@ -163,16 +319,8 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe | ... | @@ -163,16 +319,8 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe |
| 163 | } | 319 | } |
| 164 | 320 | ||
| 165 | 321 | ||
| 166 | - private void sendMessage(String data) { | ||
| 167 | - try { | ||
| 168 | - connection.sendMessage(data); | ||
| 169 | - } catch (IOException e) { | ||
| 170 | - e.printStackTrace(); | ||
| 171 | - } | ||
| 172 | - } | ||
| 173 | - | ||
| 174 | // Produces a link event message to the client. | 322 | // Produces a link event message to the client. |
| 175 | - private String message(DeviceEvent event) { | 323 | + private ObjectNode deviceMessage(DeviceEvent event) { |
| 176 | Device device = event.subject(); | 324 | Device device = event.subject(); |
| 177 | ObjectNode payload = mapper.createObjectNode() | 325 | ObjectNode payload = mapper.createObjectNode() |
| 178 | .put("id", device.id().toString()) | 326 | .put("id", device.id().toString()) |
| ... | @@ -183,7 +331,7 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe | ... | @@ -183,7 +331,7 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe |
| 183 | ArrayNode labels = mapper.createArrayNode(); | 331 | ArrayNode labels = mapper.createArrayNode(); |
| 184 | labels.add(device.id().toString()); | 332 | labels.add(device.id().toString()); |
| 185 | labels.add(device.chassisId().toString()); | 333 | labels.add(device.chassisId().toString()); |
| 186 | - labels.add(" "); // compact no-label view | 334 | + labels.add(""); // compact no-label view |
| 187 | labels.add(device.annotations().value("name")); | 335 | labels.add(device.annotations().value("name")); |
| 188 | 336 | ||
| 189 | // Add labels, props and stuff the payload into envelope. | 337 | // Add labels, props and stuff the payload into envelope. |
| ... | @@ -197,11 +345,11 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe | ... | @@ -197,11 +345,11 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe |
| 197 | 345 | ||
| 198 | String type = (event.type() == DEVICE_ADDED) ? "addDevice" : | 346 | String type = (event.type() == DEVICE_ADDED) ? "addDevice" : |
| 199 | ((event.type() == DEVICE_REMOVED) ? "removeDevice" : "updateDevice"); | 347 | ((event.type() == DEVICE_REMOVED) ? "removeDevice" : "updateDevice"); |
| 200 | - return envelope(type, payload); | 348 | + return envelope(type, 0, payload); |
| 201 | } | 349 | } |
| 202 | 350 | ||
| 203 | // Produces a link event message to the client. | 351 | // Produces a link event message to the client. |
| 204 | - private String message(LinkEvent event) { | 352 | + private ObjectNode linkMessage(LinkEvent event) { |
| 205 | Link link = event.subject(); | 353 | Link link = event.subject(); |
| 206 | ObjectNode payload = mapper.createObjectNode() | 354 | ObjectNode payload = mapper.createObjectNode() |
| 207 | .put("type", link.type().toString().toLowerCase()) | 355 | .put("type", link.type().toString().toLowerCase()) |
| ... | @@ -211,43 +359,112 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe | ... | @@ -211,43 +359,112 @@ public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListe |
| 211 | .put("dst", link.dst().deviceId().toString()) | 359 | .put("dst", link.dst().deviceId().toString()) |
| 212 | .put("dstPort", link.dst().port().toString()); | 360 | .put("dstPort", link.dst().port().toString()); |
| 213 | String type = (event.type() == LINK_ADDED) ? "addLink" : | 361 | String type = (event.type() == LINK_ADDED) ? "addLink" : |
| 214 | - ((event.type() == LINK_REMOVED) ? "removeLink" : "removeLink"); | 362 | + ((event.type() == LINK_REMOVED) ? "removeLink" : "updateLink"); |
| 215 | - return envelope(type, payload); | 363 | + return envelope(type, 0, payload); |
| 216 | } | 364 | } |
| 217 | 365 | ||
| 218 | - // Produces JSON structure from annotations. | 366 | + // Produces a host event message to the client. |
| 219 | - private JsonNode props(Annotations annotations) { | 367 | + private ObjectNode hostMessage(HostEvent event) { |
| 220 | - ObjectNode props = mapper.createObjectNode(); | 368 | + Host host = event.subject(); |
| 221 | - for (String key : annotations.keys()) { | 369 | + ObjectNode payload = mapper.createObjectNode() |
| 222 | - props.put(key, annotations.value(key)); | 370 | + .put("id", host.id().toString()); |
| 371 | + payload.set("cp", location(mapper, host.location())); | ||
| 372 | + payload.set("labels", labels(mapper, ip(host.ipAddresses()), | ||
| 373 | + host.mac().toString())); | ||
| 374 | + return payload; | ||
| 375 | + } | ||
| 376 | + | ||
| 377 | + | ||
| 378 | + // Returns device details response. | ||
| 379 | + private ObjectNode deviceDetails(DeviceId deviceId, long sid) { | ||
| 380 | + Device device = deviceService.getDevice(deviceId); | ||
| 381 | + Annotations annot = device.annotations(); | ||
| 382 | + int portCount = deviceService.getPorts(deviceId).size(); | ||
| 383 | + return envelope("showDetails", sid, | ||
| 384 | + json(deviceId.toString(), | ||
| 385 | + device.type().toString().toLowerCase(), | ||
| 386 | + new Prop("Name", annot.value("name")), | ||
| 387 | + new Prop("Vendor", device.manufacturer()), | ||
| 388 | + new Prop("H/W Version", device.hwVersion()), | ||
| 389 | + new Prop("S/W Version", device.swVersion()), | ||
| 390 | + new Prop("Serial Number", device.serialNumber()), | ||
| 391 | + new Separator(), | ||
| 392 | + new Prop("Latitude", annot.value("latitude")), | ||
| 393 | + new Prop("Longitude", annot.value("longitude")), | ||
| 394 | + new Prop("Ports", Integer.toString(portCount)))); | ||
| 395 | + } | ||
| 396 | + | ||
| 397 | + // Returns host details response. | ||
| 398 | + private ObjectNode hostDetails(HostId hostId, long sid) { | ||
| 399 | + Host host = hostService.getHost(hostId); | ||
| 400 | + Annotations annot = host.annotations(); | ||
| 401 | + return envelope("showDetails", sid, | ||
| 402 | + json(hostId.toString(), "host", | ||
| 403 | + new Prop("MAC", host.mac().toString()), | ||
| 404 | + new Prop("IP", host.ipAddresses().toString()), | ||
| 405 | + new Separator(), | ||
| 406 | + new Prop("Latitude", annot.value("latitude")), | ||
| 407 | + new Prop("Longitude", annot.value("longitude")))); | ||
| 408 | + } | ||
| 409 | + | ||
| 410 | + // Produces JSON property details. | ||
| 411 | + private ObjectNode json(String id, String type, Prop... props) { | ||
| 412 | + ObjectMapper mapper = new ObjectMapper(); | ||
| 413 | + ObjectNode result = mapper.createObjectNode() | ||
| 414 | + .put("id", id).put("type", type); | ||
| 415 | + ObjectNode pnode = mapper.createObjectNode(); | ||
| 416 | + ArrayNode porder = mapper.createArrayNode(); | ||
| 417 | + for (Prop p : props) { | ||
| 418 | + porder.add(p.key); | ||
| 419 | + pnode.put(p.key, p.value); | ||
| 223 | } | 420 | } |
| 224 | - return props; | 421 | + result.set("propOrder", porder); |
| 422 | + result.set("props", pnode); | ||
| 423 | + return result; | ||
| 225 | } | 424 | } |
| 226 | 425 | ||
| 227 | - // Produces a log message event bound to the client. | 426 | + // Auxiliary key/value carrier. |
| 228 | - private String message(String severity, String message) { | 427 | + private class Prop { |
| 229 | - return envelope("message", | 428 | + private final String key; |
| 230 | - mapper.createObjectNode() | 429 | + private final String value; |
| 231 | - .put("severity", severity) | 430 | + |
| 232 | - .put("message", message)); | 431 | + protected Prop(String key, String value) { |
| 432 | + this.key = key; | ||
| 433 | + this.value = value; | ||
| 434 | + } | ||
| 233 | } | 435 | } |
| 234 | 436 | ||
| 235 | - // Puts the payload into an envelope and returns it. | 437 | + private class Separator extends Prop { |
| 236 | - private String envelope(String type, ObjectNode payload) { | 438 | + protected Separator() { |
| 237 | - ObjectNode event = mapper.createObjectNode(); | 439 | + super("-", ""); |
| 238 | - event.put("event", type); | 440 | + } |
| 239 | - event.set("payload", payload); | ||
| 240 | - return event.toString(); | ||
| 241 | } | 441 | } |
| 242 | 442 | ||
| 243 | - @Override | 443 | + private class InternalDeviceListener implements DeviceListener { |
| 244 | - public void event(TopologyEvent event) { | 444 | + @Override |
| 245 | - for (Event reason : event.reasons()) { | 445 | + public void event(DeviceEvent event) { |
| 246 | - if (reason instanceof DeviceEvent) { | 446 | + sendMessage(deviceMessage(event)); |
| 247 | - sendMessage(message((DeviceEvent) reason)); | 447 | + } |
| 248 | - } else if (reason instanceof LinkEvent) { | 448 | + } |
| 249 | - sendMessage(message((LinkEvent) reason)); | 449 | + |
| 250 | - } | 450 | + private class InternalLinkListener implements LinkListener { |
| 451 | + @Override | ||
| 452 | + public void event(LinkEvent event) { | ||
| 453 | + sendMessage(linkMessage(event)); | ||
| 454 | + } | ||
| 455 | + } | ||
| 456 | + | ||
| 457 | + private class InternalHostListener implements HostListener { | ||
| 458 | + @Override | ||
| 459 | + public void event(HostEvent event) { | ||
| 460 | + sendMessage(hostMessage(event)); | ||
| 461 | + } | ||
| 462 | + } | ||
| 463 | + | ||
| 464 | + private class InternalMastershipListener implements MastershipListener { | ||
| 465 | + @Override | ||
| 466 | + public void event(MastershipEvent event) { | ||
| 467 | + | ||
| 251 | } | 468 | } |
| 252 | } | 469 | } |
| 253 | } | 470 | } | ... | ... |
-
Please register or login to post a comment