Refactor: move telemetry config from componentCfg to configs.xml

1. Support to export the metrics to multiple targets
2. Add a set of properties to kafka config (key, topic, etc.)
3. Add distributedStore to manage telemetry configs
4. Add CLI to query stored telemetry configs
5. Add a set of telemetry loaders to import xml definitions
6. Add unit tests for telemetry cfg, xml cfg loader and dist store
7. Add missing javadoc for a set of implementation classes

Change-Id: I39480c9a6ac07357184d2e1094b9c9f4d36fd8b1
diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultGrpcTelemetryConfig.java b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultGrpcTelemetryConfig.java
index 5ece99b..8d2f0fd 100644
--- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultGrpcTelemetryConfig.java
+++ b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultGrpcTelemetryConfig.java
@@ -19,18 +19,26 @@
 import com.google.common.collect.Maps;
 import org.onosproject.openstacktelemetry.api.config.GrpcTelemetryConfig;
 import org.onosproject.openstacktelemetry.api.config.TelemetryConfig;
+import org.onosproject.openstacktelemetry.api.config.TelemetryConfigProperties;
 
 import java.util.Map;
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.GRPC;
 
 /**
  * A configuration file contains gRPC telemetry parameters.
  */
 public final class DefaultGrpcTelemetryConfig implements GrpcTelemetryConfig {
 
+    protected static final String ADDRESS = "address";
+    protected static final String PORT = "port";
+    protected static final String USE_PLAINTEXT = "usePlaintext";
+    protected static final String MAX_INBOUND_MSG_SIZE = "maxInboundMsgSize";
+    protected static final String CONFIG_MAP = "configMap";
+
     private final String address;
     private final int port;
     private final boolean usePlaintext;
@@ -101,20 +109,39 @@
     @Override
     public String toString() {
         return toStringHelper(this)
-                .add("address", address)
-                .add("port", port)
-                .add("usePlaintext", usePlaintext)
-                .add("maxInboundMsgSize", maxInboundMsgSize)
-                .add("configMap", configMap)
+                .add(ADDRESS, address)
+                .add(PORT, port)
+                .add(USE_PLAINTEXT, usePlaintext)
+                .add(MAX_INBOUND_MSG_SIZE, maxInboundMsgSize)
+                .add(CONFIG_MAP, configMap)
                 .toString();
     }
 
     @Override
-    public TelemetryConfig.Builder createBuilder() {
+    public TelemetryConfigProperties.Builder createBuilder() {
         return new DefaultBuilder();
     }
 
     /**
+     * Builds a gRPC telemetry config from telemetry config instance.
+     *
+     * @param config telemetry config
+     * @return gRPC telemetry config
+     */
+    public static GrpcTelemetryConfig fromTelemetryConfig(TelemetryConfig config) {
+        if (config.type() != GRPC) {
+            return null;
+        }
+
+        return new DefaultBuilder()
+                .withAddress(config.getProperty(ADDRESS))
+                .withPort(Integer.valueOf(config.getProperty(PORT)))
+                .withUsePlaintext(Boolean.valueOf(config.getProperty(USE_PLAINTEXT)))
+                .withMaxInboundMsgSize(Integer.valueOf(config.getProperty(MAX_INBOUND_MSG_SIZE)))
+                .build();
+    }
+
+    /**
      * Builder class of DefaultKafkaTelemetryConfig.
      */
     public static final class DefaultBuilder implements Builder {
@@ -163,4 +190,4 @@
                     maxInboundMsgSize, configMap);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultInfluxDbTelemetryConfig.java b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultInfluxDbTelemetryConfig.java
index c63f2bc..db60cb8 100644
--- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultInfluxDbTelemetryConfig.java
+++ b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultInfluxDbTelemetryConfig.java
@@ -15,10 +15,12 @@
  */
 package org.onosproject.openstacktelemetry.config;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import org.onosproject.openstacktelemetry.api.config.InfluxDbTelemetryConfig;
 import org.onosproject.openstacktelemetry.api.config.TelemetryConfig;
+import org.onosproject.openstacktelemetry.api.config.TelemetryConfigProperties;
 
 import java.util.Map;
 import java.util.Objects;
@@ -31,6 +33,15 @@
  */
 public final class DefaultInfluxDbTelemetryConfig implements InfluxDbTelemetryConfig {
 
+    protected static final String ADDRESS = "address";
+    protected static final String PORT = "port";
+    protected static final String USERNAME = "username";
+    protected static final String PASSWORD = "password";
+    protected static final String DATABASE = "database";
+    protected static final String MEASUREMENT = "measurement";
+    protected static final String ENABLE_BATCH = "enableBatch";
+    protected static final String CONFIG_MAP = "configMap";
+
     private final String address;
     private final int port;
     private final String username;
@@ -122,29 +133,54 @@
     @Override
     public int hashCode() {
         return Objects.hash(address, port, username, password, database,
-                            measurement, enableBatch, configMap);
+                measurement, enableBatch, configMap);
     }
 
     @Override
     public String toString() {
         return toStringHelper(this)
-                .add("address", address)
-                .add("port", port)
-                .add("username", username)
-                .add("password", password)
-                .add("database", database)
-                .add("measurement", measurement)
-                .add("enableBatch", enableBatch)
-                .add("configMap", configMap)
+                .add(ADDRESS, address)
+                .add(PORT, port)
+                .add(USERNAME, username)
+                .add(PASSWORD, password)
+                .add(DATABASE, database)
+                .add(MEASUREMENT, measurement)
+                .add(ENABLE_BATCH, enableBatch)
+                .add(CONFIG_MAP, configMap)
                 .toString();
     }
 
     @Override
-    public TelemetryConfig.Builder createBuilder() {
+    public TelemetryConfigProperties.Builder createBuilder() {
         return new DefaultBuilder();
     }
 
     /**
+     * Builds an influxDB telemetry config from telemetry config instance.
+     *
+     * @param config telemetry config
+     * @return influxDB telemetry config
+     */
+    public static InfluxDbTelemetryConfig fromTelemetryConfig(TelemetryConfig config) {
+        if (config.type() != TelemetryConfig.ConfigType.INFLUXDB) {
+            return null;
+        }
+
+        boolean enableBatch = Strings.isNullOrEmpty(config.getProperty(ENABLE_BATCH)) ? false :
+                Boolean.valueOf(config.getProperty(ENABLE_BATCH));
+
+        return new DefaultBuilder()
+                .withAddress(config.getProperty(ADDRESS))
+                .withPort(Integer.valueOf(config.getProperty(PORT)))
+                .withUsername(config.getProperty(USERNAME))
+                .withPassword(config.getProperty(PASSWORD))
+                .withDatabase(config.getProperty(DATABASE))
+                .withMeasurement(config.getProperty(MEASUREMENT))
+                .withEnableBatch(enableBatch)
+                .build();
+    }
+
+    /**
      * Builder class of DefaultInfluxDbTelemetryConfig.
      */
     public static final class DefaultBuilder implements Builder {
@@ -211,11 +247,10 @@
             checkNotNull(address, "InfluxDB server address cannot be null");
             checkNotNull(username, "InfluxDB server username cannot be null");
             checkNotNull(password, "InfluxDB server password cannot be null");
-            checkNotNull(database, "InfluxDB server database cannot be null");
-            checkNotNull(measurement, "InfluxDB server measurement cannot be null");
 
             return new DefaultInfluxDbTelemetryConfig(address, port, username,
                     password, database, measurement, enableBatch, configMap);
         }
+
     }
-}
+}
\ No newline at end of file
diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultKafkaTelemetryConfig.java b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultKafkaTelemetryConfig.java
index 6fc90fd..1cd52ef 100644
--- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultKafkaTelemetryConfig.java
+++ b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultKafkaTelemetryConfig.java
@@ -15,22 +15,39 @@
  */
 package org.onosproject.openstacktelemetry.config;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import org.onosproject.openstacktelemetry.api.config.KafkaTelemetryConfig;
 import org.onosproject.openstacktelemetry.api.config.TelemetryConfig;
