Thomas Vachuska

ONOS-314 Added ability to export JSON via GUI rest.

Change-Id: I8cc6011f54ce6a3fb50916a74cabb7234b04ef39
1 -/*
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 - */
16 -package org.onlab.onos.gui;
17 -
18 -import org.onlab.rest.BaseResource;
19 -
20 -import javax.ws.rs.DefaultValue;
21 -import javax.ws.rs.GET;
22 -import javax.ws.rs.Path;
23 -import javax.ws.rs.QueryParam;
24 -import javax.ws.rs.core.Response;
25 -
26 -/**
27 - * Simple example of a GUI JAX-RS resource.
28 - */
29 -@Path("greet")
30 -public class GreetResource extends BaseResource {
31 -
32 - @GET
33 - public Response yo(@QueryParam("name") @DefaultValue("dude") String name) {
34 - return Response.ok("Yo!!!").build();
35 - }
36 -
37 -}
...@@ -18,284 +18,53 @@ package org.onlab.onos.gui; ...@@ -18,284 +18,53 @@ package org.onlab.onos.gui;
18 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 import com.fasterxml.jackson.databind.node.ArrayNode; 19 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.onos.net.Annotations;
22 -import org.onlab.onos.net.ConnectPoint;
23 -import org.onlab.onos.net.Device;
24 -import org.onlab.onos.net.DeviceId;
25 -import org.onlab.onos.net.Host;
26 -import org.onlab.onos.net.HostId;
27 -import org.onlab.onos.net.HostLocation;
28 -import org.onlab.onos.net.Link;
29 -import org.onlab.onos.net.device.DeviceService;
30 -import org.onlab.onos.net.host.HostService;
31 -import org.onlab.onos.net.link.LinkService;
32 -import org.onlab.onos.net.topology.Topology;
33 -import org.onlab.onos.net.topology.TopologyGraph;
34 -import org.onlab.onos.net.topology.TopologyService;
35 -import org.onlab.onos.net.topology.TopologyVertex;
36 -import org.onlab.packet.IpAddress;
37 -import org.onlab.packet.MacAddress;
38 import org.onlab.rest.BaseResource; 21 import org.onlab.rest.BaseResource;
39 22
40 import javax.ws.rs.GET; 23 import javax.ws.rs.GET;
41 -import javax.ws.rs.PathParam; 24 +import javax.ws.rs.Path;
42 import javax.ws.rs.Produces; 25 import javax.ws.rs.Produces;
43 import javax.ws.rs.core.Response; 26 import javax.ws.rs.core.Response;
44 -import java.util.HashMap;
45 -import java.util.HashSet;
46 -import java.util.Iterator;
47 import java.util.Map; 27 import java.util.Map;
48 -import java.util.Set;
49 -
50 -import static org.onlab.onos.net.DeviceId.deviceId;
51 -import static org.onlab.onos.net.HostId.hostId;
52 28
53 /** 29 /**
54 * Topology viewer resource. 30 * Topology viewer resource.
55 */ 31 */
56 -@javax.ws.rs.Path("topology") 32 +@Path("topology")
57 public class TopologyResource extends BaseResource { 33 public class TopologyResource extends BaseResource {
58 34
59 - private static final String HOST_SEP = "/"; 35 + private final ObjectMapper mapper = new ObjectMapper();
60 36
61 - @javax.ws.rs.Path("/graph") 37 + @Path("/geoloc")
62 @GET 38 @GET
63 @Produces("application/json") 39 @Produces("application/json")
64 - public Response graph() { 40 + public Response getGeoLocations() {
65 - // Fetch the services we'll be using.
66 - DeviceService deviceService = get(DeviceService.class);
67 - HostService hostService = get(HostService.class);
68 - TopologyService topologyService = get(TopologyService.class);
69 -
70 - // Fetch the current topology and its graph that we'll use to render.
71 - Topology topo = topologyService.currentTopology();
72 - TopologyGraph graph = topologyService.getGraph(topo);
73 -
74 - ObjectMapper mapper = new ObjectMapper();
75 ObjectNode rootNode = mapper.createObjectNode(); 41 ObjectNode rootNode = mapper.createObjectNode();
76 - rootNode.set("devices", getDevices(mapper, deviceService, graph));
77 - rootNode.set("links", getLinks(mapper, topo, graph));
78 - rootNode.set("hosts", getHosts(mapper, hostService));
79 - return Response.ok(rootNode.toString()).build();
80 - }
81 -
82 - @javax.ws.rs.Path("/graph/{id}")
83 - @GET
84 - @Produces("application/json")
85 - public Response details(@PathParam("id") String id) {
86 - if (id.contains(HOST_SEP)) {
87 - return hostDetails(hostId(id));
88 - }
89 - return deviceDetails(deviceId(id));
90 - }
91 -
92 - // Returns device details response.
93 - private Response deviceDetails(DeviceId deviceId) {
94 - DeviceService deviceService = get(DeviceService.class);
95 - Device device = deviceService.getDevice(deviceId);
96 - Annotations annot = device.annotations();
97 - int portCount = deviceService.getPorts(deviceId).size();
98 - ObjectNode r = json(deviceId.toString(),
99 - device.type().toString().toLowerCase(),
100 - new Prop("Name", annot.value("name")),
101 - new Prop("Vendor", device.manufacturer()),
102 - new Prop("H/W Version", device.hwVersion()),
103 - new Prop("S/W Version", device.swVersion()),
104 - new Prop("Serial Number", device.serialNumber()),
105 - new Separator(),
106 - new Prop("Latitude", annot.value("latitude")),
107 - new Prop("Longitude", annot.value("longitude")),
108 - new Prop("Ports", Integer.toString(portCount)));
109 - return Response.ok(r.toString()).build();
110 - }
111 -
112 - // Returns host details response.
113 - private Response hostDetails(HostId hostId) {
114 - HostService hostService = get(HostService.class);
115 - Host host = hostService.getHost(hostId);
116 - Annotations annot = host.annotations();
117 - ObjectNode r = json(hostId.toString(), "host",
118 - new Prop("MAC", host.mac().toString()),
119 - new Prop("IP", host.ipAddresses().toString()),
120 - new Separator(),
121 - new Prop("Latitude", annot.value("latitude")),
122 - new Prop("Longitude", annot.value("longitude")));
123 - return Response.ok(r.toString()).build();
124 - }
125 -
126 - // Produces JSON property details.
127 - private ObjectNode json(String id, String type, Prop... props) {
128 - ObjectMapper mapper = new ObjectMapper();
129 - ObjectNode result = mapper.createObjectNode()
130 - .put("id", id).put("type", type);
131 - ObjectNode pnode = mapper.createObjectNode();
132 - ArrayNode porder = mapper.createArrayNode();
133 - for (Prop p : props) {
134 - porder.add(p.key);
135 - pnode.put(p.key, p.value);
136 - }
137 - result.set("propOrder", porder);
138 - result.set("props", pnode);
139 - return result;
140 - }
141 -
142 - // Encodes all infrastructure devices.
143 - private ArrayNode getDevices(ObjectMapper mapper, DeviceService deviceService,
144 - TopologyGraph graph) {
145 ArrayNode devices = mapper.createArrayNode(); 42 ArrayNode devices = mapper.createArrayNode();
146 - for (TopologyVertex vertex : graph.getVertexes()) {
147 - devices.add(json(mapper, deviceService.getDevice(vertex.deviceId()),
148 - deviceService.isAvailable(vertex.deviceId())));
149 - }
150 - return devices;
151 - }
152 -
153 - // Encodes all infrastructure links.
154 - private ArrayNode getLinks(ObjectMapper mapper, Topology topo, TopologyGraph graph) {
155 - // Now scan all links and count number of them between the same devices
156 - // using a normalized link key.
157 - Map<String, AggLink> linkRecords = aggregateLinks();
158 -
159 - // Now build all interior edges using the aggregated links.
160 - ArrayNode links = mapper.createArrayNode();
161 - for (AggLink lr : linkRecords.values()) {
162 - links.add(json(mapper, lr));
163 - }
164 - return links;
165 - }
166 -
167 - // Encodes all end-station hosts.
168 - private ArrayNode getHosts(ObjectMapper mapper, HostService hostService) {
169 ArrayNode hosts = mapper.createArrayNode(); 43 ArrayNode hosts = mapper.createArrayNode();
170 - for (Host host : hostService.getHosts()) {
171 - Set<IpAddress> ipAddresses = host.ipAddresses();
172 - IpAddress ipAddress = ipAddresses.isEmpty() ? null : ipAddresses.iterator().next();
173 - String label = ipAddress != null ? ipAddress.toString() : host.mac().toString();
174 - hosts.add(json(mapper, host));
175 - }
176 - return hosts;
177 - }
178 -
179 - // Scan all links and counts number of them between the same devices
180 - // using a normalized link key.
181 - private Map<String, AggLink> aggregateLinks() {
182 - Map<String, AggLink> aggLinks = new HashMap<>();
183 - LinkService linkService = get(LinkService.class);
184 - for (Link link : linkService.getLinks()) {
185 - String key = key(link);
186 - AggLink lr = aggLinks.get(key);
187 - if (lr == null) {
188 - lr = new AggLink(key);
189 - aggLinks.put(key, lr);
190 - }
191 - lr.addLink(link);
192 - }
193 - return aggLinks;
194 - }
195 -
196 - // Produces JSON for a device.
197 - private ObjectNode json(ObjectMapper mapper, Device device, boolean isOnline) {
198 - ObjectNode node = mapper.createObjectNode()
199 - .put("id", device.id().toString())
200 - .put("type", device.type().toString().toLowerCase())
201 - .put("online", isOnline);
202 - node.set("labels", labels(mapper,
203 - device.id().uri().getSchemeSpecificPart(),
204 - MacAddress.valueOf(device.chassisId().value()).toString(),
205 - device.serialNumber()));
206 - return node;
207 - }
208 -
209 - // Produces JSON for a link.
210 - private ObjectNode json(ObjectMapper mapper, AggLink aggLink) {
211 - Link link = aggLink.link;
212 - ConnectPoint src = link.src();
213 - ConnectPoint dst = link.dst();
214 - return mapper.createObjectNode()
215 - .put("src", src.deviceId().toString())
216 - .put("srcPort", src.port().toString())
217 - .put("dst", dst.deviceId().toString())
218 - .put("dstPort", dst.port().toString())
219 - .put("type", link.type().toString().toLowerCase())
220 - .put("linkWidth", aggLink.links.size());
221 - }
222 -
223 - // Produces JSON for a device.
224 - private ObjectNode json(ObjectMapper mapper, Host host) {
225 - ObjectNode json = mapper.createObjectNode()
226 - .put("id", host.id().toString());
227 - json.set("cp", location(mapper, host.location()));
228 - json.set("labels", labels(mapper, ip(host.ipAddresses()),
229 - host.mac().toString()));
230 - return json;
231 - }
232 -
233 - private String ip(Set<IpAddress> ipAddresses) {
234 - Iterator<IpAddress> it = ipAddresses.iterator();
235 - return it.hasNext() ? it.next().toString() : "unknown";
236 - }
237 -
238 - private ObjectNode location(ObjectMapper mapper, HostLocation location) {
239 - return mapper.createObjectNode()
240 - .put("device", location.deviceId().toString())
241 - .put("port", location.port().toLong());
242 - }
243 -
244 - private ArrayNode labels(ObjectMapper mapper, String... labels) {
245 - ArrayNode json = mapper.createArrayNode();
246 - for (String label : labels) {
247 - json.add(label);
248 - }
249 - return json;
250 - }
251 -
252 - // Aggregate link of all links between the same devices regardless of
253 - // their direction.
254 - private class AggLink {
255 - Link link; // representative links
256 -
257 - final String key;
258 - final Set<Link> links = new HashSet<>();
259 44
260 - AggLink(String key) { 45 + Map<String, ObjectNode> metaUi = TopologyViewMessages.getMetaUi();
261 - this.key = key; 46 + for (String id : metaUi.keySet()) {
262 - } 47 + ObjectNode memento = metaUi.get(id);
263 - 48 + if (id.charAt(12) == '/') {
264 - void addLink(Link link) { 49 + addGeoData(hosts, "id", id, memento);
265 - links.add(link); 50 + } else {
266 - if (this.link == null) { 51 + addGeoData(devices, "uri", id, memento);
267 - this.link = link;
268 - }
269 } 52 }
270 } 53 }
271 54
272 - // Returns a canonical key for the specified link. 55 + rootNode.set("devices", devices);
273 - static String key(Link link) { 56 + rootNode.set("hosts", hosts);
274 - String s = id(link.src()); 57 + return Response.ok(rootNode.toString()).build();
275 - String d = id(link.dst());
276 - return s.compareTo(d) > 0 ? d + s : s + d;
277 } 58 }
278 59
279 - // Returns a formatted string for the element associated with the given 60 + private void addGeoData(ArrayNode array, String idField, String id,
280 - // connection point. 61 + ObjectNode memento) {
281 - private static String id(ConnectPoint cp) { 62 + ObjectNode node = mapper.createObjectNode().put(idField, id);
282 - return cp.elementId().toString(); 63 + ObjectNode annot = mapper.createObjectNode();
64 + node.set("annotations", annot);
65 + annot.put("latitude", memento.get("lat").asDouble())
66 + .put("longitude", memento.get("lng").asDouble());
67 + array.add(node);
283 } 68 }
284 69
285 - // Auxiliary key/value carrier.
286 - private class Prop {
287 - private final String key;
288 - private final String value;
289 -
290 - protected Prop(String key, String value) {
291 - this.key = key;
292 - this.value = value;
293 - }
294 - }
295 -
296 - private class Separator extends Prop {
297 - protected Separator() {
298 - super("-", "");
299 - }
300 - }
301 } 70 }
......
...@@ -66,6 +66,7 @@ import org.slf4j.LoggerFactory; ...@@ -66,6 +66,7 @@ import org.slf4j.LoggerFactory;
66 66
67 import java.text.DecimalFormat; 67 import java.text.DecimalFormat;
68 import java.util.ArrayList; 68 import java.util.ArrayList;
69 +import java.util.Collections;
69 import java.util.HashMap; 70 import java.util.HashMap;
70 import java.util.HashSet; 71 import java.util.HashSet;
71 import java.util.Iterator; 72 import java.util.Iterator;
...@@ -129,6 +130,15 @@ public abstract class TopologyViewMessages { ...@@ -129,6 +130,15 @@ public abstract class TopologyViewMessages {
129 private static Map<String, ObjectNode> metaUi = new ConcurrentHashMap<>(); 130 private static Map<String, ObjectNode> metaUi = new ConcurrentHashMap<>();
130 131
131 /** 132 /**
133 + * Returns read-only view of the meta-ui information.
134 + *
135 + * @return map of id to meta-ui mementos
136 + */
137 + static Map<String, ObjectNode> getMetaUi() {
138 + return Collections.unmodifiableMap(metaUi);
139 + }
140 +
141 + /**
132 * Creates a messaging facility for creating messages for topology viewer. 142 * Creates a messaging facility for creating messages for topology viewer.
133 * 143 *
134 * @param directory service directory 144 * @param directory service directory
......