ONOS-314 Added ability to export JSON via GUI rest.
Change-Id: I8cc6011f54ce6a3fb50916a74cabb7234b04ef39
Showing
3 changed files
with
33 additions
and
291 deletions
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 | ... | ... |
-
Please register or login to post a comment