+import org.onosproject.openstacktelemetry.api.config.TelemetryConfigProperties;
 
 import java.util.Map;
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.KAFKA;
 
 /**
  * A configuration file contains Kafka telemetry parameters.
  */
 public final class DefaultKafkaTelemetryConfig implements KafkaTelemetryConfig {
 
+    protected static final String ADDRESS = "address";
+    protected static final String PORT = "port";
+    protected static final String RETRIES = "retries";
+    protected static final String REQUIRED_ACKS = "requiredAcks";
+    protected static final String BATCH_SIZE = "batchSize";
+    protected static final String LINGER_MS = "lingerMs";
+    protected static final String MEMORY_BUFFER = "memoryBuffer";
+    protected static final String KEY_SERIALIZER = "keySerializer";
+    protected static final String VALUE_SERIALIZER = "valueSerializer";
+    protected static final String KEY = "key";
+    protected static final String TOPIC = "topic";
+    protected static final String CODEC = "codec";
+    protected static final String CONFIG_MAP = "configMap";
+
     private final String address;
     private final int port;
     private final int retries;
@@ -40,6 +57,9 @@
     private final int memoryBuffer;
     private final String keySerializer;
     private final String valueSerializer;
+    private final String key;
+    private final String topic;
+    private final String codec;
     private final Map<String, Object> configMap;
 
     private DefaultKafkaTelemetryConfig(String address, int port, int retries,
@@ -47,6 +67,7 @@
                                         int lingerMs, int memoryBuffer,
                                         String keySerializer,
                                         String valueSerializer,
+                                        String key, String topic, String codec,
                                         Map<String, Object> configMap) {
         this.address = address;
         this.port = port;
@@ -57,6 +78,9 @@
         this.memoryBuffer = memoryBuffer;
         this.keySerializer = keySerializer;
         this.valueSerializer = valueSerializer;
+        this.key = key;
+        this.topic = topic;
+        this.codec = codec;
         this.configMap = configMap;
     }
 
@@ -106,6 +130,21 @@
     }
 
     @Override
