[SDFAB-384] Modify the MeterStore APIs

Change-Id: I2b612bee1c6addc10a0126fe28880e8076735bfa
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java b/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java
index 21696e4..2e632ed 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java
@@ -27,11 +27,21 @@
 public interface MeterStore extends Store<MeterEvent, MeterStoreDelegate> {
 
     /**
-     * Adds a meter to the store.
+     * Adds a meter to the store or updates a meter in the store.
      *
      * @param meter a meter
      * @return a future indicating the result of the store operation
      */
+    CompletableFuture<MeterStoreResult> addOrUpdateMeter(Meter meter);
+
+    /**
+     * Adds a meter to the store.
+     *
+     * @param meter a meter
+     * @return a future indicating the result of the store operation
+     * @deprecated in onos-2.5 replaced by {@link #addOrUpdateMeter(Meter)}
+     */
+    @Deprecated
     CompletableFuture<MeterStoreResult> storeMeter(Meter meter);
 
     /**
@@ -51,6 +61,14 @@
     MeterStoreResult storeMeterFeatures(MeterFeatures meterfeatures);
 
     /**
+     * Adds a collection of meter features to the store.
+     *
+     * @param meterfeatures the collection of meter features
+     * @return the result of the store operation
+     */
+    MeterStoreResult storeMeterFeatures(Collection<MeterFeatures> meterfeatures);
+
+    /**
      * Deletes the meter features from the store.
      *
      * @param deviceId the device id
@@ -59,11 +77,21 @@
     MeterStoreResult deleteMeterFeatures(DeviceId deviceId);
 
     /**
+     * Deletes a collection of meter features from the store.
+     *
+     * @param meterfeatures a collection of meter features
+     * @return a future indicating the result of the store operation
+     */
+    MeterStoreResult deleteMeterFeatures(Collection<MeterFeatures> meterfeatures);
+
+    /**
      * Updates a meter whose meter id is the same as the passed meter.
      *
      * @param meter a new meter
      * @return a future indicating the result of the store operation
+     * @deprecated in onos-2.5 replaced by {@link #addOrUpdateMeter(Meter)}
      */
+    @Deprecated
     CompletableFuture<MeterStoreResult> updateMeter(Meter meter);
 
     /**
diff --git a/core/store/dist/src/main/java/org/onosproject/store/meter/impl/DistributedMeterStore.java b/core/store/dist/src/main/java/org/onosproject/store/meter/impl/DistributedMeterStore.java
index 2fdba6f..38f8748 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/meter/impl/DistributedMeterStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/meter/impl/DistributedMeterStore.java
@@ -86,6 +86,7 @@
 import static org.onosproject.net.meter.MeterFailReason.TIMEOUT;
 import static org.onosproject.net.meter.MeterCellId.MeterCellType.INDEX;
 import static org.onosproject.net.meter.MeterCellId.MeterCellType.PIPELINE_INDEPENDENT;
+import static org.onosproject.net.meter.MeterStoreResult.Type.FAIL;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -204,10 +205,30 @@
     }
 
     @Override
+    public CompletableFuture<MeterStoreResult> addOrUpdateMeter(Meter meter) {
+        // Init steps
+        CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
+        MeterKey key = MeterKey.key(meter.deviceId(), meter.meterCellId());
+        MeterData data = new MeterData(meter, null);
+        // Store the future related to the operation
+        futures.put(key, future);
+        // Check if the meter exists
+        try {
+            meters.compute(key, (k, v) -> data);
+        } catch (StorageException e) {
+            log.error("{} thrown a storage exception: {}", e.getStackTrace()[0].getMethodName(),
+                    e.getMessage(), e);
+            futures.remove(key);
+            future.completeExceptionally(e);
+        }
+        return future;
+    }
+
+    @Override
     public CompletableFuture<MeterStoreResult> storeMeter(Meter meter) {
         // Init steps
         CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
-        MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
+        MeterKey key = MeterKey.key(meter.deviceId(), meter.meterCellId());
         // Store the future related to the operation
         futures.put(key, future);
         // Store the meter data
@@ -228,7 +249,7 @@
     public CompletableFuture<MeterStoreResult> deleteMeter(Meter meter) {
         // Init steps
         CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
-        MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
+        MeterKey key = MeterKey.key(meter.deviceId(), meter.meterCellId());
         // Store the future related to the operation
         futures.put(key, future);
         // Create the meter data
@@ -267,6 +288,20 @@
     }
 
     @Override
+    public MeterStoreResult storeMeterFeatures(Collection<MeterFeatures> meterfeatures) {
+        // These store operations is treated as one single operation
+        // If one of them is failed, Fail is returned
+        // But the failed operation will not block the rest.
+        MeterStoreResult result = MeterStoreResult.success();
+        for (MeterFeatures mf : meterfeatures) {
+            if (storeMeterFeatures(mf).type() == FAIL) {
+                result = MeterStoreResult.fail(TIMEOUT);
+            }
+        }
+        return result;
+    }
+
+    @Override
     public MeterStoreResult deleteMeterFeatures(DeviceId deviceId) {
         MeterStoreResult result = MeterStoreResult.success();
         try {
@@ -286,10 +321,30 @@
     }
 
     @Override
+    public MeterStoreResult deleteMeterFeatures(Collection<MeterFeatures> meterfeatures) {
+        // These store operations is treated as one single operation
+        // If one of them is failed, Fail is returned
+        // But the failed operation will not block the rest.
+        MeterStoreResult result = MeterStoreResult.success();
+        for (MeterFeatures mf : meterfeatures) {
+            try {
+                MeterTableKey key = MeterTableKey.key(mf.deviceId(), mf.scope());
+                metersFeatures.remove(key);
+            } catch (StorageException e) {
+                log.error("{} thrown a storage exception: {}", e.getStackTrace()[0].getMethodName(),
+                        e.getMessage(), e);
+                result = MeterStoreResult.fail(TIMEOUT);
+            }
+        }
+
+        return result;
+    }
+
+    @Override
     // TODO Should we remove it ? We are not using it
     public CompletableFuture<MeterStoreResult> updateMeter(Meter meter) {
         CompletableFuture<MeterStoreResult> future = new CompletableFuture<>();
-        MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
+        MeterKey key = MeterKey.key(meter.deviceId(), meter.meterCellId());
         futures.put(key, future);
 
         MeterData data = new MeterData(meter, null);
@@ -309,7 +364,7 @@
     @Override
     public Meter updateMeterState(Meter meter) {
         // Update meter if present (stats workflow)
-        MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
+        MeterKey key = MeterKey.key(meter.deviceId(), meter.meterCellId());
         Versioned<MeterData> value = meters.computeIfPresent(key, (k, v) -> {
             DefaultMeter m = (DefaultMeter) v.meter();
             MeterState meterState = m.state();