Adding GUI server-side code.
Change-Id: Iaa8452a315762f9a57c5bdaec2de4ec60877d928
Showing
1 changed file
with
306 additions
and
89 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); | ||
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 | } | 112 | } |
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()) { |
116 | + sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device))); | ||
117 | + } | ||
99 | } | 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()); |
159 | + } catch (IOException e) { | ||
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 | + } | ||
173 | + | ||
174 | + // Returns the specified node property as a string. | ||
175 | + private String string(ObjectNode node, String name) { | ||
176 | + return node.path(name).asText(); | ||
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 | + } | ||
222 | + | ||
223 | + // Puts the payload into an envelope and returns it. | ||
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); | ||
229 | + } | ||
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) { | ||
140 | ObjectNode payload = mapper.createObjectNode(); | 300 | ObjectNode payload = mapper.createObjectNode(); |
141 | ArrayNode links = mapper.createArrayNode(); | 301 | ArrayNode links = mapper.createArrayNode(); |
142 | - | ||
143 | - Path path = paths.iterator().next(); | ||
144 | for (Link link : path.links()) { | 302 | for (Link link : path.links()) { |
145 | links.add(compactLinkString(link)); | 303 | links.add(compactLinkString(link)); |
146 | } | 304 | } |
147 | 305 | ||
148 | payload.set("links", links); | 306 | payload.set("links", links); |
149 | - sendMessage(envelope("showPath", payload)); | 307 | + return payload; |
150 | - } | ||
151 | - // TODO: when no path, send a message to the client | ||
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; | ||
223 | } | 375 | } |
224 | - return props; | 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)))); | ||
225 | } | 395 | } |
226 | 396 | ||
227 | - // Produces a log message event bound to the client. | 397 | + // Returns host details response. |
228 | - private String message(String severity, String message) { | 398 | + private ObjectNode hostDetails(HostId hostId, long sid) { |
229 | - return envelope("message", | 399 | + Host host = hostService.getHost(hostId); |
230 | - mapper.createObjectNode() | 400 | + Annotations annot = host.annotations(); |
231 | - .put("severity", severity) | 401 | + return envelope("showDetails", sid, |
232 | - .put("message", message)); | 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")))); | ||
233 | } | 408 | } |
234 | 409 | ||
235 | - // Puts the payload into an envelope and returns it. | 410 | + // Produces JSON property details. |
236 | - private String envelope(String type, ObjectNode payload) { | 411 | + private ObjectNode json(String id, String type, Prop... props) { |
237 | - ObjectNode event = mapper.createObjectNode(); | 412 | + ObjectMapper mapper = new ObjectMapper(); |
238 | - event.put("event", type); | 413 | + ObjectNode result = mapper.createObjectNode() |
239 | - event.set("payload", payload); | 414 | + .put("id", id).put("type", type); |
240 | - return event.toString(); | 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); | ||
420 | + } | ||
421 | + result.set("propOrder", porder); | ||
422 | + result.set("props", pnode); | ||
423 | + return result; | ||
241 | } | 424 | } |
242 | 425 | ||
426 | + // Auxiliary key/value carrier. | ||
427 | + private class Prop { | ||
428 | + private final String key; | ||
429 | + private final String value; | ||
430 | + | ||
431 | + protected Prop(String key, String value) { | ||
432 | + this.key = key; | ||
433 | + this.value = value; | ||
434 | + } | ||
435 | + } | ||
436 | + | ||
437 | + private class Separator extends Prop { | ||
438 | + protected Separator() { | ||
439 | + super("-", ""); | ||
440 | + } | ||
441 | + } | ||
442 | + | ||
443 | + private class InternalDeviceListener implements DeviceListener { | ||
444 | + @Override | ||
445 | + public void event(DeviceEvent event) { | ||
446 | + sendMessage(deviceMessage(event)); | ||
447 | + } | ||
448 | + } | ||
449 | + | ||
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 { | ||
243 | @Override | 458 | @Override |
244 | - public void event(TopologyEvent event) { | 459 | + public void event(HostEvent event) { |
245 | - for (Event reason : event.reasons()) { | 460 | + sendMessage(hostMessage(event)); |
246 | - if (reason instanceof DeviceEvent) { | 461 | + } |
247 | - sendMessage(message((DeviceEvent) reason)); | ||
248 | - } else if (reason instanceof LinkEvent) { | ||
249 | - sendMessage(message((LinkEvent) reason)); | ||
250 | } | 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