+    public String key() {
+        return key;
+    }
+
+    @Override
+    public String topic() {
+        return topic;
+    }
+
+    @Override
+    public String codec() {
+        return codec;
+    }
+
+    @Override
     public Map<String, Object> configMap() {
         if (configMap != null) {
             return ImmutableMap.copyOf(configMap);
@@ -131,6 +170,9 @@
                     Objects.equals(this.memoryBuffer, other.memoryBuffer) &&
                     Objects.equals(this.keySerializer, other.keySerializer) &&
                     Objects.equals(this.valueSerializer, other.valueSerializer) &&
+                    Objects.equals(this.key, other.key) &&
+                    Objects.equals(this.topic, other.topic) &&
+                    Objects.equals(this.codec, other.codec) &&
                     Objects.equals(this.configMap, other.configMap);
         }
         return false;
@@ -139,31 +181,71 @@
     @Override
     public int hashCode() {
         return Objects.hash(address, port, retries, requiredAcks, batchSize,
-                lingerMs, memoryBuffer, keySerializer, valueSerializer, configMap);
+                lingerMs, memoryBuffer, keySerializer, valueSerializer,
+                key, topic, codec, configMap);
     }
 
     @Override
     public String toString() {
         return toStringHelper(this)
-                .add("address", address)
-                .add("port", port)
-                .add("retries", retries)
-                .add("requiredAcks", requiredAcks)
-                .add("batchSize", batchSize)
-                .add("lingerMs", lingerMs)
-                .add("memoryBuffer", memoryBuffer)
-                .add("keySerializer", keySerializer)
-                .add("valueSerializer", valueSerializer)
-                .add("configMap", configMap)
+                .add(ADDRESS, address)
+                .add(PORT, port)
+                .add(RETRIES, retries)
+                .add(REQUIRED_ACKS, requiredAcks)
+                .add(BATCH_SIZE, batchSize)
+                .add(LINGER_MS, lingerMs)
+                .add(MEMORY_BUFFER, memoryBuffer)
+                .add(KEY_SERIALIZER, keySerializer)
+                .add(VALUE_SERIALIZER, valueSerializer)
+                .add(KEY, key)
+                .add(TOPIC, topic)
+                .add(CODEC, codec)
+                .add(CONFIG_MAP, configMap)
                 .toString();
     }
 
     @Override
