Aggregate stats from all cluster nodes and publish

Change-Id: Ic41cdcc8fc17845dabffc42b817b8bb7439a0b52
diff --git a/app/src/main/java/org/opencord/dhcpl2relay/impl/DhcpL2RelayStatistics.java b/app/src/main/java/org/opencord/dhcpl2relay/impl/DhcpL2RelayStatistics.java
new file mode 100644
index 0000000..c719253
--- /dev/null
+++ b/app/src/main/java/org/opencord/dhcpl2relay/impl/DhcpL2RelayStatistics.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ */
+
+package org.opencord.dhcpl2relay.impl;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Snapshot of DHCP L2 Relay statistics.
+ */
+public class DhcpL2RelayStatistics {
+
+    private final ImmutableMap<DhcpL2RelayCountersIdentifier, Long> counters;
+
+    private DhcpL2RelayStatistics(ImmutableMap<DhcpL2RelayCountersIdentifier, Long> counters) {
+        this.counters = counters;
+    }
+
+    /**
+     * Creates a new empty statistics instance.
+     */
+    public DhcpL2RelayStatistics() {
+        counters = ImmutableMap.of();
+    }
+
+    /**
+     * Gets the value of the counter with the given ID. Defaults to 0 if counter is not present.
+     *
+     * @param id counter ID
+     * @return counter value
+     */
+    public long get(DhcpL2RelayCountersIdentifier id) {
+        return counters.getOrDefault(id, 0L);
+    }
+
+    /**
+     * Gets the map of counters.
+     *
+     * @return map of counters
+     */
+    public Map<DhcpL2RelayCountersIdentifier, Long> counters() {
+        return counters;
+    }
+
+    /**
+     * Creates a new statistics instance with the given counter values.
+     *
+     * @param counters counters
+     * @return statistics
+     */
+    public static DhcpL2RelayStatistics withCounters(Map<DhcpL2RelayCountersIdentifier, Long> counters) {
+        ImmutableMap.Builder<DhcpL2RelayCountersIdentifier, Long> builder = ImmutableMap.builder();
+
+        counters.forEach(builder::put);
+
+        return new DhcpL2RelayStatistics(builder.build());
+    }
+
+    /**
+     * Adds the given statistics instance to this one (sums the common counters) and returns
+     * a new instance containing the result.
+     *
+     * @param other other instance
+     * @return result
+     */
+    public DhcpL2RelayStatistics add(DhcpL2RelayStatistics other) {
+        ImmutableMap.Builder<DhcpL2RelayCountersIdentifier, Long> builder = ImmutableMap.builder();
+
+        Set<DhcpL2RelayCountersIdentifier> keys = Sets.newHashSet(other.counters.keySet());
+
+        counters.forEach((id, value) -> {
+            builder.put(id, value + other.counters.getOrDefault(id, 0L));
+            keys.remove(id);
+        });
+
+        keys.forEach(i -> builder.put(i, other.counters.get(i)));
+
+        return new DhcpL2RelayStatistics(builder.build());
+    }
+
+    @Override
+    public String toString() {
+        MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(this.getClass());
+        counters.forEach((id, v) -> helper.add(id.toString(), v));
+        return helper.toString();
+    }
+}