[WIP][ONOS-3722] Augment TableModel with Annotations Mechanism
Change-Id: I815ce0b0fde254dd730153c34905d9454f019d9a
diff --git a/core/api/src/main/java/org/onosproject/ui/table/TableModel.java b/core/api/src/main/java/org/onosproject/ui/table/TableModel.java
index d0fccb6..bf5d95d 100644
--- a/core/api/src/main/java/org/onosproject/ui/table/TableModel.java
+++ b/core/api/src/main/java/org/onosproject/ui/table/TableModel.java
@@ -22,6 +22,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -57,7 +58,7 @@
private final Map<String, CellComparator> comparators = new HashMap<>();
private final Map<String, CellFormatter> formatters = new HashMap<>();
private final List<Row> rows = new ArrayList<>();
-
+ private final Map<String, Annot> annotations = new HashMap<>();
/**
* Constructs a table (devoid of data) with the given column IDs.
@@ -124,6 +125,28 @@
}
/**
+ * Inserts a new annotation.
+ *
+ * @param key key of annotation
+ * @param value value of annotation
+ */
+ public void addAnnotation(String key, Object value) {
+ Annot annot = new Annot(key, value);
+ annotations.put(key, annot);
+ }
+
+ /**
+ * Returns the annotations in this table.
+ *
+ * @return annotations
+ */
+ public Collection<Annot> getAnnotations() {
+ Collection<Annot> annots = new ArrayList<>(annotations.size());
+ annotations.forEach((k, v) -> annots.add(v));
+ return annots;
+ }
+
+ /**
* Sets a cell comparator for the specified column.
*
* @param columnId column identifier
@@ -233,6 +256,53 @@
}
/**
+ * Model of an annotation.
+ */
+ public class Annot {
+ private final String key;
+ private final Object value;
+
+ /**
+ * Constructs an annotation with the given key and value.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ public Annot(String key, Object value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ /**
+ * Returns the annotation's key.
+ *
+ * @return key
+ */
+ public String key() {
+ return key;
+ }
+
+ /**
+ * Returns the annotation's value.
+ *
+ * @return value
+ */
+ public Object value() {
+ return value;
+ }
+
+ /**
+ * Returns the value as a string.
+ * This default implementation uses the value's toString() method.
+ *
+ * @return the value as a string
+ */
+ public String valueAsString() {
+ return value.toString();
+ }
+ }
+
+ /**
* Model of a row.
*/
public class Row {
diff --git a/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java b/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java
index b8d4857..43700db 100644
--- a/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java
+++ b/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java
@@ -25,6 +25,8 @@
*/
public abstract class TableRequestHandler extends RequestHandler {
+ private static final String ANNOTS = "annots";
+ private static final String NO_ROWS_MSG_KEY = "no_rows_msg";
private final String respType;
private final String nodeName;
@@ -53,8 +55,11 @@
String sortDir = JsonUtils.string(payload, "sortDir", "asc");
tm.sort(sortCol, TableModel.sortDir(sortDir));
+ addTableConfigAnnotations(tm);
+
ObjectNode rootNode = MAPPER.createObjectNode();
- rootNode.set(nodeName, TableUtils.generateArrayNode(tm));
+ rootNode.set(nodeName, TableUtils.generateRowArrayNode(tm));
+ rootNode.set(ANNOTS, TableUtils.generateAnnotObjectNode(tm));
sendMessage(respType, 0, rootNode);
}
@@ -72,6 +77,15 @@
}
/**
+ * Adds all annotations to table model.
+ *
+ * @param tm a table model
+ */
+ protected void addTableConfigAnnotations(TableModel tm) {
+ tm.addAnnotation(NO_ROWS_MSG_KEY, noRowsMessage());
+ }
+
+ /**
* Returns the default column ID to be used when one is not supplied in
* the payload as the column on which to sort.
* <p>
@@ -92,6 +106,15 @@
protected abstract String[] getColumnIds();
/**
+ * Subclasses should return the message to display in the table when there
+ * are no rows to display. For example, a host table might return
+ * "No hosts found".
+ *
+ * @return the message
+ */
+ protected abstract String noRowsMessage();
+
+ /**
* Subclasses should populate the table model by adding
* {@link TableModel.Row rows}.
* <pre>
@@ -108,4 +131,4 @@
* @param payload request payload
*/
protected abstract void populateTable(TableModel tm, ObjectNode payload);
-}
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/ui/table/TableUtils.java b/core/api/src/main/java/org/onosproject/ui/table/TableUtils.java
index eb2dff7..14c6743 100644
--- a/core/api/src/main/java/org/onosproject/ui/table/TableUtils.java
+++ b/core/api/src/main/java/org/onosproject/ui/table/TableUtils.java
@@ -32,12 +32,12 @@
private TableUtils() { }
/**
- * Generates a JSON array node from a table model.
+ * Generates a JSON array node from the rows of the given table model.
*
* @param tm the table model
- * @return the array node representation
+ * @return the array node representation of rows
*/
- public static ArrayNode generateArrayNode(TableModel tm) {
+ public static ArrayNode generateRowArrayNode(TableModel tm) {
ArrayNode array = MAPPER.createArrayNode();
for (TableModel.Row r : tm.getRows()) {
array.add(toJsonNode(r, tm));
@@ -45,6 +45,20 @@
return array;
}
+ /**
+ * Generates a JSON object node from the annotations of the given table model.
+ *
+ * @param tm the table model
+ * @return the object node representation of the annotations
+ */
+ public static ObjectNode generateAnnotObjectNode(TableModel tm) {
+ ObjectNode node = MAPPER.createObjectNode();
+ for (TableModel.Annot a : tm.getAnnotations()) {
+ node.put(a.key(), a.valueAsString());
+ }
+ return node;
+ }
+
private static JsonNode toJsonNode(TableModel.Row row, TableModel tm) {
ObjectNode result = MAPPER.createObjectNode();
String[] keys = tm.getColumnIds();
diff --git a/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java b/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java
index 7524bcb..8c79a05 100644
--- a/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java
@@ -21,6 +21,8 @@
import org.onosproject.ui.table.cell.DefaultCellFormatter;
import org.onosproject.ui.table.cell.HexFormatter;
+import java.util.Collection;
+
import static org.junit.Assert.*;
/**
@@ -122,7 +124,6 @@
assertEquals("bad cell", true, row.get(BAR));
}
-
private static final String ONE = "one";
private static final String TWO = "two";
private static final String THREE = "three";
@@ -313,7 +314,6 @@
assertEquals("null sort dir", SortDir.ASC, TableModel.sortDir(null));
}
-
@Test
public void enumSort() {
tm = new TableModel(FOO);
@@ -335,4 +335,83 @@
assertEquals(UNEX_SORT + i, ordered[i], rows[i].get(FOO));
}
}
+
+ @Test
+ public void stringAnnotation() {
+ tm = new TableModel(FOO);
+ tm.addAnnotation(BAR, ZOO);
+ Collection<TableModel.Annot> annots = tm.getAnnotations();
+ assertEquals("wrong size", 1, annots.size());
+
+ TableModel.Annot annot = annots.iterator().next();
+ assertEquals("wrong key", BAR, annot.key());
+ assertEquals("wrong value", ZOO, annot.value());
+ }
+
+ private static final String K_INT = "int";
+ private static final String K_BOOL = "bool";
+ private static final String K_FLOAT = "float";
+ private static final String K_DOUBLE = "double";
+ private static final String K_ENUM = "enum";
+
+ private TableModel.Annot getAnnotation(Collection<TableModel.Annot> annots, String key) {
+ final TableModel.Annot[] annot = {null};
+ annots.forEach(a -> {
+ if (a.key().equals(key)) {
+ annot[0] = a;
+ }
+ });
+ return annot[0];
+ }
+
+ private void verifyCollectionContains(Collection<TableModel.Annot> annots,
+ String key, int i) {
+ TableModel.Annot a = getAnnotation(annots, key);
+ assertEquals("wrong int value", i, a.value());
+ }
+
+ private void verifyCollectionContains(Collection<TableModel.Annot> annots,
+ String key, boolean b) {
+ TableModel.Annot a = getAnnotation(annots, key);
+ assertEquals("wrong boolean value", b, a.value());
+ }
+
+ private void verifyCollectionContains(Collection<TableModel.Annot> annots,
+ String key, float f) {
+ TableModel.Annot a = getAnnotation(annots, key);
+ assertEquals("wrong float value", f, a.value());
+ }
+
+ private void verifyCollectionContains(Collection<TableModel.Annot> annots,
+ String key, double d) {
+ TableModel.Annot a = getAnnotation(annots, key);
+ assertEquals("wrong double value", d, a.value());
+ }
+
+ private void verifyCollectionContains(Collection<TableModel.Annot> annots,
+ String key, Enum<?> e) {
+ TableModel.Annot a = getAnnotation(annots, key);
+ assertEquals("wrong double value", e, a.value());
+ }
+
+ @Test
+ public void primitivesAnnotation() {
+ tm = new TableModel(FOO);
+ tm.addAnnotation(K_INT, 1);
+ tm.addAnnotation(K_BOOL, true);
+ tm.addAnnotation(K_FLOAT, 3.14f);
+ tm.addAnnotation(K_DOUBLE, 2.71828);
+ tm.addAnnotation(K_ENUM, StarWars.LUKE_SKYWALKER);
+
+ Collection<TableModel.Annot> annots = tm.getAnnotations();
+ assertEquals("wrong size", 5, annots.size());
+
+ verifyCollectionContains(annots, K_INT, 1);
+ verifyCollectionContains(annots, K_BOOL, true);
+ verifyCollectionContains(annots, K_FLOAT, 3.14f);
+ verifyCollectionContains(annots, K_DOUBLE, 2.71828);
+ verifyCollectionContains(annots, K_ENUM, StarWars.LUKE_SKYWALKER);
+ }
+
+ // TODO: add support for compound object value
}
diff --git a/core/api/src/test/java/org/onosproject/ui/table/TableUtilsTest.java b/core/api/src/test/java/org/onosproject/ui/table/TableUtilsTest.java
index 4456dd3..66ac647 100644
--- a/core/api/src/test/java/org/onosproject/ui/table/TableUtilsTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/table/TableUtilsTest.java
@@ -37,7 +37,7 @@
tm.addRow().cell(FOO, 1).cell(BAR, 2);
tm.addRow().cell(FOO, 3).cell(BAR, 4);
- ArrayNode array = TableUtils.generateArrayNode(tm);
+ ArrayNode array = TableUtils.generateRowArrayNode(tm);
Assert.assertEquals("wrong results", ARRAY_AS_STRING, array.toString());
}