blob: e82303b73b421ea84c4e273a0d663fdab1282ae8 [file] [log] [blame]
Thomas Vachuska7d638d32014-11-07 10:24:43 -08001/*
2 * Copyright 2014 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 */
16package org.onlab.onos.gui;
17
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ArrayNode;
21import com.fasterxml.jackson.databind.node.ObjectNode;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080022import org.eclipse.jetty.websocket.WebSocket;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080023import org.onlab.onos.event.Event;
24import org.onlab.onos.net.Annotations;
25import org.onlab.onos.net.Device;
26import org.onlab.onos.net.Link;
27import org.onlab.onos.net.device.DeviceEvent;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080028import org.onlab.onos.net.device.DeviceService;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080029import org.onlab.onos.net.link.LinkEvent;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080030import org.onlab.onos.net.topology.Topology;
31import org.onlab.onos.net.topology.TopologyEdge;
32import org.onlab.onos.net.topology.TopologyEvent;
33import org.onlab.onos.net.topology.TopologyGraph;
34import org.onlab.onos.net.topology.TopologyListener;
35import org.onlab.onos.net.topology.TopologyService;
36import org.onlab.onos.net.topology.TopologyVertex;
37import org.onlab.osgi.ServiceDirectory;
38
39import java.io.IOException;
40
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080041import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_ADDED;
42import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_REMOVED;
43import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED;
44import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
45
Thomas Vachuska7d638d32014-11-07 10:24:43 -080046/**
47 * Web socket capable of interacting with the GUI topology view.
48 */
49public class TopologyWebSocket implements WebSocket.OnTextMessage, TopologyListener {
50
51 private final ServiceDirectory directory;
52 private final TopologyService topologyService;
53 private final DeviceService deviceService;
54
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080055 private final ObjectMapper mapper = new ObjectMapper();
56
Thomas Vachuska7d638d32014-11-07 10:24:43 -080057 private Connection connection;
58
59 /**
60 * Creates a new web-socket for serving data to GUI topology view.
61 *
62 * @param directory service directory
63 */
64 public TopologyWebSocket(ServiceDirectory directory) {
65 this.directory = directory;
66 topologyService = directory.get(TopologyService.class);
67 deviceService = directory.get(DeviceService.class);
68 }
69
70 @Override
71 public void onOpen(Connection connection) {
72 this.connection = connection;
73
74 // Register for topology events...
75 if (topologyService != null && deviceService != null) {
76 topologyService.addListener(this);
77
Thomas Vachuska7d638d32014-11-07 10:24:43 -080078 Topology topology = topologyService.currentTopology();
79 TopologyGraph graph = topologyService.getGraph(topology);
80 for (TopologyVertex vertex : graph.getVertexes()) {
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080081 sendMessage(message(new DeviceEvent(DEVICE_ADDED,
82 deviceService.getDevice(vertex.deviceId()))));
Thomas Vachuska7d638d32014-11-07 10:24:43 -080083 }
84
85 for (TopologyEdge edge : graph.getEdges()) {
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080086 sendMessage(message(new LinkEvent(LINK_ADDED, edge.link())));
Thomas Vachuska7d638d32014-11-07 10:24:43 -080087 }
88
Thomas Vachuska7d638d32014-11-07 10:24:43 -080089 } else {
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080090 sendMessage(message("error", "No topology service!!!"));
Thomas Vachuska7d638d32014-11-07 10:24:43 -080091 }
92 }
93
94 @Override
95 public void onClose(int closeCode, String message) {
96 TopologyService topologyService = directory.get(TopologyService.class);
97 if (topologyService != null) {
98 topologyService.removeListener(this);
99 }
100 }
101
102 @Override
103 public void onMessage(String data) {
104 System.out.println("Received: " + data);
105 }
106
Thomas Vachuskad472c6e2014-11-07 19:11:05 -0800107 private void sendMessage(String data) {
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800108 try {
109 connection.sendMessage(data);
110 } catch (IOException e) {
111 e.printStackTrace();
112 }
113 }
114
Thomas Vachuskad472c6e2014-11-07 19:11:05 -0800115 // Produces a link event message to the client.
116 private String message(DeviceEvent event) {
117 Device device = event.subject();
118 ObjectNode payload = mapper.createObjectNode()
119 .put("id", device.id().toString())
120 .put("type", device.type().toString().toLowerCase())
121 .put("online", deviceService.isAvailable(device.id()));
122
123 // Generate labels: id, chassis id, no-label, optional-name
124 ArrayNode labels = mapper.createArrayNode();
125 labels.add(device.id().toString());
126 labels.add(device.chassisId().toString());
127 labels.add(" "); // compact no-label view
128 labels.add(device.annotations().value("name"));
129
130 // Add labels, props and stuff the payload into envelope.
131 payload.set("labels", labels);
132 payload.set("props", props(device.annotations()));
133 payload.set("metaUi", mapper.createObjectNode());
134
135 String type = (event.type() == DEVICE_ADDED) ? "addDevice" :
136 ((event.type() == DEVICE_REMOVED) ? "removeDevice" : "updateDevice");
137 return envelope(type, payload);
138 }
139
140 // Produces a link event message to the client.
141 private String message(LinkEvent event) {
142 Link link = event.subject();
143 ObjectNode payload = mapper.createObjectNode()
144 .put("type", link.type().toString().toLowerCase())
145 .put("linkWidth", 2)
146 .put("src", link.src().deviceId().toString())
147 .put("srcPort", link.src().port().toString())
148 .put("dst", link.dst().deviceId().toString())
149 .put("dstPort", link.dst().port().toString());
150 String type = (event.type() == LINK_ADDED) ? "addLink" :
151 ((event.type() == LINK_REMOVED) ? "removeLink" : "removeLink");
152 return envelope(type, payload);
153 }
154
155 // Produces JSON structure from annotations.
156 private JsonNode props(Annotations annotations) {
157 ObjectNode props = mapper.createObjectNode();
158 for (String key : annotations.keys()) {
159 props.put(key, annotations.value(key));
160 }
161 return props;
162 }
163
164 // Produces a log message event bound to the client.
165 private String message(String severity, String message) {
166 return envelope("message",
167 mapper.createObjectNode()
168 .put("severity", severity)
169 .put("message", message));
170 }
171
172 // Puts the payload into an envelope and returns it.
173 private String envelope(String type, ObjectNode payload) {
174 ObjectNode event = mapper.createObjectNode();
175 event.put("event", type);
176 event.set("payload", payload);
177 return event.toString();
178 }
179
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800180 @Override
181 public void event(TopologyEvent event) {
Thomas Vachuskad472c6e2014-11-07 19:11:05 -0800182 for (Event reason : event.reasons()) {
183 if (reason instanceof DeviceEvent) {
184 sendMessage(message((DeviceEvent) reason));
185 } else if (reason instanceof LinkEvent) {
186 sendMessage(message((LinkEvent) reason));
187 }
188 }
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800189 }
190}
191