Added a framework for metrics

Added a metrics framework based on the codahale Metrics
package.  ONOS can create a registry and maintain Metrics,
as well as dump out metrics values via a REST API.  Unit
tests are include that test the REST APIs.  Currently
supports Timers, Counters, Gauges, Meters, and Histograms.

Change-Id: I0f6ed87f889dc7037caf9aefc92e663702c6dda8
diff --git a/src/main/java/net/onrc/onos/core/metrics/MetricsObjectResource.java b/src/main/java/net/onrc/onos/core/metrics/MetricsObjectResource.java
new file mode 100644
index 0000000..efb0213
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/metrics/MetricsObjectResource.java
@@ -0,0 +1,283 @@
+package net.onrc.onos.core.metrics;
+
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.Timer;
+import com.codahale.metrics.Histogram;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import java.util.List;
+
+/**
+ * Resource class to hold Metrics information.  Timers, Gauges, Counters,
+ * Meters and Historgrams are currently implemented.
+ */
+@JsonSerialize(using = MetricsObjectSerializer.class)
+@SuppressWarnings("rawtypes")
+public class MetricsObjectResource {
+
+    /**
+     * Base Metric object that all metrics inherit from.  Defines common
+     * attributes.
+     */
+    static class BaseMetricObject {
+        private final String name;
+
+        /**
+         * Constructor for the base object.  Sets the name attribute.
+         *
+         * @param newName name of the Metric
+         */
+        protected BaseMetricObject(final String newName) {
+            name = newName;
+        }
+
+        /**
+         * Get the name of the Metric.
+         *
+         * @return metric name
+         */
+        public String getName() {
+            return name;
+        }
+    }
+
+    /**
+     * Metric object that represents a Timer.
+     */
+    static class TimerObjectResource extends BaseMetricObject {
+        private final Timer timer;
+
+        /**
+         * Construct a new Timer resource object.
+         *
+         * @param newName name to use for the timer
+         * @param newTimer Metrics Timer object
+         */
+        public TimerObjectResource(final String newName,
+                                   final Timer newTimer) {
+            super(newName);
+            timer = newTimer;
+        }
+
+        /**
+         * Get the Metrics Timer object for this resource.
+         *
+         * @return Metrics Timer object.
+         */
+        public Timer getTimer() {
+            return timer;
+        }
+    }
+
+    /**
+     * Metric object that represents a Gauge.
+     */
+    static class GaugeObjectResource extends BaseMetricObject {
+        private final Gauge gauge;
+
+        /**
+         * Constructs a new Gauge resource object.
+         *
+         * @param newName name to use for the Gauge object
+         * @param newGauge Metrics Gauge object
+         */
+        public GaugeObjectResource(final String newName,
+                                   final Gauge newGauge) {
+            super(newName);
+            gauge = newGauge;
+        }
+
+        /**
+         * Gets the Metrics Gauge object for this resource.
+         *
+         * @return Metrics Gauge object.
+         */
+        public Gauge getGauge() {
+            return gauge;
+        }
+    }
+
+    /**
+     * Metric object that represents a Counter.
+     */
+    static class CounterObjectResource extends BaseMetricObject {
+        private final Counter counter;
+
+        /**
+         * Constructs a new Counter resource object.
+         *
+         * @param newName name to use for the Counter object
+         * @param newCounter Metrics Counter object
+         */
+        public CounterObjectResource(final String newName,
+                                     final Counter newCounter) {
+            super(newName);
+            counter = newCounter;
+        }
+
+        /**
+         * Gets the Metrics Counter object for this resource.
+         *
+         * @return Metrics Counter object.
+         */
+        public Counter getCounter() {
+            return counter;
+        }
+    }
+
+    /**
+     * Metric object that represents a Meter.
+     */
+    static class MeterObjectResource extends BaseMetricObject {
+        private final Meter meter;
+
+        /**
+         * Constructs a new Meter resource object.
+         *
+         * @param newName name to use for the Meter object
+         * @param newMeter Metrics Meter object
+         */
+        public MeterObjectResource(final String newName,
+                                   final Meter newMeter) {
+            super(newName);
+            meter = newMeter;
+        }
+
+        /**
+         * Gets the Metrics Meter object for this resource.
+         *
+         * @return Metrics Meter object.
+         */
+        public Meter getMeter() {
+            return meter;
+        }
+    }
+
+    /**
+     * Metric objerct that represents a Histogram.
+     */
+    static class HistogramObjectResource extends BaseMetricObject {
+        private final Histogram histogram;
+
+        /**
+         * Constructs a new Histogram resource object.
+         *
+         * @param newName name to use for Histogram object.
+         * @param newHistogram Metrics Histogram object.
+         */
+        public HistogramObjectResource(final String newName,
+                                       final Histogram newHistogram) {
+            super(newName);
+            histogram = newHistogram;
+        }
+
+        /**
+         * Gets the Metrics Histogram object for this resource.
+         *
+         * @return Metrics Histogram Object
+         */
+        public Histogram getHistogram() {
+            return histogram;
+        }
+    }
+
+
+    private List<TimerObjectResource> timers;
+    private List<GaugeObjectResource> gauges;
+    private List<CounterObjectResource> counters;
+    private List<MeterObjectResource> meters;
+    private List<HistogramObjectResource> histograms;
+
+    /**
+     * Gets the list of Gauge objects.
+     *
+     * @return list of gauges
+     */
+    public List<GaugeObjectResource> getGauges() {
+        return gauges;
+    }
+
+    /**
+     * Defines the list of Gauge objects.
+     *
+     * @param gauges list of gauges
+     */
+    public void setGauges(List<GaugeObjectResource> gauges) {
+        this.gauges = gauges;
+    }
+
+    /**
+     * Gets the list of Timer objects.
+     *
+     * @return list of Timers
+     */
+    public List<TimerObjectResource> getTimers() {
+        return timers;
+    }
+
+    /**
+     * Defines the list of Timer objects.
+     *
+     * @param newTimers list of Timers
+     */
+    public void setTimers(List<TimerObjectResource> newTimers) {
+        timers = newTimers;
+    }
+
+    /**
+     * Gets the list of Counter objects.
+     *
+     * @return list of Counters
+     */
+    public List<CounterObjectResource> getCounters() {
+        return counters;
+    }
+
+    /**
+     * Defines the list of Counter objects.
+     *
+     * @param counters list of Counters
+     */
+    public void setCounters(List<CounterObjectResource> counters) {
+        this.counters = counters;
+    }
+
+    /**
+     * Gets the list of Meter objects.
+     *
+     * @return list of Meters
+     */
+    public List<MeterObjectResource> getMeters() {
+        return meters;
+    }
+
+    /**
+     * Defines the list of Meter objects.
+     *
+     * @param meters list of Meters
+     */
+    public void setMeters(List<MeterObjectResource> meters) {
+        this.meters = meters;
+    }
+
+    /**
+     * Gets the list of Histogram objects.
+     *
+     * @return list of Histograms
+     */
+    public List<HistogramObjectResource> getHistograms() {
+        return histograms;
+    }
+
+    /**
+     * Defines the list of Histogram objects.
+     *
+     * @param histograms list of Histograms.
+     */
+    public void setHistograms(List<HistogramObjectResource> histograms) {
+        this.histograms = histograms;
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/metrics/MetricsObjectSerializer.java b/src/main/java/net/onrc/onos/core/metrics/MetricsObjectSerializer.java
new file mode 100644
index 0000000..ba32381
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/metrics/MetricsObjectSerializer.java
@@ -0,0 +1,123 @@
+package net.onrc.onos.core.metrics;
+
+import com.codahale.metrics.json.MetricsModule;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.SerializerProvider;
+import org.codehaus.jackson.map.ser.std.SerializerBase;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * JSON serializer for the Metrics resource.
+ */
+public class MetricsObjectSerializer extends SerializerBase<MetricsObjectResource> {
+
+    /**
+     * Public constructor - just calls its super class constructor.
+     */
+    public MetricsObjectSerializer() {
+        super(MetricsObjectResource.class);
+    }
+
+    /**
+     * Convenience method to serialize a Metrics field.
+     *
+     * @param jsonGenerator generator to use for serialization
+     * @param fieldName name of the top level field
+     * @param serializedObjectJSON JSON representation from the Metrics serializer
+     * @param object internal resource for the Metric
+     * @throws IOException if JSON generation fails.
+     */
+    private void serializeItem(final JsonGenerator jsonGenerator,
+                               final String fieldName,
+                               final String serializedObjectJSON,
+                               final MetricsObjectResource.BaseMetricObject object)
+            throws IOException {
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("name", object.getName());
+
+        // If you write the JSON for the Metric using a StringField, the
+        // generator applies an extra set of double quotes and breaks the
+        // syntax.  You have to use the raw JSON output to get it right.
+        jsonGenerator.writeRaw(",\"" + fieldName + "\": " + serializedObjectJSON);
+        jsonGenerator.writeEndObject();
+    }
+
+    /**
+     * Serialize a MetricsObjectResource into JSON.  For each kind of Metric,
+     * his serializes common ONOS defined fields like name and
+     * then calls the Metrics serializer to make the JSON string
+     * for the actual Metric.
+     *
+     * @param metrics resource for all ONOS Metrics
+     * @param jsonGenerator generator to use for the JSON output
+     * @param serializerProvider unused, needed for Override
+     * @throws IOException if any of the JSON serializations fail
+     */
+    @Override
+    @SuppressWarnings("rawtypes")
+    public void serialize(final MetricsObjectResource metrics,
+                          final JsonGenerator jsonGenerator,
+                          final SerializerProvider serializerProvider)
+            throws IOException {
+
+        final ObjectMapper mapper = new ObjectMapper().registerModule(
+                new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, false));
+        jsonGenerator.writeStartObject();
+
+        //  serialize Timers
+        jsonGenerator.writeArrayFieldStart("timers");
+
+        for (final MetricsObjectResource.TimerObjectResource timer :
+             metrics.getTimers()) {
+            final String timerJSON = mapper.writeValueAsString(timer.getTimer());
+            serializeItem(jsonGenerator, "timer", timerJSON, timer);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Serialize Gauges
+        jsonGenerator.writeArrayFieldStart("gauges");
+
+        for (final MetricsObjectResource.GaugeObjectResource gauge :
+             metrics.getGauges()) {
+            final String gaugeJSON = mapper.writeValueAsString(gauge.getGauge());
+            serializeItem(jsonGenerator, "gauge", gaugeJSON, gauge);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Serialize Counters
+        jsonGenerator.writeArrayFieldStart("counters");
+
+        for (final MetricsObjectResource.CounterObjectResource counter :
+             metrics.getCounters()) {
+            final String counterJSON = mapper.writeValueAsString(counter.getCounter());
+            serializeItem(jsonGenerator, "counter", counterJSON, counter);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Serialize Meters
+        jsonGenerator.writeArrayFieldStart("meters");
+
+        for (final MetricsObjectResource.MeterObjectResource meter :
+             metrics.getMeters()) {
+            final String meterJSON = mapper.writeValueAsString(meter.getMeter());
+            serializeItem(jsonGenerator, "meter", meterJSON, meter);
+        }
+        jsonGenerator.writeEndArray();
+
+        // Serialize Histograms
+        jsonGenerator.writeArrayFieldStart("histograms");
+
+        for (final MetricsObjectResource.HistogramObjectResource histogram :
+             metrics.getHistograms()) {
+            final String histogramJSON = mapper.writeValueAsString(histogram.getHistogram());
+            serializeItem(jsonGenerator, "histogram", histogramJSON, histogram);
+        }
+        jsonGenerator.writeEndArray();
+
+        jsonGenerator.writeEndObject();
+   }
+
+}
diff --git a/src/main/java/net/onrc/onos/core/metrics/MetricsResource.java b/src/main/java/net/onrc/onos/core/metrics/MetricsResource.java
new file mode 100644
index 0000000..64b7996
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/metrics/MetricsResource.java
@@ -0,0 +1,82 @@
+package net.onrc.onos.core.metrics;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.Timer;
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.Histogram;
+import org.restlet.representation.Representation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * REST APIs for Metrics objects.
+ */
+public class MetricsResource extends ServerResource {
+
+    /**
+     * REST API to get all of the system's metrics.
+     *
+     * @return a Representation object containing the metrics
+     */
+    @Get("json")
+    @SuppressWarnings("rawtypes")
+    public Representation retrieve() throws Exception {
+        final MetricRegistry registry = OnosMetrics.getMetricsRegistry();
+        final MetricsObjectResource result = new MetricsObjectResource();
+
+        final List<MetricsObjectResource.TimerObjectResource> timers =
+                new ArrayList<>();
+        final List<MetricsObjectResource.GaugeObjectResource> gauges =
+                new ArrayList<>();
+        final List<MetricsObjectResource.CounterObjectResource> counters =
+                new ArrayList<>();
+        final List<MetricsObjectResource.MeterObjectResource> meters =
+                new ArrayList<>();
+        final List<MetricsObjectResource.HistogramObjectResource> histograms =
+                new ArrayList<>();
+
+        for (final Map.Entry<String, Timer> timer :
+             registry.getTimers().entrySet()) {
+            timers.add(new MetricsObjectResource.TimerObjectResource(
+                    timer.getKey(), timer.getValue()));
+        }
+        result.setTimers(timers);
+
+        for (final Map.Entry<String, Gauge> gauge :
+             registry.getGauges().entrySet()) {
+            gauges.add(new MetricsObjectResource.GaugeObjectResource(
+                    gauge.getKey(), gauge.getValue()));
+        }
+        result.setGauges(gauges);
+
+        for (final Map.Entry<String, Counter> counter :
+             registry.getCounters().entrySet()) {
+            counters.add(new MetricsObjectResource.CounterObjectResource(
+                    counter.getKey(), counter.getValue()));
+        }
+        result.setCounters(counters);
+
+        for (final Map.Entry<String, Meter> meter :
+             registry.getMeters().entrySet()) {
+            meters.add(new MetricsObjectResource.MeterObjectResource(
+                    meter.getKey(), meter.getValue()));
+        }
+        result.setMeters(meters);
+
+        for (final Map.Entry<String, Histogram> histogram :
+             registry.getHistograms().entrySet()) {
+            histograms.add(new MetricsObjectResource.HistogramObjectResource(
+                    histogram.getKey(), histogram.getValue()));
+        }
+        result.setHistograms(histograms);
+
+        return toRepresentation(result, null);
+    }
+
+}
diff --git a/src/main/java/net/onrc/onos/core/metrics/MetricsWebRoutable.java b/src/main/java/net/onrc/onos/core/metrics/MetricsWebRoutable.java
new file mode 100644
index 0000000..2761e71
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/metrics/MetricsWebRoutable.java
@@ -0,0 +1,31 @@
+package net.onrc.onos.core.metrics;
+
+import net.floodlightcontroller.restserver.RestletRoutable;
+import org.restlet.Context;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+
+/**
+ * Restlet Router for Metrics REST APIs.
+ */
+public class MetricsWebRoutable implements RestletRoutable {
+    /**
+     * Creates the Restlet router and binds to the proper resources.
+     */
+    @Override
+    public Restlet getRestlet(Context context) {
+        Router router = new Router(context);
+        // GET all metrics
+        router.attach("", MetricsResource.class);
+        return router;
+    }
+
+
+    /**
+     * Sets the base path for the Metrics.
+     */
+    @Override
+    public String basePath() {
+        return "/wm/onos/metrics";
+    }
+}
diff --git a/src/main/java/net/onrc/onos/core/metrics/OnosMetrics.java b/src/main/java/net/onrc/onos/core/metrics/OnosMetrics.java
new file mode 100644
index 0000000..bfd603f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/metrics/OnosMetrics.java
@@ -0,0 +1,28 @@
+package net.onrc.onos.core.metrics;
+
+import com.codahale.metrics.MetricRegistry;
+
+/**
+ * This class acts a singleton to hold the Metrics registry for ONOS.
+ */
+public final class OnosMetrics {
+
+    /**
+     * Hide constructor.  The only way to get the registry is through the
+     * singleton getter.
+     */
+    private OnosMetrics() {}
+
+    private static final MetricRegistry METRICS_REGISTRY = new MetricRegistry();
+
+    /**
+     * Get the singleton Metrics registry.  A single instance of
+     * the registry is statically allocated and then used by all callers.
+     *
+     * @return Metrics registry
+     */
+    public static MetricRegistry getMetricsRegistry() {
+        return METRICS_REGISTRY;
+    }
+}
+
diff --git a/src/main/java/net/onrc/onos/core/metrics/OnosMetricsModule.java b/src/main/java/net/onrc/onos/core/metrics/OnosMetricsModule.java
new file mode 100644
index 0000000..6f046cf
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/metrics/OnosMetricsModule.java
@@ -0,0 +1,53 @@
+package net.onrc.onos.core.metrics;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.floodlightcontroller.restserver.IRestApiService;
+import net.onrc.onos.core.registry.IControllerRegistryService;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Floodlight module to add the REST APIs for Metrics.
+ */
+public class OnosMetricsModule implements IFloodlightModule {
+
+    private IRestApiService restApi;
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+        return null;
+    }
+
+    @Override
+    public Map<Class<? extends IFloodlightService>, IFloodlightService>
+           getServiceImpls() {
+        return null;
+    }
+
+    @Override
+    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+        List<Class<? extends IFloodlightService>> dependencies =
+                new ArrayList<>();
+        dependencies.add(IControllerRegistryService.class);
+        dependencies.add(IRestApiService.class);
+        return dependencies;
+    }
+
+    @Override
+    public void init(FloodlightModuleContext context)
+            throws FloodlightModuleException {
+        restApi = context.getServiceImpl(IRestApiService.class);
+    }
+
+    @Override
+    public void startUp(FloodlightModuleContext context) {
+        restApi.addRestletRoutable(new MetricsWebRoutable());
+    }
+}
+