Add annotation to ChartModel

Change-Id: I7c299ccb3a6363fac1c66ce001813e2197029e1e
diff --git a/core/api/src/main/java/org/onosproject/ui/chart/ChartModel.java b/core/api/src/main/java/org/onosproject/ui/chart/ChartModel.java
index 9493acf..40c3028 100644
--- a/core/api/src/main/java/org/onosproject/ui/chart/ChartModel.java
+++ b/core/api/src/main/java/org/onosproject/ui/chart/ChartModel.java
@@ -20,7 +20,10 @@
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -30,7 +33,6 @@
 
 /**
  * A simple model of time series chart data.
- *
  * <p>
  * Note that this is not a full MVC type model; the expected usage pattern
  * is to create an empty chart, add data points (by consulting the business model),
@@ -43,6 +45,7 @@
     private final String[] seriesArray;
     private final List<Long> labels = Lists.newArrayList();
     private final List<DataPoint> dataPoints = Lists.newArrayList();
+    private final Map<String, Annot> annotations = new HashMap<>();
 
     /**
      * Constructs a chart model with initialized series set.
@@ -146,6 +149,72 @@
     }
 
     /**
+     * Inserts a new annotation.
+     *
+     * @param key key of annotation
+     * @param value value of annotation
+     */
+    public void addAnnotation(String key, Object value) {
+        annotations.put(key, new Annot(key, value));
+    }
+
+    /**
+     * Returns the annotations in this chart.
+     *
+     * @return annotations
+     */
+    public Collection<Annot> getAnnotations() {
+        return new ArrayList<>(annotations.values());
+    }
+
+    /**
+     * 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();
+        }
+    }
+
+    /**
      * A class of data point.
      */
     public class DataPoint {
@@ -156,7 +225,7 @@
          * Sets the data value for the given series of this data point.
          *
          * @param series series name
-         * @param value value to set
+         * @param value  value to set
          * @return self, for chaining
          */
         public DataPoint data(String series, Double value) {
diff --git a/core/api/src/main/java/org/onosproject/ui/chart/ChartRequestHandler.java b/core/api/src/main/java/org/onosproject/ui/chart/ChartRequestHandler.java
index 2cbc05f..1d00689 100644
--- a/core/api/src/main/java/org/onosproject/ui/chart/ChartRequestHandler.java
+++ b/core/api/src/main/java/org/onosproject/ui/chart/ChartRequestHandler.java
@@ -31,6 +31,8 @@
     private final String nodeName;
     protected static final String LABEL = "label";
 
+    private static final String ANNOTS = "annots";
+
     /**
      * Constructs a chart model handler for a specific graph view. When chart
      * requests come in, the handler will generate the appropriate chart data
@@ -53,6 +55,7 @@
 
         ObjectNode rootNode = MAPPER.createObjectNode();
         rootNode.set(nodeName, ChartUtils.generateDataPointArrayNode(cm));
+        rootNode.set(ANNOTS, ChartUtils.generateAnnotObjectNode(cm));
         sendMessage(respType, 0, rootNode);
     }
 
diff --git a/core/api/src/main/java/org/onosproject/ui/chart/ChartUtils.java b/core/api/src/main/java/org/onosproject/ui/chart/ChartUtils.java
index 959a2b0..7ba0bdd 100644
--- a/core/api/src/main/java/org/onosproject/ui/chart/ChartUtils.java
+++ b/core/api/src/main/java/org/onosproject/ui/chart/ChartUtils.java
@@ -46,6 +46,20 @@
     }
 
     /**
+     * Generates a JSON object node from the annotations of the given chart model.
+     *
+     * @param cm the chart model
+     * @return the object node representation of the annotations
+     */
+    public static ObjectNode generateAnnotObjectNode(ChartModel cm) {
+        ObjectNode node = MAPPER.createObjectNode();
+        for (ChartModel.Annot a : cm.getAnnotations()) {
+            node.put(a.key(), a.valueAsString());
+        }
+        return node;
+    }
+
+    /**
      * Generate a JSON node from the data point and given chart model.
      *
      * @param dp the data point
diff --git a/core/api/src/test/java/org/onosproject/ui/chart/ChartUtilsTest.java b/core/api/src/test/java/org/onosproject/ui/chart/ChartUtilsTest.java
index 13059d6..2252503 100644
--- a/core/api/src/test/java/org/onosproject/ui/chart/ChartUtilsTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/chart/ChartUtilsTest.java
@@ -16,6 +16,7 @@
 package org.onosproject.ui.chart;
 
 import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -29,6 +30,8 @@
 
     private static final String ARRAY_AS_STRING =
             "[{\"foo\":1.0,\"bar\":2.0},{\"foo\":3.0,\"bar\":4.0}]";
+    private static final String NODE_AS_STRING =
+            "{\"dev1\":\"of:0000000000000001\",\"dev2\":\"of:0000000000000002\"}";
 
     @Test
     public void basic() {
@@ -39,4 +42,14 @@
         ArrayNode array = ChartUtils.generateDataPointArrayNode(cm);
         Assert.assertEquals("wrong results", ARRAY_AS_STRING, array.toString());
     }
+
+    @Test
+    public void annot() {
+        ChartModel cm = new ChartModel(FOO, BAR);
+        cm.addAnnotation("dev1", "of:0000000000000001");
+        cm.addAnnotation("dev2", "of:0000000000000002");
+
+        ObjectNode node = ChartUtils.generateAnnotObjectNode(cm);
+        Assert.assertEquals("wrong results", NODE_AS_STRING, node.toString());
+    }
 }