Simon Hunt
Committed by Gerrit Code Review

ONOS-2186 - GUI Topo Overlay - (WIP)

- Re-worked JSONification of LinkHighlights to simplify code.
- added a couple of static imports to clean up code.

Change-Id: Ia210c17dfb10972b52241b7a01c0906eef0a1f2a
......@@ -53,12 +53,11 @@ import org.onosproject.net.intent.IntentListener;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.link.LinkEvent;
import org.onosproject.net.link.LinkListener;
import org.onosproject.ui.JsonUtils;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiConnection;
import org.onosproject.ui.impl.TrafficMonitor.Mode;
import org.onosproject.ui.topo.NodeSelection;
import org.onosproject.ui.topo.Highlights;
import org.onosproject.ui.topo.NodeSelection;
import org.onosproject.ui.topo.PropertyPanel;
import java.util.ArrayList;
......@@ -80,6 +79,8 @@ import static org.onosproject.net.HostId.hostId;
import static org.onosproject.net.device.DeviceEvent.Type.*;
import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
import static org.onosproject.ui.JsonUtils.envelope;
import static org.onosproject.ui.impl.topo.TopoJson.json;
/**
* Web socket capable of interacting with the GUI topology view.
......@@ -349,8 +350,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
overlayCache.currentOverlay().modifyHostDetails(pp);
}
ObjectNode json = JsonUtils.envelope(SHOW_DETAILS, sid, json(pp));
sendMessage(json);
sendMessage(envelope(SHOW_DETAILS, sid, json(pp)));
}
}
......@@ -538,7 +538,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
// Converts highlights to JSON format and sends the message to the client
protected void sendHighlights(Highlights highlights) {
sendMessage(JsonUtils.envelope(SHOW_HIGHLIGHTS, json(highlights)));
sendMessage(envelope(SHOW_HIGHLIGHTS, json(highlights)));
}
// Sends the specified data to the client.
......@@ -553,8 +553,7 @@ public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
private synchronized void requestSummary(long sid) {
PropertyPanel pp = summmaryMessage(sid);
overlayCache.currentOverlay().modifySummary(pp);
ObjectNode json = JsonUtils.envelope(SHOW_SUMMARY, sid, json(pp));
sendMessage(json);
sendMessage(envelope(SHOW_SUMMARY, sid, json(pp)));
}
......
......@@ -63,11 +63,6 @@ import org.onosproject.ui.JsonUtils;
import org.onosproject.ui.UiConnection;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.impl.topo.ServicesBundle;
import org.onosproject.ui.topo.ButtonId;
import org.onosproject.ui.topo.DeviceHighlight;
import org.onosproject.ui.topo.Highlights;
import org.onosproject.ui.topo.HostHighlight;
import org.onosproject.ui.topo.LinkHighlight;
import org.onosproject.ui.topo.PropertyPanel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -96,9 +91,9 @@ import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED;
import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
import static org.onosproject.ui.topo.TopoUtils.compactLinkString;
import static org.onosproject.ui.topo.TopoConstants.CoreButtons;
import static org.onosproject.ui.topo.TopoConstants.Properties;
import static org.onosproject.ui.topo.TopoUtils.compactLinkString;
/**
* Facility for creating messages bound for the topology viewer.
......@@ -511,118 +506,4 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
return pp;
}
// ----------------------------------------------------------------------
/**
* Transforms the given highlights model into a JSON message payload.
*
* @param highlights the model to transform
* @return JSON payload
*/
protected ObjectNode json(Highlights highlights) {
ObjectNode payload = objectNode();
ArrayNode devices = arrayNode();
ArrayNode hosts = arrayNode();
ArrayNode links = arrayNode();
payload.set("devices", devices);
payload.set("hosts", hosts);
payload.set("links", links);
highlights.devices().forEach(dh -> devices.add(json(dh)));
highlights.hosts().forEach(hh -> hosts.add(json(hh)));
jsonifyLinks(links, highlights.links());
return payload;
}
private void jsonifyLinks(ArrayNode links, Set<LinkHighlight> hilites) {
// a little more complicated than devices or hosts, since we are
// grouping the link highlights by CSS classes
// TODO: refactor this method (including client side) to use new format
// as a more compact representation of the data...
// * links:
// * "primary animated":
// * "link01" -> "label"
// * "link02" -> "label"
// * "secondary":
// * "link04" -> "label"
// * "link05" -> ""
Map<String, List<String>> linkIdMap = new HashMap<>();
Map<String, List<String>> linkLabelMap = new HashMap<>();
List<String> ids;
List<String> labels;
for (LinkHighlight lh : hilites) {
String cls = lh.cssClasses();
ids = linkIdMap.get(cls);
labels = linkLabelMap.get(cls);
if (ids == null) { // labels will be null also
ids = new ArrayList<>();
linkIdMap.put(cls, ids);
labels = new ArrayList<>();
linkLabelMap.put(cls, labels);
}
ids.add(lh.elementId());
labels.add(lh.label());
}
for (String cls : linkIdMap.keySet()) {
ObjectNode group = objectNode();
links.add(group);
group.put("class", cls);
ArrayNode lnks = arrayNode();
ArrayNode labs = arrayNode();
group.set("links", lnks);
group.set("labels", labs);
linkIdMap.get(cls).forEach(lnks::add);
linkLabelMap.get(cls).forEach(labs::add);
}
}
protected ObjectNode json(DeviceHighlight dh) {
// TODO: implement this once we know what a device highlight looks like
return objectNode();
}
protected ObjectNode json(HostHighlight hh) {
// TODO: implement this once we know what a host highlight looks like
return objectNode();
}
// translates the property panel into JSON, for returning to the client
protected ObjectNode json(PropertyPanel pp) {
ObjectNode result = objectNode()
.put("title", pp.title())
.put("type", pp.typeId())
.put("id", pp.id());
ObjectNode pnode = objectNode();
ArrayNode porder = arrayNode();
for (PropertyPanel.Prop p : pp.properties()) {
porder.add(p.key());
pnode.put(p.key(), p.value());
}
result.set("propOrder", porder);
result.set("props", pnode);
ArrayNode buttons = arrayNode();
for (ButtonId b : pp.buttons()) {
buttons.add(b.id());
}
result.set("buttons", buttons);
return result;
}
}
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.onosproject.ui.impl.topo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onosproject.ui.topo.ButtonId;
import org.onosproject.ui.topo.DeviceHighlight;
import org.onosproject.ui.topo.Highlights;
import org.onosproject.ui.topo.HostHighlight;
import org.onosproject.ui.topo.LinkHighlight;
import org.onosproject.ui.topo.PropertyPanel;
/**
* JSON utilities for the Topology View.
*/
public final class TopoJson {
private static final String DEVICES = "devices";
private static final String HOSTS = "hosts";
private static final String LINKS = "links";
private static final String ID = "id";
private static final String LABEL = "label";
private static final String CSS = "css";
private static final String TITLE = "title";
private static final String TYPE = "type";
private static final String PROP_ORDER = "propOrder";
private static final String PROPS = "props";
private static final String BUTTONS = "buttons";
private static final ObjectMapper MAPPER = new ObjectMapper();
private static ObjectNode objectNode() {
return MAPPER.createObjectNode();
}
private static ArrayNode arrayNode() {
return MAPPER.createArrayNode();
}
// non-instantiable
private TopoJson() { }
/**
* Transforms the given highlights model into a JSON message payload.
*
* @param highlights the model to transform
* @return JSON payload
*/
public static ObjectNode json(Highlights highlights) {
ObjectNode payload = objectNode();
ArrayNode devices = arrayNode();
ArrayNode hosts = arrayNode();
ArrayNode links = arrayNode();
payload.set(DEVICES, devices);
payload.set(HOSTS, hosts);
payload.set(LINKS, links);
highlights.devices().forEach(dh -> devices.add(json(dh)));
highlights.hosts().forEach(hh -> hosts.add(json(hh)));
highlights.links().forEach(lh -> links.add(json(lh)));
return payload;
}
private static ObjectNode json(DeviceHighlight dh) {
// TODO: implement this once we know what a device highlight looks like
return objectNode();
}
private static ObjectNode json(HostHighlight hh) {
// TODO: implement this once we know what a host highlight looks like
return objectNode();
}
private static ObjectNode json(LinkHighlight lh) {
return objectNode()
.put(ID, lh.elementId())
.put(LABEL, lh.label())
.put(CSS, lh.cssClasses());
}
/**
* Translates the given property panel into JSON, for returning
* to the client.
*
* @param pp the property panel model
* @return JSON payload
*/
public static ObjectNode json(PropertyPanel pp) {
ObjectNode result = objectNode()
.put(TITLE, pp.title())
.put(TYPE, pp.typeId())
.put(ID, pp.id());
ObjectNode pnode = objectNode();
ArrayNode porder = arrayNode();
for (PropertyPanel.Prop p : pp.properties()) {
porder.add(p.key());
pnode.put(p.key(), p.value());
}
result.set(PROP_ORDER, porder);
result.set(PROPS, pnode);
ArrayNode buttons = arrayNode();
for (ButtonId b : pp.buttons()) {
buttons.add(b.id());
}
result.set(BUTTONS, buttons);
return result;
}
}
......@@ -293,7 +293,6 @@
tss = _tss_;
}
// TODO: refactor this (currently using showTraffic data structure)
function showHighlights(data) {
/*
API to topoForce
......@@ -303,43 +302,39 @@
findLinkById( id )
*/
var paths = data.links;
// TODO: clear node highlighting
api.clearLinkTrafficStyle();
api.removeLinkLabels();
// Now highlight all links in the paths payload, and attach
// labels to them, if they are defined.
paths.forEach(function (p) {
var n = p.links.length,
i, ldata, lab, units, magnitude, portcls;
for (i=0; i<n; i++) {
ldata = api.findLinkById(p.links[i]);
lab = p.labels[i];
if (ldata && !ldata.el.empty()) {
ldata.el.classed(p.class, true);
ldata.label = lab;
if (fs.endsWith(lab, 'bps')) {
// inject additional styling for port-based traffic
units = lab.substring(lab.length-4);
portcls = 'port-traffic-' + units;
// for GBps
if (units.substring(0,1) === 'G') {
magnitude = fs.parseBitRate(lab);
if (magnitude >= 9) {
portcls += '-choked'
}
// TODO: device and host highlights
data.links.forEach(function (lnk) {
var ldata = api.findLinkById(lnk.id),
lab = lnk.label,
units, portcls, magnitude;
if (ldata && !ldata.el.empty()) {
ldata.el.classed(lnk.css, true);
ldata.label = lab;
// inject additional styling for port-based traffic
if (fs.endsWith(lab, 'bps')) {
units = lab.substring(lab.length-4);
portcls = 'port-traffic-' + units;
// for GBps
if (units.substring(0,1) === 'G') {
magnitude = fs.parseBitRate(lab);
if (magnitude >= 9) {
portcls += '-choked'
}
ldata.el.classed(portcls, true);
}
ldata.el.classed(portcls, true);
}
}
});
// TODO: api.updateNodes()
api.updateLinks();
}
......
......@@ -211,6 +211,7 @@
// invoked from mouseover/mouseout and selection change
requestTrafficForMode: requestTrafficForMode,
// TODO: these should move to new UI demo app
// invoked from buttons on detail (multi-select) panel
addHostIntent: addHostIntent,
addMultiSourceIntent: addMultiSourceIntent
......