Simon Hunt
Committed by Gerrit Code Review

ONOS-1479 -- GUI - augmenting topology view for extensibility:

- Cleaning up PropertyPanel methods - overloading values (string, int, long, object)

Change-Id: I84c86a48de8a776b407982687bc02def18eaef61
......@@ -29,6 +29,8 @@ import java.util.Set;
*/
public class PropertyPanel {
private static final DecimalFormat DF0 = new DecimalFormat("#,###");
private String title;
private String typeId;
private String id;
......@@ -47,28 +49,93 @@ public class PropertyPanel {
}
/**
* Adds a property to the panel.
* Adds an ID field to the panel data, to be included in
* the returned JSON data to the client.
*
* @param p the property
* @param id the identifier
* @return self, for chaining
*/
public PropertyPanel add(Prop p) {
properties.add(p);
public PropertyPanel id(String id) {
this.id = id;
return this;
}
/**
* Adds an ID field to the panel data, to be included in
* the returned JSON data to the client.
* Adds a property to the panel data.
*
* @param id the identifier
* @param key property key
* @param value property value
* @return self, for chaining
*/
public PropertyPanel id(String id) {
this.id = id;
public PropertyPanel addProp(String key, String value) {
properties.add(new Prop(key, value));
return this;
}
/**
* Adds a property to the panel data, using a decimal formatter.
*
* @param key property key
* @param value property value
* @return self, for chaining
*/
public PropertyPanel addProp(String key, int value) {
properties.add(new Prop(key, DF0.format(value)));
return this;
}
/**
* Adds a property to the panel data, using a decimal formatter.
*
* @param key property key
* @param value property value
* @return self, for chaining
*/
public PropertyPanel addProp(String key, long value) {
properties.add(new Prop(key, DF0.format(value)));
return this;
}
/**
* Adds a property to the panel data. Note that the value's
* {@link Object#toString toString()} method is used to convert the
* value to a string.
*
* @param key property key
* @param value property value
* @return self, for chaining
*/
public PropertyPanel addProp(String key, Object value) {
properties.add(new Prop(key, value.toString()));
return this;
}
/**
* Adds a property to the panel data. Note that the value's
* {@link Object#toString toString()} method is used to convert the
* value to a string, from which the characters defined in the given
* regular expression string are stripped.
*
* @param key property key
* @param value property value
* @param reStrip regexp characters to strip from value string
* @return self, for chaining
*/
public PropertyPanel addProp(String key, Object value, String reStrip) {
String val = value.toString().replaceAll(reStrip, "");
properties.add(new Prop(key, val));
return this;
}
/**
* Adds a separator to the panel data.
*
* @return self, for chaining
*/
public PropertyPanel addSeparator() {
properties.add(new Separator());
return this;
}
/**
* Returns the title text.
......@@ -161,7 +228,6 @@ public class PropertyPanel {
// ====================
private static final DecimalFormat DF0 = new DecimalFormat("#,###");
/**
* Simple data carrier for a property, composed of a key/value pair.
......@@ -182,26 +248,6 @@ public class PropertyPanel {
}
/**
* Constructs a property data value.
* @param key property key
* @param value property value
*/
public Prop(String key, int value) {
this.key = key;
this.value = DF0.format(value);
}
/**
* Constructs a property data value.
* @param key property key
* @param value property value
*/
public Prop(String key, long value) {
this.key = key;
this.value = DF0.format(value);
}
/**
* Returns the property's key.
*
* @return the key
......
......@@ -17,12 +17,17 @@
package org.onosproject.ui.topo;
import org.junit.BeforeClass;
import org.junit.Test;
import org.onosproject.ui.topo.PropertyPanel.Prop;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
/**
* Unit tests for {@link PropertyPanel}.
......@@ -33,20 +38,49 @@ public class PropertyPanelTest {
private static final String TYPE_ORIG = "Original type ID";
private static final String TITLE_NEW = "New Title";
private static final String TYPE_NEW = "New type";
private static final String SOME_IDENTIFICATION = "It's Me!";
private static final String KEY_A = "A";
private static final String KEY_B = "B";
private static final String KEY_C = "C";
private static final String KEY_Z = "Z";
private static final String VALUE_A = "Hay";
private static final String VALUE_B = "Bee";
private static final String VALUE_C = "Sea";
private static final String VALUE_Z = "Zed";
private static final Map<String, Prop> PROP_MAP = new HashMap<>();
private static class FooClass {
private final String s;
FooClass(String s) {
this.s = s;
}
private static final Prop PROP_A = new Prop("A", "Hay");
private static final Prop PROP_B = new Prop("B", "Bee");
private static final Prop PROP_C = new Prop("C", "Sea");
private static final Prop PROP_Z = new Prop("Z", "Zed");
@Override
public String toString() {
return ">" + s + "<";
}
}
private PropertyPanel pp;
@BeforeClass
public static void setUpClass() {
PROP_MAP.put(KEY_A, new Prop(KEY_A, VALUE_A));
PROP_MAP.put(KEY_B, new Prop(KEY_B, VALUE_B));
PROP_MAP.put(KEY_C, new Prop(KEY_C, VALUE_C));
PROP_MAP.put(KEY_Z, new Prop(KEY_Z, VALUE_Z));
}
@Test
public void basic() {
pp = new PropertyPanel(TITLE_ORIG, TYPE_ORIG);
assertEquals("wrong title", TITLE_ORIG, pp.title());
assertEquals("wrong type", TYPE_ORIG, pp.typeId());
assertNull("id?", pp.id());
assertEquals("unexpected props", 0, pp.properties().size());
}
......@@ -64,20 +98,46 @@ public class PropertyPanelTest {
assertEquals("wrong type", TYPE_NEW, pp.typeId());
}
private void validateProps(Prop... props) {
@Test
public void setId() {
basic();
pp.id(SOME_IDENTIFICATION);
assertEquals("wrong id", SOME_IDENTIFICATION, pp.id());
}
private void validateProps(String... keys) {
Iterator<Prop> iter = pp.properties().iterator();
for (Prop p: props) {
Prop ppProp = iter.next();
assertEquals("Bad prop sequence", p, ppProp);
for (String k: keys) {
Prop exp = PROP_MAP.get(k);
Prop act = iter.next();
assertEquals("Bad prop sequence", exp, act);
}
}
private void validateProp(String key, String expValue) {
Iterator<Prop> iter = pp.properties().iterator();
Prop prop = null;
while (iter.hasNext()) {
Prop p = iter.next();
if (p.key().equals(key)) {
prop = p;
break;
}
}
if (prop == null) {
fail("no prop found with key: " + key);
}
assertEquals("Wrong prop value", expValue, prop.value());
}
@Test
public void props() {
basic();
pp.add(PROP_A).add(PROP_B).add(PROP_C);
pp.addProp(KEY_A, VALUE_A)
.addProp(KEY_B, VALUE_B)
.addProp(KEY_C, VALUE_C);
assertEquals("bad props", 3, pp.properties().size());
validateProps(PROP_A, PROP_B, PROP_C);
validateProps(KEY_A, KEY_B, KEY_C);
}
@Test
......@@ -91,8 +151,45 @@ public class PropertyPanelTest {
@Test
public void adjustProps() {
props();
pp.removeProps("B", "A");
pp.add(PROP_Z);
validateProps(PROP_C, PROP_Z);
pp.removeProps(KEY_B, KEY_A);
pp.addProp(KEY_Z, VALUE_Z);
validateProps(KEY_C, KEY_Z);
}
@Test
public void intValues() {
basic();
pp.addProp(KEY_A, 200)
.addProp(KEY_B, 2000)
.addProp(KEY_C, 1234567);
validateProp(KEY_A, "200");
validateProp(KEY_B, "2,000");
validateProp(KEY_C, "1,234,567");
}
@Test
public void longValues() {
basic();
pp.addProp(KEY_A, 200L)
.addProp(KEY_B, 2000L)
.addProp(KEY_C, 1234567L)
.addProp(KEY_Z, Long.MAX_VALUE);
validateProp(KEY_A, "200");
validateProp(KEY_B, "2,000");
validateProp(KEY_C, "1,234,567");
validateProp(KEY_Z, "9,223,372,036,854,775,807");
}
@Test
public void objectValue() {
basic();
pp.addProp(KEY_A, new FooClass("a"))
.addProp(KEY_B, new FooClass("bxyyzy"), "[xz]");
validateProp(KEY_A, ">a<");
validateProp(KEY_B, ">byyy<");
}
}
......
......@@ -446,18 +446,17 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
// Returns property panel model for summary response.
protected PropertyPanel summmaryMessage(long sid) {
Topology topology = topologyService.currentTopology();
PropertyPanel pp = new PropertyPanel("ONOS Summary", "node")
.add(new PropertyPanel.Prop("Devices", topology.deviceCount()))
.add(new PropertyPanel.Prop("Links", topology.linkCount()))
.add(new PropertyPanel.Prop("Hosts", hostService.getHostCount()))
.add(new PropertyPanel.Prop("Topology SCCs", topology.clusterCount()))
.add(new PropertyPanel.Separator())
.add(new PropertyPanel.Prop("Intents", intentService.getIntentCount()))
.add(new PropertyPanel.Prop("Tunnels", tunnelService.tunnelCount()))
.add(new PropertyPanel.Prop("Flows", flowService.getFlowRuleCount()))
.add(new PropertyPanel.Prop("Version", version));
return pp;
return new PropertyPanel("ONOS Summary", "node")
.addProp("Devices", topology.deviceCount())
.addProp("Links", topology.linkCount())
.addProp("Hosts", hostService.getHostCount())
.addProp("Topology SCCs", topology.clusterCount())
.addSeparator()
.addProp("Intents", intentService.getIntentCount())
.addProp("Tunnels", tunnelService.tunnelCount())
.addProp("Flows", flowService.getFlowRuleCount())
.addProp("Version", version);
}
// Returns property panel model for device details response.
......@@ -474,19 +473,21 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
PropertyPanel pp = new PropertyPanel(title, typeId)
.id(deviceId.toString())
.add(new PropertyPanel.Prop("URI", deviceId.toString()))
.add(new PropertyPanel.Prop("Vendor", device.manufacturer()))
.add(new PropertyPanel.Prop("H/W Version", device.hwVersion()))
.add(new PropertyPanel.Prop("S/W Version", device.swVersion()))
.add(new PropertyPanel.Prop("Serial Number", device.serialNumber()))
.add(new PropertyPanel.Prop("Protocol", annot.value(AnnotationKeys.PROTOCOL)))
.add(new PropertyPanel.Separator())
.add(new PropertyPanel.Prop("Latitude", annot.value(AnnotationKeys.LATITUDE)))
.add(new PropertyPanel.Prop("Longitude", annot.value(AnnotationKeys.LONGITUDE)))
.add(new PropertyPanel.Separator())
.add(new PropertyPanel.Prop("Ports", portCount))
.add(new PropertyPanel.Prop("Flows", flowCount))
.add(new PropertyPanel.Prop("Tunnels", tunnelCount));
.addProp("URI", deviceId.toString())
.addProp("Vendor", device.manufacturer())
.addProp("H/W Version", device.hwVersion())
.addProp("S/W Version", device.swVersion())
.addProp("Serial Number", device.serialNumber())
.addProp("Protocol", annot.value(AnnotationKeys.PROTOCOL))
.addSeparator()
.addProp("Latitude", annot.value(AnnotationKeys.LATITUDE))
.addProp("Longitude", annot.value(AnnotationKeys.LONGITUDE))
.addSeparator()
.addProp("Ports", portCount)
.addProp("Flows", flowCount)
.addProp("Tunnels", tunnelCount);
// TODO: add button descriptors
return pp;
}
......@@ -570,13 +571,14 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
PropertyPanel pp = new PropertyPanel(title, typeId)
.id(hostId.toString())
.add(new PropertyPanel.Prop("MAC", host.mac().toString()))
.add(new PropertyPanel.Prop("IP", host.ipAddresses().toString().replaceAll("[\\[\\]]", "")))
.add(new PropertyPanel.Prop("VLAN", vlan.equals("-1") ? "none" : vlan))
.add(new PropertyPanel.Separator())
.add(new PropertyPanel.Prop("Latitude", annot.value(AnnotationKeys.LATITUDE)))
.add(new PropertyPanel.Prop("Longitude", annot.value(AnnotationKeys.LONGITUDE)));
.addProp("MAC", host.mac())
.addProp("IP", host.ipAddresses(), "[\\[\\]]")
.addProp("VLAN", vlan.equals("-1") ? "none" : vlan)
.addSeparator()
.addProp("Latitude", annot.value(AnnotationKeys.LATITUDE))
.addProp("Longitude", annot.value(AnnotationKeys.LONGITUDE));
// TODO: add button descriptors
return pp;
}
......@@ -860,21 +862,6 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
return result;
}
// Produces JSON property details.
private ObjectNode json(String id, String type, Prop... props) {
ObjectNode result = objectNode()
.put("id", id).put("type", type);
ObjectNode pnode = objectNode();
ArrayNode porder = arrayNode();
for (Prop p : props) {
porder.add(p.key);
pnode.put(p.key, p.value);
}
result.set("propOrder", porder);
result.set("props", pnode);
return result;
}
// Produces canonical link key, i.e. one that will match link and its inverse.
static LinkKey canonicalLinkKey(Link link) {
String sn = link.src().elementId().toString();
......@@ -946,25 +933,6 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
}
}
// Auxiliary key/value carrier.
@Deprecated
static class Prop {
public final String key;
public final String value;
protected Prop(String key, String value) {
this.key = key;
this.value = value;
}
}
// Auxiliary properties separator
@Deprecated
static class Separator extends Prop {
protected Separator() {
super("-", "");
}
}
// TODO: move this to traffic overlay component
// Auxiliary carrier of data for requesting traffic message.
......