-    public TelemetryConfig.Builder createBuilder() {
+    public TelemetryConfigProperties.Builder createBuilder() {
         return new DefaultBuilder();
     }
 
     /**
+     * Builds a kafka telemetry config from telemetry config instance.
+     *
+     * @param config telemetry config
+     * @return kafka telemetry config
+     */
+    public static KafkaTelemetryConfig fromTelemetryConfig(TelemetryConfig config) {
+        if (config.type() != KAFKA) {
+            return null;
+        }
+
+        int retries = Strings.isNullOrEmpty(config.getProperty(RETRIES)) ? 0 :
+                Integer.valueOf(config.getProperty(RETRIES));
+        int batchSize = Strings.isNullOrEmpty(config.getProperty(BATCH_SIZE)) ? 0 :
+                Integer.valueOf(config.getProperty(BATCH_SIZE));
+        int lingerMs = Strings.isNullOrEmpty(config.getProperty(LINGER_MS)) ? 0 :
+                Integer.valueOf(config.getProperty(LINGER_MS));
+        int memoryBuffer = Strings.isNullOrEmpty(config.getProperty(MEMORY_BUFFER)) ? 0 :
+                Integer.valueOf(config.getProperty(MEMORY_BUFFER));
+
+        return new DefaultBuilder()
+                .withAddress(config.getProperty(ADDRESS))
+                .withPort(Integer.valueOf(config.getProperty(PORT)))
+                .withRetries(retries)
+                .withRequiredAcks(config.getProperty(REQUIRED_ACKS))
+                .withBatchSize(batchSize)
+                .withLingerMs(lingerMs)
+                .withMemoryBuffer(memoryBuffer)
+                .withKeySerializer(config.getProperty(KEY_SERIALIZER))
+                .withValueSerializer(config.getProperty(VALUE_SERIALIZER))
+                .withKey(config.getProperty(KEY))
+                .withTopic(config.getProperty(TOPIC))
+                .withCodec(config.getProperty(CODEC))
+                .build();
+    }
+
+    /**
      * Builder class of DefaultKafkaTelemetryConfig.
      */
     public static final class DefaultBuilder implements Builder {
@@ -176,6 +258,9 @@
         private int memoryBuffer;
         private String keySerializer;
         private String valueSerializer;
+        private String key;
+        private String topic;
+        private String codec;
         private Map<String, Object> configMap;
 
         @Override
@@ -233,6 +318,24 @@
         }
 
         @Override
+        public Builder withKey(String key) {
+            this.key = key;
+            return this;
+        }
+
+        @Override
+        public Builder withTopic(String topic) {
+            this.topic = topic;
+            return this;
+        }
+
+        @Override
+        public Builder withCodec(String codec) {
+            this.codec = codec;
+            return this;
+        }
+
+        @Override
         public Builder withConfigMap(Map<String, Object> configMap) {
             this.configMap = configMap;
             return this;
@@ -241,12 +344,10 @@
         @Override
         public KafkaTelemetryConfig build() {
             checkNotNull(address, "Kafka server address cannot be null");
-            checkNotNull(keySerializer, "Kafka key serializer cannot be null");
-            checkNotNull(valueSerializer, "Kafka value serializer cannot be null");
 
             return new DefaultKafkaTelemetryConfig(address, port, retries,
-                                requiredAcks, batchSize, lingerMs, memoryBuffer,
-                                keySerializer, valueSerializer, configMap);
+                    requiredAcks, batchSize, lingerMs, memoryBuffer, keySerializer,
+                    valueSerializer, key, topic, codec, configMap);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultPrometheusTelemetryConfig.java b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultPrometheusTelemetryConfig.java
index 33d1d2e..7dc5a5a 100644
--- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultPrometheusTelemetryConfig.java
+++ b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultPrometheusTelemetryConfig.java
@@ -19,18 +19,24 @@
 import com.google.common.collect.Maps;
 import org.onosproject.openstacktelemetry.api.config.PrometheusTelemetryConfig;
 import org.onosproject.openstacktelemetry.api.config.TelemetryConfig;
+import org.onosproject.openstacktelemetry.api.config.TelemetryConfigProperties;
 
 import java.util.Map;
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.PROMETHEUS;
 
 /**
  * A configuration file contains Prometheus telemetry parameters.
  */
 public final class DefaultPrometheusTelemetryConfig implements PrometheusTelemetryConfig {
 
+    protected static final String ADDRESS = "address";
+    protected static final String PORT = "port";
+    protected static final String CONFIG_MAP = "configMap";
+
     private final String address;
     private final int port;
     private final Map<String, Object> configMap;
@@ -85,18 +91,35 @@
     @Override
     public String toString() {
         return toStringHelper(this)
-                .add("address", address)
-                .add("port", port)
-                .add("configMap", configMap)
+                .add(ADDRESS, address)
+                .add(PORT, port)
+                .add(CONFIG_MAP, configMap)
                 .toString();
     }
 
     @Override
-    public TelemetryConfig.Builder createBuilder() {
+    public TelemetryConfigProperties.Builder createBuilder() {
         return new DefaultBuilder();
     }
 
     /**
+     * Builds a prometheus telemetry config from telemetry config instance.
+     *
+     * @param config telemetry config
+     * @return prometheus telemetry config
+     */
+    public static PrometheusTelemetryConfig fromTelemetryConfig(TelemetryConfig config) {
+        if (config.type() != PROMETHEUS) {
+            return null;
+        }
+
+        return new DefaultBuilder()
+                .withAddress(config.getProperty(ADDRESS))
+                .withPort(Integer.valueOf(config.getProperty(PORT)))
+                .build();
+    }
+
+    /**
      * Builder class of DefaultPrometheusTelemetryConfig.
      */
     public static final class DefaultBuilder implements Builder {
@@ -121,10 +144,11 @@
             this.configMap = configMap;
             return this;
         }
+
         @Override
         public PrometheusTelemetryConfig build() {
             checkNotNull(address, "Prometheus exporter binding address cannot be null");
             return new DefaultPrometheusTelemetryConfig(address, port, configMap);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultRestTelemetryConfig.java b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultRestTelemetryConfig.java
index df9d6ce..a5977a5 100644
--- a/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultRestTelemetryConfig.java
+++ b/apps/openstacktelemetry/app/src/main/java/org/onosproject/openstacktelemetry/config/DefaultRestTelemetryConfig.java
@@ -19,18 +19,28 @@
 import com.google.common.collect.Maps;
 import org.onosproject.openstacktelemetry.api.config.RestTelemetryConfig;
 import org.onosproject.openstacktelemetry.api.config.TelemetryConfig;
+import org.onosproject.openstacktelemetry.api.config.TelemetryConfigProperties;
 
 import java.util.Map;
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.REST;
 
 /**
  * A configuration file contains REST telemetry parameters.
  */
 public final class DefaultRestTelemetryConfig implements RestTelemetryConfig {
 
+    protected static final String ADDRESS = "address";
+    protected static final String PORT = "port";
+    protected static final String ENDPOINT = "endpoint";
+    protected static final String METHOD = "method";
+    protected static final String REQUEST_MEDIA_TYPE = "requestMediaType";
+    protected static final String RESPONSE_MEDIA_TYPE = "responseMediaType";
+    protected static final String CONFIG_MAP = "configMap";
+
     private final String address;
     private final int port;
     private final String endpoint;
@@ -119,22 +129,43 @@
     @Override
     public String toString() {
         return toStringHelper(this)
-                .add("address", address)
-                .add("port", port)
-                .add("endpoint", endpoint)
-                .add("method", method)
-                .add("requestMediaType", requestMediaType)
-                .add("responseMediaType", responseMediaType)
-                .add("configMap", configMap)
+                .add(ADDRESS, address)
+                .add(PORT, port)
+                .add(ENDPOINT, endpoint)
+                .add(METHOD, method)
+                .add(REQUEST_MEDIA_TYPE, requestMediaType)
+                .add(RESPONSE_MEDIA_TYPE, responseMediaType)
+                .add(CONFIG_MAP, configMap)
                 .toString();
     }
 
     @Override
-    public TelemetryConfig.Builder createBuilder() {
+    public TelemetryConfigProperties.Builder createBuilder() {
         return new DefaultBuilder();
     }
 
     /**
+     * Builds a REST telemetry config from telemetry config instance.
+     *
+     * @param config telemetry config
+     * @return REST telemetry config
+     */
+    public static RestTelemetryConfig fromTelemetryConfig(TelemetryConfig config) {
+        if (config.type() != REST) {
+            return null;
+        }
+
+        return new DefaultBuilder()
+                .withAddress(config.getProperty(ADDRESS))
+                .withPort(Integer.valueOf(config.getProperty(PORT)))
+                .withEndpoint(config.getProperty(ENDPOINT))
+                .withMethod(config.getProperty(METHOD))
+                .withRequestMediaType(config.getProperty(REQUEST_MEDIA_TYPE))
+                .withResponseMediaType(config.getProperty(RESPONSE_MEDIA_TYPE))
+                .build();
+    }
+
+    /**
      * Builder class of DefaultRestTelemetryConfig.
      */
     public static final class DefaultBuilder implements Builder {
@@ -198,4 +229,4 @@
                     method, requestMediaType, responseMediaType, configMap);
         }
     }
-}
+}
\ No newline at end of file