[VOL-2525] Fixing the OLT app meter removal and optimizing the bandwith profile to meter map with a Multimap

Change-Id: I62b1fe58770df8f1a9e73a4b5bc1dec751d47ad9
diff --git a/app/src/main/java/org/opencord/olt/impl/OltMeterService.java b/app/src/main/java/org/opencord/olt/impl/OltMeterService.java
index df434eb..3fff30c 100644
--- a/app/src/main/java/org/opencord/olt/impl/OltMeterService.java
+++ b/app/src/main/java/org/opencord/olt/impl/OltMeterService.java
@@ -15,9 +15,12 @@
  */
 package org.opencord.olt.impl;
 
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
 import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -51,7 +54,7 @@
 import org.slf4j.Logger;
 
 import java.util.ArrayList;
-
+import java.util.Collection;
 import java.util.Dictionary;
 import java.util.Iterator;
 import java.util.List;
@@ -68,6 +71,9 @@
 import static org.onlab.util.Tools.groupedThreads;
 import static org.slf4j.LoggerFactory.getLogger;
 
+/**
+ * Provisions Meters on access devices.
+ */
 @Service
 @Component(immediate = true)
 public class OltMeterService implements AccessDeviceMeterService {
@@ -85,7 +91,8 @@
             label = "Deleting Meters based on flow count statistics")
     protected boolean deleteMeters = true;
 
-    protected Map<String, Set<MeterKey>> bpInfoToMeter;
+    protected SetMultimap<String, MeterKey> bpInfoToMeter =
+            Multimaps.synchronizedSetMultimap(HashMultimap.create());
     protected Set<MeterKey> programmedMeters;
     private ApplicationId appId;
     private static final String APP_NAME = "org.opencord.olt";
@@ -101,7 +108,6 @@
         eventExecutor = Executors.newFixedThreadPool(5, groupedThreads("onos/olt",
                 "events-%d", log));
         appId = coreService.registerApplication(APP_NAME);
-        bpInfoToMeter = Maps.newConcurrentMap();
         programmedMeters = Sets.newConcurrentHashSet();
         meterService.addListener(meterListener);
         componentConfigService.registerProperties(getClass());
@@ -125,20 +131,13 @@
     }
 
     @Override
-    public ImmutableMap<String, Set<MeterKey>> getBpMeterMappings() {
-        return ImmutableMap.copyOf(bpInfoToMeter);
+    public ImmutableMap<String, Collection<MeterKey>> getBpMeterMappings() {
+        return ImmutableMap.copyOf(bpInfoToMeter.asMap());
     }
 
     @Override
     public void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
-        bpInfoToMeter.compute(bandwidthProfile, (k, v) -> {
-            if (v == null) {
-                return Sets.newHashSet(MeterKey.key(deviceId, meterId));
-            } else {
-                v.add(MeterKey.key(deviceId, meterId));
-                return v;
-            }
-        });
+        bpInfoToMeter.put(bandwidthProfile, MeterKey.key(deviceId, meterId));
     }
 
     @Override
@@ -199,7 +198,8 @@
 
                     @Override
                     public void onError(MeterRequest op, MeterFailReason reason) {
-                        bpInfoToMeter.remove(MeterKey.key(deviceId, meterIdRef.get()));
+                        bpInfoToMeter.remove(bpInfo.id(),
+                                             MeterKey.key(deviceId, meterIdRef.get()));
                         meterFuture.complete(reason);
                     }
                 })
@@ -242,12 +242,16 @@
         public void event(MeterEvent meterEvent) {
             eventExecutor.execute(() -> {
                 Meter meter = meterEvent.subject();
+                if (meter == null) {
+                    log.error("Meter in event {} is null", meterEvent);
+                    return;
+                }
                 MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
                 if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
                     log.info("Zero Count Meter Event is received. Meter is {}", meter.id());
                     incrementMeterCount(key);
 
-                    if (meter != null && appId.equals(meter.appId()) && pendingRemoveMeters.get(key).get() == 3) {
+                    if (appId.equals(meter.appId()) && pendingRemoveMeters.get(key).get() == 3) {
                         log.info("Deleting unreferenced, no longer programmed Meter {}", meter.id());
                         deleteMeter(meter.deviceId(), meter.id());
                     }
@@ -256,7 +260,7 @@
                     log.info("Meter Removed Event is received for {}", meter.id());
                     programmedMeters.remove(key);
                     pendingRemoveMeters.remove(key);
-                    removeMeterFromBpMapping(meter);
+                    removeMeterFromBpMapping(key);
                 }
             });
         }
@@ -290,12 +294,11 @@
             }
         }
 
-        private void removeMeterFromBpMapping(Meter meter) {
-            MeterKey meterKey = MeterKey.key(meter.deviceId(), meter.id());
-            Iterator<Map.Entry<String, Set<MeterKey>>> iterator = bpInfoToMeter.entrySet().iterator();
+        private void removeMeterFromBpMapping(MeterKey meterKey) {
+            Iterator<Map.Entry<String, MeterKey>> iterator = bpInfoToMeter.entries().iterator();
             while (iterator.hasNext()) {
-                Map.Entry<String, Set<MeterKey>> entry = iterator.next();
-                if (entry.getValue().contains(meterKey)) {
+                Map.Entry<String, MeterKey> entry = iterator.next();
+                if (entry.getValue().equals(meterKey)) {
                     iterator.remove();
                     log.info("Deleted meter for MeterKey {} - Last prog meters {}", meterKey, programmedMeters);
                     break;