ONOS-1479 -- GUI - augmenting topology view for extensibility:
- Cleaning up PropertyPanel methods - overloading values (string, int, long, object)
Change-Id: I84c86a48de8a776b407982687bc02def18eaef61
diff --git a/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java b/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java
index 88dad9a..87b6839 100644
--- a/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java
+++ b/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java
@@ -29,6 +29,8 @@
*/
public class PropertyPanel {
+ private static final DecimalFormat DF0 = new DecimalFormat("#,###");
+
private String title;
private String typeId;
private String id;
@@ -47,17 +49,6 @@
}
/**
- * Adds a property to the panel.
- *
- * @param p the property
- * @return self, for chaining
- */
- public PropertyPanel add(Prop p) {
- properties.add(p);
- return this;
- }
-
- /**
* Adds an ID field to the panel data, to be included in
* the returned JSON data to the client.
*
@@ -69,6 +60,82 @@
return this;
}
+ /**
+ * Adds a property to the panel data.
+ *
+ * @param key property key
+ * @param value property value
+ * @return self, for chaining
+ */
+ 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 @@
// ====================
- private static final DecimalFormat DF0 = new DecimalFormat("#,###");
/**
* Simple data carrier for a property, composed of a key/value pair.
@@ -182,26 +248,6 @@
}
/**
- * 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
diff --git a/core/api/src/test/java/org/onosproject/ui/topo/PropertyPanelTest.java b/core/api/src/test/java/org/onosproject/ui/topo/PropertyPanelTest.java
index 65bb167..7ca9ce5 100644
--- a/core/api/src/test/java/org/onosproject/ui/topo/PropertyPanelTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/topo/PropertyPanelTest.java
@@ -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 @@
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 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");
+ 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;
+ }
+
+ @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 @@
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 @@
@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<");
+ }
+
}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
index d32ad1d..017925b 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
@@ -446,18 +446,17 @@
// 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 @@
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 @@
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 @@
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 @@
}
}
- // 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.