Multiple meter support added and meter action added for OF1.5
MeterFeaturesFlag added for OF1.5

Change-Id: I84d2785f37ea51b08244de9c54effe5224af9531
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
index 8bde2f6..c6a1c16 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
@@ -19,7 +19,10 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
 import org.onlab.packet.EthType;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
@@ -56,7 +59,7 @@
 
     private static final DefaultTrafficTreatment EMPTY
             = new DefaultTrafficTreatment(ImmutableList.of(Instructions.createNoAction()));
-    private final Instructions.MeterInstruction meter;
+    private final Set<Instructions.MeterInstruction> meter;
 
     /**
      * Creates a new traffic treatment from the specified list of instructions.
@@ -70,7 +73,7 @@
         this.hasClear = false;
         this.table = null;
         this.meta = null;
-        this.meter = null;
+        this.meter = ImmutableSet.of();
         this.statTrigger = null;
     }
 
@@ -87,7 +90,7 @@
                                     Instructions.TableTypeTransition table,
                                     boolean clear,
                                     Instructions.MetadataInstruction meta,
-                                    Instructions.MeterInstruction meter,
+                                    Set<Instructions.MeterInstruction> meters,
                                     Instructions.StatTriggerInstruction statTrigger
                                     ) {
         this.immediate = ImmutableList.copyOf(checkNotNull(immediate));
@@ -99,7 +102,7 @@
         this.table = table;
         this.meta = meta;
         this.hasClear = clear;
-        this.meter = meter;
+        this.meter = ImmutableSet.copyOf(meters);
         this.statTrigger = statTrigger;
     }
 
@@ -140,6 +143,14 @@
 
     @Override
     public Instructions.MeterInstruction metered() {
+        if (meter.isEmpty()) {
+            return null;
+        }
+        return meter.iterator().next();
+    }
+
+    @Override
+    public Set<Instructions.MeterInstruction> meters() {
         return meter;
     }
 
@@ -200,7 +211,7 @@
                 .add("immediate", immediate)
                 .add("deferred", deferred)
                 .add("transition", table == null ? "None" : table.toString())
-                .add("meter", meter == null ? "None" : meter.toString())
+                .add("meter", meter == null ? "None" : meter)
                 .add("cleared", hasClear)
                 .add("StatTrigger", statTrigger)
                 .add("metadata", meta)
@@ -219,7 +230,7 @@
 
         Instructions.MetadataInstruction meta;
 
-        Instructions.MeterInstruction meter;
+        Set<Instructions.MeterInstruction> meter = Sets.newHashSet();
 
         Instructions.StatTriggerInstruction statTrigger;
 
@@ -271,7 +282,7 @@
                     meta = (Instructions.MetadataInstruction) instruction;
                     break;
                 case METER:
-                    meter = (Instructions.MeterInstruction) instruction;
+                    meter.add((Instructions.MeterInstruction) instruction);
                     break;
                 case STAT_TRIGGER:
                     statTrigger = (Instructions.StatTriggerInstruction) instruction;
diff --git a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
index 057f0f8..f61b017 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
@@ -17,6 +17,7 @@
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import com.google.common.annotations.Beta;
 import org.onlab.packet.EthType;
@@ -90,11 +91,18 @@
     /**
      * Returns the meter instruction if there is one.
      *
-     * @return a meter instruction that may be null
+     * @return a meter instruction that may be a null.
      */
     Instructions.MeterInstruction metered();
 
     /**
+     * Returns the meter instructions if there is any.
+     *
+     * @return meter instructions that may be an empty set.
+     */
+    Set<Instructions.MeterInstruction> meters();
+
+    /**
      * Builder of traffic treatment entities.
      */
     interface Builder {
diff --git a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterFeatures.java b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterFeatures.java
index 1835872..bd5d998 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterFeatures.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterFeatures.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.meter;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.collect.Sets;
 import org.onosproject.net.DeviceId;
 
 import java.util.HashSet;
@@ -35,11 +36,12 @@
     private boolean stats;
     private short maxBands;
     private short maxColor;
+    private Set<MeterFeaturesFlag> features;
 
     private DefaultMeterFeatures(DeviceId did, long maxMeter,
                                  Set<Band.Type> bandTypes, Set<Meter.Unit> units,
                                  boolean burst, boolean stats,
-                                 short maxBands, short maxColor) {
+                                 short maxBands, short maxColor, Set<MeterFeaturesFlag> flag) {
         this.deviceId = did;
         this.maxMeter = maxMeter;
         this.bandTypes = bandTypes;
@@ -48,6 +50,7 @@
         this.units = units;
         this.maxBands = maxBands;
         this.maxColor = maxColor;
+        this.features = flag;
     }
 
     @Override
@@ -90,6 +93,11 @@
         return maxColor;
     }
 
+    @Override
+    public Set<MeterFeaturesFlag> features() {
+        return features;
+    }
+
     public static Builder builder() {
         return new Builder();
     }
@@ -125,6 +133,7 @@
         private Set<Meter.Unit> units1 = new HashSet<>();
         private boolean burst = false;
         private boolean stats = false;
