Jian Li
Committed by Gerrit Code Review

[WIP][ONOS-3722] Augment TableModel with Annotations Mechanism

Change-Id: I815ce0b0fde254dd730153c34905d9454f019d9a
Showing 21 changed files with 309 additions and 9 deletions
......@@ -57,6 +57,8 @@ public class DhcpViewMessageHandler extends UiMessageHandler {
// handler for dhcp table requests
private final class DataRequestHandler extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No mappings found";
private DataRequestHandler() {
super(DHCP_DATA_REQ, DHCP_DATA_RESP, DHCP);
}
......@@ -72,6 +74,11 @@ public class DhcpViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected void populateTable(TableModel tm, ObjectNode payload) {
DhcpService dhcpService = AbstractShellCommand.get(DhcpService.class);
Map<HostId, IpAssignment> allocationMap = dhcpService.listMapping();
......
......@@ -63,6 +63,8 @@ public class DriverMatrixMessageHandler extends UiMessageHandler {
// handler for sample table requests
private final class SampleTableDataRequestHandler extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No data found";
private SampleTableDataRequestHandler() {
super(SAMPLE_TABLE_DATA_REQ, SAMPLE_TABLE_DATA_RESP, SAMPLE_TABLES);
}
......@@ -74,6 +76,11 @@ public class DriverMatrixMessageHandler extends UiMessageHandler {
return COLUMN_IDS;
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
// if required, override createTableModel() to set column formatters / comparators
@Override
......
......@@ -74,6 +74,8 @@ public class AlarmTableMessageHandler extends UiMessageHandler {
// handler for alarm table requests
private final class AlarmTableDataRequestHandler extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No alarms found";
private AlarmTableDataRequestHandler() {
super(ALARM_TABLE_DATA_REQ, ALARM_TABLE_DATA_RESP, ALARM_TABLES);
}
......@@ -90,6 +92,11 @@ public class AlarmTableMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
// if required, override createTableModel() to set column formatters / comparators
TableModel tm = super.createTableModel();
......
......@@ -22,6 +22,7 @@ import org.onosproject.ui.table.cell.DefaultCellFormatter;
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 @@ public class TableModel {
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 @@ public class TableModel {
}
/**
* 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 @@ public class TableModel {
}
/**
* 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 {
......
......@@ -25,6 +25,8 @@ import org.onosproject.ui.RequestHandler;
*/
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 @@ public abstract class TableRequestHandler extends RequestHandler {
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 @@ public abstract class TableRequestHandler extends RequestHandler {
}
/**
* 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 @@ public abstract class TableRequestHandler extends RequestHandler {
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 @@ public abstract class TableRequestHandler extends RequestHandler {
* @param payload request payload
*/
protected abstract void populateTable(TableModel tm, ObjectNode payload);
}
}
\ No newline at end of file
......
......@@ -32,12 +32,12 @@ public final class TableUtils {
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 @@ public final class TableUtils {
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();
......
......@@ -21,6 +21,8 @@ import org.onosproject.ui.table.TableModel.SortDir;
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 @@ public class TableModelTest {
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 @@ public class TableModelTest {
assertEquals("null sort dir", SortDir.ASC, TableModel.sortDir(null));
}
@Test
public void enumSort() {
tm = new TableModel(FOO);
......@@ -335,4 +335,83 @@ public class TableModelTest {
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
}
......
......@@ -37,7 +37,7 @@ public class TableUtilsTest {
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());
}
......
......@@ -66,6 +66,8 @@ public class ApplicationViewMessageHandler extends UiMessageHandler {
// handler for application table requests
private final class AppDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No applications found";
private AppDataRequest() {
super(APP_DATA_REQ, APP_DATA_RESP, APPS);
}
......@@ -76,6 +78,11 @@ public class ApplicationViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected void populateTable(TableModel tm, ObjectNode payload) {
ApplicationService as = get(ApplicationService.class);
for (Application app : as.getApplications()) {
......
......@@ -60,6 +60,8 @@ public class ClusterViewMessageHandler extends UiMessageHandler {
// handler for cluster table requests
private final class ClusterDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No cluster nodes found";
private ClusterDataRequest() {
super(CLUSTER_DATA_REQ, CLUSTER_DATA_RESP, CLUSTERS);
}
......@@ -70,6 +72,11 @@ public class ClusterViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(UPDATED, new TimeFormatter());
......
......@@ -127,6 +127,8 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
// handler for device table requests
private final class DataRequestHandler extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No devices found";
private DataRequestHandler() {
super(DEV_DATA_REQ, DEV_DATA_RESP, DEVICES);
}
......@@ -137,6 +139,11 @@ public class DeviceViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected void populateTable(TableModel tm, ObjectNode payload) {
DeviceService ds = get(DeviceService.class);
MastershipService ms = get(MastershipService.class);
......
......@@ -75,6 +75,8 @@ public class FlowViewMessageHandler extends UiMessageHandler {
// handler for flow table requests
private final class FlowDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No flows found";
private FlowDataRequest() {
super(FLOW_DATA_REQ, FLOW_DATA_RESP, FLOWS);
}
......@@ -85,6 +87,11 @@ public class FlowViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(ID, HexLongFormatter.INSTANCE);
......
......@@ -65,6 +65,8 @@ public class GroupViewMessageHandler extends UiMessageHandler {
// handler for group table requests
private final class GroupDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No groups found";
private GroupDataRequest() {
super(GROUP_DATA_REQ, GROUP_DATA_RESP, GROUPS);
}
......@@ -75,6 +77,12 @@ public class GroupViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
// TODO: if devices with OF 1.0, should return not support message
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(ID, HexFormatter.INSTANCE);
......
......@@ -62,6 +62,8 @@ public class HostViewMessageHandler extends UiMessageHandler {
// handler for host table requests
private final class HostDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No hosts found";
private HostDataRequest() {
super(HOST_DATA_REQ, HOST_DATA_RESP, HOSTS);
}
......@@ -72,6 +74,11 @@ public class HostViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(LOCATION, HostLocationFormatter.INSTANCE);
......
......@@ -71,6 +71,8 @@ public class IntentViewMessageHandler extends UiMessageHandler {
// handler for intent table requests
private final class IntentDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No intents found";
private IntentDataRequest() {
super(INTENT_DATA_REQ, INTENT_DATA_RESP, INTENTS);
}
......@@ -86,6 +88,11 @@ public class IntentViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(APP_ID, AppIdFormatter.INSTANCE);
......
......@@ -65,6 +65,8 @@ public class LinkViewMessageHandler extends UiMessageHandler {
// handler for link table requests
private final class LinkDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No links found";
private LinkDataRequest() {
super(LINK_DATA_REQ, LINK_DATA_RESP, LINKS);
}
......@@ -75,6 +77,11 @@ public class LinkViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected String defaultColumnId() {
return ONE;
}
......
......@@ -61,6 +61,8 @@ public class MeterViewMessageHandler extends UiMessageHandler {
// handler for meter table requests
private final class MeterDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No meters found";
private MeterDataRequest() {
super(METER_DATA_REQ, METER_DATA_RESP, METERS);
}
......@@ -71,6 +73,12 @@ public class MeterViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
// TODO: if the device with OF 1.0, return not support message
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(ID, HexLongFormatter.INSTANCE);
......
......@@ -62,6 +62,8 @@ public class PortViewMessageHandler extends UiMessageHandler {
// handler for port table requests
private final class PortDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No ports found";
private PortDataRequest() {
super(PORT_DATA_REQ, PORT_DATA_RESP, PORTS);
}
......@@ -72,6 +74,11 @@ public class PortViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(PKT_RX, NumberFormatter.INTEGER);
......
......@@ -64,6 +64,8 @@ public class ProcessorViewMessageHandler extends UiMessageHandler {
// handler for packet processor table requests
private final class ProcessorDataRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No packet processors found";
private ProcessorDataRequest() {
super(PROCESSOR_DATA_REQ, PROCESSOR_DATA_RESP, PROCESSORS);
}
......@@ -74,6 +76,11 @@ public class ProcessorViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(AVG_MS, NumberFormatter.TO_5DP);
......
......@@ -53,6 +53,8 @@ public class SettingsViewMessageHandler extends UiMessageHandler {
// handler for host table requests
private final class SettingsRequest extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No settings found";
private SettingsRequest() {
super(DATA_REQUEST, DATA_RESPONSE, SETTINGS);
}
......@@ -63,6 +65,11 @@ public class SettingsViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected String defaultColumnId() {
return COMPONENT;
}
......
......@@ -55,6 +55,8 @@ public class TunnelViewMessageHandler extends UiMessageHandler {
private final class TunnelDataRequestHandler extends TableRequestHandler {
private static final String NO_ROWS_MESSAGE = "No tunnels found";
public TunnelDataRequestHandler() {
super(TUNNEL_DATA_REQ, TUNNEL_DATA_RESP, TUNNELS);
}
......@@ -65,6 +67,11 @@ public class TunnelViewMessageHandler extends UiMessageHandler {
}
@Override
protected String noRowsMessage() {
return NO_ROWS_MESSAGE;
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
//TODO add more formater class so that we can get a more readable table
......