[SDFAB-355] Revisit MeterService and north abstractions

Change-Id: I685cb90d53f8aa61017ecda9fa7ff842e58e2940
diff --git a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java
index 681846f..f3e29fe 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java
@@ -23,6 +23,7 @@
 import org.onosproject.net.DeviceId;
 
 import java.util.Collection;
+import java.util.Optional;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 import static com.google.common.base.Preconditions.checkArgument;
@@ -36,7 +37,7 @@
 
 
     private final MeterCellId cellId;
-    private final ApplicationId appId;
+    private final Optional<ApplicationId> appId;
     private final Unit unit;
     private final boolean burst;
     private final Collection<Band> bands;
@@ -48,8 +49,9 @@
     private long packets;
     private long bytes;
 
-    private DefaultMeter(DeviceId deviceId, MeterCellId cellId, ApplicationId appId,
-                         Unit unit, boolean burst, Collection<Band> bands,
+    private DefaultMeter(DeviceId deviceId, MeterCellId cellId,
+                         Optional<ApplicationId> appId, Unit unit,
+                         boolean burst, Collection<Band> bands,
                          Annotations... annotations) {
         super(annotations);
         this.deviceId = deviceId;
@@ -81,7 +83,8 @@
 
     @Override
     public ApplicationId appId() {
-        return appId;
+        return appId.orElse(null);
+        // TODO: Deprecate this API because AppId becomes optional in Meter
     }
 
     @Override
@@ -158,7 +161,7 @@
         return toStringHelper(this)
                 .add("device", deviceId)
                 .add("cellId", cellId)
-                .add("appId", appId.name())
+                .add("appId", appId.orElse(null))
                 .add("unit", unit)
                 .add("isBurst", burst)
                 .add("state", state)
@@ -190,7 +193,7 @@
     public static final class Builder implements Meter.Builder {
 
         private MeterCellId cellId;
-        private ApplicationId appId;
+        private Optional<ApplicationId> appId = Optional.empty();
         private Unit unit = Unit.KB_PER_SEC;
         private boolean burst = false;
         private Collection<Band> bands;
@@ -217,7 +220,7 @@
 
         @Override
         public Meter.Builder fromApp(ApplicationId appId) {
-            this.appId = appId;
+            this.appId = Optional.ofNullable(appId);
             return this;
         }
 
@@ -250,7 +253,6 @@
             checkNotNull(deviceId, "Must specify a device");
             checkNotNull(bands, "Must have bands.");
             checkArgument(!bands.isEmpty(), "Must have at least one band.");
-            checkNotNull(appId, "Must have an application id");
             checkArgument(cellId != null, "Must specify a cell id.");
             return new DefaultMeter(deviceId, cellId, appId, unit, burst, bands,
                                     annotations);
diff --git a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java
index e6e2d1b..0dbd4f7 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java
@@ -42,11 +42,14 @@
     private final DeviceId deviceId;
     private final Optional<MeterContext> context;
     private final Type op;
+    private final MeterScope scope;
+    private final Optional<Long> index;
 
     private DefaultMeterRequest(DeviceId deviceId, ApplicationId appId,
                                 Meter.Unit unit, boolean burst,
                                 Collection<Band> bands, MeterContext context,
-                                Type op, Annotations... annotations) {
+                                Type op, MeterScope scope, Optional<Long> index,
+                                Annotations... annotations) {
         super(annotations);
         this.deviceId = deviceId;
         this.appId = appId;
@@ -55,6 +58,8 @@
         this.bands = bands;
         this.context = Optional.ofNullable(context);
         this.op = op;
+        this.scope = scope;
+        this.index = index;
     }
 
     @Override
@@ -88,7 +93,15 @@
         return context;
     }
 
+    @Override
+    public MeterScope scope() {
+        return scope;
+    }
 
+    @Override
+    public Optional<Long> index() {
+        return index;
+    }
 
     public static Builder builder() {
         return new Builder();
@@ -102,6 +115,8 @@
                 .add("unit", unit)
                 .add("isBurst", burst)
                 .add("bands", bands)
+                .add("scope", scope)
+                .add("desired index", index.orElse(null))
                 .add("annotations", annotations())
                 .toString();
     }
@@ -114,9 +129,9 @@
         private Collection<Band> bands;
         private DeviceId deviceId;
         private MeterContext context;
-        private Optional<MeterId> desiredId = Optional.empty();
         private Annotations annotations;
-
+        private MeterScope scope = MeterScope.globalScope();
+        private Optional<Long> desiredIndex = Optional.empty();
 
         @Override
         public MeterRequest.Builder forDevice(DeviceId deviceId) {
@@ -131,19 +146,19 @@
         }
 
         @Override
-        public MeterRequest.Builder  withUnit(Meter.Unit unit) {
+        public MeterRequest.Builder withUnit(Meter.Unit unit) {
             this.unit = unit;
             return this;
         }
 
         @Override
-        public MeterRequest.Builder  burst() {
+        public MeterRequest.Builder burst() {
             this.burst = true;
             return this;
         }
 
         @Override
-        public MeterRequest.Builder  withBands(Collection<Band> bands) {
+        public MeterRequest.Builder withBands(Collection<Band> bands) {
             this.bands = ImmutableSet.copyOf(bands);
             return this;
         }
@@ -161,17 +176,29 @@
         }
 
         @Override
+        public MeterRequest.Builder withScope(MeterScope scope) {
+            this.scope = scope;
+            return this;
+        }
+
+        @Override
+        public MeterRequest.Builder withIndex(Long index) {
+            this.desiredIndex = Optional.ofNullable(index);
+            return this;
+        }
+
+        @Override
         public MeterRequest add() {
             validate();
-            return new DefaultMeterRequest(deviceId, appId, unit, burst, bands,
-                                           context, Type.ADD, annotations);
+            return new DefaultMeterRequest(deviceId, appId, unit, burst, bands, context,
+                                           Type.ADD, scope, desiredIndex, annotations);
         }
 
         @Override
         public MeterRequest remove() {
             validate();
-            return new DefaultMeterRequest(deviceId, appId, unit, burst, bands,
-                                           context, Type.REMOVE, annotations);
+            return new DefaultMeterRequest(deviceId, appId, unit, burst, bands, context,
+                                           Type.REMOVE, scope, desiredIndex, annotations);
         }
 
         private void validate() {
@@ -179,6 +206,9 @@
             checkNotNull(bands, "Must have bands.");
             checkArgument(!bands.isEmpty(), "Must have at least one band.");
             checkNotNull(appId, "Must have an application id");
+            if (desiredIndex.isPresent()) {
+                checkArgument(desiredIndex.get() >= 0, "Desired index cannot be negative");
+            }
         }
 
 
diff --git a/core/api/src/main/java/org/onosproject/net/meter/Meter.java b/core/api/src/main/java/org/onosproject/net/meter/Meter.java
index 63b6db3..64379d3 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/Meter.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/Meter.java
@@ -37,7 +37,12 @@
         /**
          * Kilo bits per second.
          */
-        KB_PER_SEC
+        KB_PER_SEC,
+
+        /**
+         * Bytes per second.
+         */
+        BYTES_PER_SEC
     }
 
     /**
@@ -65,10 +70,13 @@
 
     /**
      * The id of the application which created this meter.
+     * Could be null if the meter is read from the controller southbound.
      *
      * @return an application id
      */
     ApplicationId appId();
+    // TODO: Deprecate this and create a new method returns an Optional ApplicationId
+    // TODO: Or introduce MeterEntry on south and keep this method
 
     /**
      * The unit used within this meter.
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java b/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java
index a2be1ce..e156fd4 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java
@@ -77,6 +77,20 @@
     Optional<MeterContext> context();
 
     /**
+     * Returns the scope of this meter request.
+     *
+     * @return a meter scope
+     */
+    MeterScope scope();
+
+    /**
+     * Returns the desired meter index of this meter request.
+     *
+     * @return an optional long index
+     */
+    Optional<Long> index();
+
+    /**
      * A meter builder.
      */
     interface Builder {
@@ -139,6 +153,22 @@
         Builder withAnnotations(Annotations annotations);
 
         /**
+         * Sets the scope.
+         *
+         * @param scope a meter scope
+         * @return this
+         */
+        Builder withScope(MeterScope scope);
+
+        /**
+         * Sets the index.
+         *
+         * @param index an optional index
+         * @return this
+         */
+        Builder withIndex(Long index);
+
+        /**
          * Requests the addition of a meter.
          *
          * @return a meter request
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterService.java b/core/api/src/main/java/org/onosproject/net/meter/MeterService.java
index 6339101..5b3ca3b 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/MeterService.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterService.java
@@ -42,19 +42,40 @@
      *
      * @param meter a meter to remove
      * @param meterId the meter id of the meter to remove.
+     * @deprecated in onos-2.5, replace MeterId with MeterCellId
      */
+    @Deprecated
     void withdraw(MeterRequest meter, MeterId meterId);
 
     /**
+     * Remove a meter from the system and the dataplane.
+     *
+     * @param meter a meter to remove
+     * @param meterCellId the meter cell id of the meter to remove.
+     */
+    void withdraw(MeterRequest meter, MeterCellId meterCellId);
+
+    /**
      * Fetch the meter by the meter id.
      *
      * @param deviceId a device id
      * @param id a meter id
      * @return a meter
+     * @deprecated in onos-2.5, Replace MeterId with MeterCellId
      */
+    @Deprecated
     Meter getMeter(DeviceId deviceId, MeterId id);
 
     /**
+     * Fetch the meter by the meter id.
+     *
+     * @param deviceId a device id
+     * @param id a meter cell id
+     * @return a meter
+     */
+    Meter getMeter(DeviceId deviceId, MeterCellId id);
+
+    /**
      * Fetches all the meters.
      *
      * @return a collection of meters
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterState.java b/core/api/src/main/java/org/onosproject/net/meter/MeterState.java
index 78fdd90..c098d91 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/MeterState.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterState.java
@@ -35,9 +35,4 @@
      */
     PENDING_REMOVE,
 
-    /**
-     * The meter has been removed.
-     */
-    REMOVED,
-
 }