+        private Set<MeterFeaturesFlag> features = Sets.newHashSet();
 
         @Override
         public MeterFeatures.Builder forDevice(DeviceId deviceId) {
@@ -175,9 +184,15 @@
         }
 
         @Override
+        public MeterFeatures.Builder withFeatures(Set<MeterFeaturesFlag> featureFlags) {
+            features = featureFlags;
+            return this;
+        }
+
+        @Override
         public MeterFeatures build() {
             checkNotNull(did, "Must specify a device");
-            return new DefaultMeterFeatures(did, mmeter, bandTypes, units1, burst, stats, mbands, mcolors);
+            return new DefaultMeterFeatures(did, mmeter, bandTypes, units1, burst, stats, mbands, mcolors, features);
         }
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterFeatures.java b/core/api/src/main/java/org/onosproject/net/meter/MeterFeatures.java
index 143e927..2749687 100644
--- a/core/api/src/main/java/org/onosproject/net/meter/MeterFeatures.java
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterFeatures.java
@@ -81,6 +81,14 @@
     short maxColor();
 
     /**
+     * Returns features flags that supported for meter actions by device.
+     *
+     * @return meter features flags
+     * otherwise empty set.
+     */
+    Set<MeterFeaturesFlag> features();
+
+    /**
      * A meter features builder.
      */
     interface Builder {
@@ -149,6 +157,14 @@
         Builder hasStats(boolean hasStats);
 
         /**
+         * Assigns the features for this meter features for OF1.5.
+         *
+         * @param featureFlags if meter features flags are supported
+         * @return this builder
+         */
+        Builder withFeatures(Set<MeterFeaturesFlag> featureFlags);
+
+        /**
          * Builds the Meter Features based on the specified parameters.
          *
          * @return the meter features
diff --git a/core/api/src/main/java/org/onosproject/net/meter/MeterFeaturesFlag.java b/core/api/src/main/java/org/onosproject/net/meter/MeterFeaturesFlag.java
new file mode 100644
index 0000000..36356ef
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/meter/MeterFeaturesFlag.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017-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
+ * limitations under the License.
+ */
+package org.onosproject.net.meter;
+
+public enum MeterFeaturesFlag {
+    /**
+     * Support meter action in action set.
+     */
+    ACTION_SET,
+    /**
+     * Support any position in action list.
+     */
+    ANY_POSITION,
+    /**
+     * Support multiple actions in action list.
+     */
+    MULTI_LIST
+}
diff --git a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
index a05745c..90cc697 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
@@ -16,6 +16,7 @@
 package org.onosproject.net.intent;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.collect.Sets;
 import org.onlab.graph.Weight;
 import org.onosproject.core.GroupId;
 import org.onosproject.net.DefaultPath;
@@ -121,6 +122,11 @@
         public Instructions.MeterInstruction metered() {
             return null;
         }
+
+        @Override
+        public Set<Instructions.MeterInstruction> meters() {
+            return Sets.newHashSet();
+        }
     }
 
     /**
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/TrafficTreatmentCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/TrafficTreatmentCodec.java
index 0003318..4a2bc92 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/TrafficTreatmentCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/TrafficTreatmentCodec.java
@@ -23,6 +23,7 @@
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
 
 import java.util.stream.IntStream;
 
@@ -51,7 +52,9 @@
         }
 
         if (treatment.metered() != null) {
-            jsonInstructions.add(instructionCodec.encode(treatment.metered(), context));
+            for (Instructions.MeterInstruction instruction : treatment.meters()) {
+                jsonInstructions.add(instructionCodec.encode(instruction, context));
+            }
         }
         if (treatment.tableTransition() != null) {
             jsonInstructions.add(instructionCodec.encode(treatment.tableTransition(), context));
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/TrafficTreatmentCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/TrafficTreatmentCodecTest.java
index ed87ce0..b014bcf 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/TrafficTreatmentCodecTest.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/TrafficTreatmentCodecTest.java
@@ -35,6 +35,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
+import java.util.Optional;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
@@ -163,9 +164,11 @@
             // check metered
             JsonNode meterNode = getInstNode(jsonInstructions, "METER");
             String jsonMeterId = meterNode != null ? meterNode.get("meterId").asText() : null;
-            if (trafficTreatment.metered() != null) {
-                String meterId = trafficTreatment.metered().meterId().toString();
-                if (!StringUtils.equals(jsonMeterId, meterId)) {
+            if (trafficTreatment.metered() != null && !trafficTreatment.meters().isEmpty()) {
+                Optional<Instructions.MeterInstruction> optional = trafficTreatment.meters().stream().filter(
+                        meterInstruction -> StringUtils.equals(jsonMeterId, meterInstruction.meterId().toString()))
+                        .findAny();
+                if (!optional.isPresent()) {
                     description.appendText("meter id was " + jsonMeterId);
                     return false;
                 }
diff --git a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
index 7785a38..3697641 100644
--- a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
@@ -673,6 +673,11 @@
             return null;
         }
 
+        @Override
+        public Set<Instructions.MeterInstruction> meters() {
+            return Sets.newHashSet();
+        }
+
     }
 
     public class TestApplicationId extends DefaultApplicationId {