Implement flow objective queue command

- View flow objecitve queus and caches
- Refactor flow objecitve service and remove deprecated method

Change-Id: I6bbd209a351e0d87c5ee518038b33f72dcb3058a
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjQueueKey.java b/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjQueueKey.java
new file mode 100644
index 0000000..8ec1bce3
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjQueueKey.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018-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.flowobjective;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.criteria.Criterion;
+
+import java.util.Objects;
+
+/**
+ * Filtering objective queue key.
+ */
+public class FilteringObjQueueKey {
+    private DeviceId deviceId;
+    private int priority;
+    private Criterion key;
+
+    public FilteringObjQueueKey(DeviceId deviceId, int priority, Criterion key) {
+        this.deviceId = deviceId;
+        this.priority = priority;
+        this.key = key;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(deviceId, priority, key);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof FilteringObjQueueKey)) {
+            return false;
+        }
+        FilteringObjQueueKey that = (FilteringObjQueueKey) other;
+        return Objects.equals(this.deviceId, that.deviceId) &&
+                Objects.equals(this.priority, that.priority) &&
+                Objects.equals(this.key, that.key);
+    }
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java b/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java
index cb7b1e0..103691c 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java
@@ -18,7 +18,12 @@
 import com.google.common.annotations.Beta;
 
 import java.util.List;
+import java.util.Map;
 
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Maps;
+import org.apache.commons.lang.NotImplementedException;
 import org.onosproject.net.DeviceId;
 
 /**
@@ -111,14 +116,48 @@
     List<String> getPendingFlowObjectives();
 
     /**
-     * Retrieve all nextObjectives that are waiting to hear back from device
-     * drivers, and the forwarding-objectives or next-objectives that are waiting
-     * on the successful completion of the original next-objectives.
+     * Returns all filtering objective that are waiting for the completion of previous objective
+     * with the same FilteringObjQueueKey.
      *
-     * @return a list of strings preformatted by the device-drivers to provide
-     *         information on next-id to group-id mapping.
+     * @return Filtering objective queue as map
      */
-    @Deprecated
-    List<String> getPendingNexts();
+    default ListMultimap<FilteringObjQueueKey, Objective> getFilteringObjQueue() {
+        return ArrayListMultimap.create();
+    }
 
+    /**
+     * Returns all forwarding objective that are waiting for the completion of previous objective
+     * with the same ForwardingObjQueueKey.
+     *
+     * @return Forwarding objective queue as map
+     */
+    default ListMultimap<ForwardingObjQueueKey, Objective> getForwardingObjQueue() {
+        return ArrayListMultimap.create();
+    }
+
+    /**
+     * Returns all next objective that are waiting for the completion of previous objective
+     * with the same NextObjQueueKey.
+     *
+     * @return Next objective queue as map
+     */
+    default ListMultimap<NextObjQueueKey, Objective> getNextObjQueue() {
+        return ArrayListMultimap.create();
+    }
+
+    default Map<FilteringObjQueueKey, Objective> getFilteringObjQueueHead() {
+        return Maps.newHashMap();
+    }
+
+    default Map<ForwardingObjQueueKey, Objective> getForwardingObjQueueHead() {
+        return Maps.newHashMap();
+    }
+
+    default Map<NextObjQueueKey, Objective> getNextObjQueueHead() {
+        return Maps.newHashMap();
+    }
+
+    default void clearQueue() {
+        throw new NotImplementedException("clearQueue is not implemented");
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjQueueKey.java b/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjQueueKey.java
new file mode 100644
index 0000000..d963d8a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjQueueKey.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018-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.flowobjective;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.TrafficSelector;
+
+import java.util.Objects;
+
+/**
+ * Forwarding objective queue key.
+ */
+public class ForwardingObjQueueKey {
+    private DeviceId deviceId;
+    private int priority;
+    private TrafficSelector selector;
+
+    public ForwardingObjQueueKey(DeviceId deviceId, int priority, TrafficSelector selector) {
+        this.deviceId = deviceId;
+        this.priority = priority;
+        this.selector = selector;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(deviceId, priority, selector);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof ForwardingObjQueueKey)) {
+            return false;
+        }
+        ForwardingObjQueueKey that = (ForwardingObjQueueKey) other;
+        return Objects.equals(this.deviceId, that.deviceId) &&
+                Objects.equals(this.priority, that.priority) &&
+                Objects.equals(this.selector, that.selector);
+    }
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjQueueKey.java b/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjQueueKey.java
new file mode 100644
index 0000000..a2d9c64
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjQueueKey.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018-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.flowobjective;
+
+import org.onosproject.net.DeviceId;
+
+import java.util.Objects;
+
+/**
+ * Next objective queue key.
+ */
+public class NextObjQueueKey {
+    private DeviceId deviceId;
+    private int id;
+
+    public NextObjQueueKey(DeviceId deviceId, int id) {
+        this.deviceId = deviceId;
+        this.id = id;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(deviceId, id);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof NextObjQueueKey)) {
+            return false;
+        }
+        NextObjQueueKey that = (NextObjQueueKey) other;
+        return Objects.equals(this.deviceId, that.deviceId) &&
+                Objects.equals(this.id, that.id);
+    }
+}
\ No newline at end of file
diff --git a/core/api/src/test/java/org/onosproject/net/flowobjective/FlowObjectiveServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/flowobjective/FlowObjectiveServiceAdapter.java
index 0b37ccd..360c1f2 100644
--- a/core/api/src/test/java/org/onosproject/net/flowobjective/FlowObjectiveServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/flowobjective/FlowObjectiveServiceAdapter.java
@@ -65,9 +65,4 @@
     public List<String> getPendingFlowObjectives() {
         return ImmutableList.of();
     }
-
-    @Override
-    public List<String> getPendingNexts() {
-        return ImmutableList.of();
-    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
index 20e55a5..1e3b2a8 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
@@ -684,9 +684,4 @@
 
         return pendingFlowObjectives;
     }
-
-    @Override
-    public List<String> getPendingNexts() {
-        return getPendingFlowObjectives();
-    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/InOrderFlowObjectiveManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/InOrderFlowObjectiveManager.java
index f32bb6c..5eb3ac0 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/InOrderFlowObjectiveManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/InOrderFlowObjectiveManager.java
@@ -29,11 +29,12 @@
 import org.onlab.util.Tools;
 import org.onlab.util.Tools.LogLevel;
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flowobjective.FilteringObjQueueKey;
 import org.onosproject.net.flowobjective.FilteringObjective;
 import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
+import org.onosproject.net.flowobjective.ForwardingObjQueueKey;
 import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjQueueKey;
 import org.onosproject.net.flowobjective.NextObjective;
 import org.onosproject.net.flowobjective.Objective;
 import org.onosproject.net.flowobjective.ObjectiveContext;
@@ -43,7 +44,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.util.List;
-import java.util.Objects;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ScheduledExecutorService;
@@ -60,14 +61,14 @@
     // TODO Make queue timeout configurable
     static final int OBJ_TIMEOUT_MS = 5000;
 
-    private Cache<FiltObjQueueKey, Objective> filtObjQueueHead;
-    private Cache<FwdObjQueueKey, Objective> fwdObjQueueHead;
+    private Cache<FilteringObjQueueKey, Objective> filtObjQueueHead;
+    private Cache<ForwardingObjQueueKey, Objective> fwdObjQueueHead;
     private Cache<NextObjQueueKey, Objective> nextObjQueueHead;
     private ScheduledExecutorService cacheCleaner;
 
-    private ListMultimap<FiltObjQueueKey, Objective> filtObjQueue =
+    private ListMultimap<FilteringObjQueueKey, Objective> filtObjQueue =
             Multimaps.synchronizedListMultimap(ArrayListMultimap.create());
-    private ListMultimap<FwdObjQueueKey, Objective> fwdObjQueue =
+    private ListMultimap<ForwardingObjQueueKey, Objective> fwdObjQueue =
             Multimaps.synchronizedListMultimap(ArrayListMultimap.create());
     private ListMultimap<NextObjQueueKey, Objective> nextObjQueue =
             Multimaps.synchronizedListMultimap(ArrayListMultimap.create());
@@ -81,7 +82,7 @@
         // TODO Clean up duplicated code
         filtObjQueueHead = CacheBuilder.newBuilder()
                 .expireAfterWrite(OBJ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
-                .removalListener((RemovalNotification<FiltObjQueueKey, Objective> notification) -> {
+                .removalListener((RemovalNotification<FilteringObjQueueKey, Objective> notification) -> {
                     Objective obj = notification.getValue();
                     switch (notification.getCause()) {
                         case EXPIRED:
@@ -97,7 +98,7 @@
                 }).build();
         fwdObjQueueHead = CacheBuilder.newBuilder()
                 .expireAfterWrite(OBJ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
-                .removalListener((RemovalNotification<FwdObjQueueKey, Objective> notification) -> {
+                .removalListener((RemovalNotification<ForwardingObjQueueKey, Objective> notification) -> {
                     Objective obj = notification.getValue();
                     switch (notification.getCause()) {
                         case EXPIRED:
@@ -144,9 +145,7 @@
     @Deactivate
     protected void deactivate() {
         cacheCleaner.shutdown();
-        filtObjQueueHead.invalidateAll();
-        fwdObjQueueHead.invalidateAll();
-        nextObjQueueHead.invalidateAll();
+        clearQueue();
 
         super.deactivate();
     }
@@ -221,6 +220,51 @@
         process(deviceId, nextObjective);
     }
 
+    @Override
+    public ListMultimap<FilteringObjQueueKey, Objective> getFilteringObjQueue() {
+        return filtObjQueue;
+    }
+
+    @Override
+    public ListMultimap<ForwardingObjQueueKey, Objective> getForwardingObjQueue() {
+        return fwdObjQueue;
+    }
+
+    @Override
+    public ListMultimap<NextObjQueueKey, Objective> getNextObjQueue() {
+        return nextObjQueue;
+    }
+
+    @Override
+    public Map<FilteringObjQueueKey, Objective> getFilteringObjQueueHead() {
+        return filtObjQueueHead.asMap();
+    }
+
+    @Override
+    public Map<ForwardingObjQueueKey, Objective> getForwardingObjQueueHead() {
+        return fwdObjQueueHead.asMap();
+    }
+
+    @Override
+    public Map<NextObjQueueKey, Objective> getNextObjQueueHead() {
+        return nextObjQueueHead.asMap();
+    }
+
+    @Override
+    public void clearQueue() {
+        filtObjQueueHead.invalidateAll();
+        fwdObjQueueHead.invalidateAll();
+        nextObjQueueHead.invalidateAll();
+
+        filtObjQueueHead.cleanUp();
+        fwdObjQueueHead.cleanUp();
+        nextObjQueueHead.cleanUp();
+
+        filtObjQueue.clear();
+        fwdObjQueue.clear();
+        nextObjQueue.clear();
+    }
+
     /**
      * Enqueue flow objective. Execute the flow objective if there is no pending objective ahead.
      *
@@ -235,11 +279,12 @@
         Tools.log(log, logLevel, "Enqueue {}", obj);
 
         if (obj instanceof FilteringObjective) {
-            FiltObjQueueKey k = new FiltObjQueueKey(deviceId, priority, ((FilteringObjective) obj).key());
+            FilteringObjQueueKey k = new FilteringObjQueueKey(deviceId, priority, ((FilteringObjective) obj).key());
             filtObjQueue.put(k, obj);
             queueSize = filtObjQueue.get(k).size();
         } else if (obj instanceof ForwardingObjective) {
-            FwdObjQueueKey k = new FwdObjQueueKey(deviceId, priority, ((ForwardingObjective) obj).selector());
+            ForwardingObjQueueKey k =
+                    new ForwardingObjQueueKey(deviceId, priority, ((ForwardingObjective) obj).selector());
             fwdObjQueue.put(k, obj);
             queueSize = fwdObjQueue.get(k).size();
         } else if (obj instanceof NextObjective) {
@@ -272,12 +317,13 @@
         Tools.log(log, logLevel, "Dequeue {}", obj);
 
         if (obj instanceof FilteringObjective) {
-            FiltObjQueueKey k = new FiltObjQueueKey(deviceId, priority, ((FilteringObjective) obj).key());
+            FilteringObjQueueKey k = new FilteringObjQueueKey(deviceId, priority, ((FilteringObjective) obj).key());
             filtObjQueueHead.invalidate(k);
             filtObjQueue.remove(k, obj);
             remaining = filtObjQueue.get(k);
         } else if (obj instanceof ForwardingObjective) {
-            FwdObjQueueKey k = new FwdObjQueueKey(deviceId, priority, ((ForwardingObjective) obj).selector());
+            ForwardingObjQueueKey k =
+                    new ForwardingObjQueueKey(deviceId, priority, ((ForwardingObjective) obj).selector());
             fwdObjQueueHead.invalidate(k);
             fwdObjQueue.remove(k, obj);
             remaining = fwdObjQueue.get(k);
@@ -311,11 +357,12 @@
 
         int priority = obj.priority();
         if (obj instanceof FilteringObjective) {
-            FiltObjQueueKey k = new FiltObjQueueKey(deviceId, priority, ((FilteringObjective) obj).key());
+            FilteringObjQueueKey k = new FilteringObjQueueKey(deviceId, priority, ((FilteringObjective) obj).key());
             filtObjQueueHead.put(k, obj);
             super.filter(deviceId, (FilteringObjective) obj);
         } else if (obj instanceof ForwardingObjective) {
-            FwdObjQueueKey k = new FwdObjQueueKey(deviceId, priority, ((ForwardingObjective) obj).selector());
+            ForwardingObjQueueKey k =
+                    new ForwardingObjQueueKey(deviceId, priority, ((ForwardingObjective) obj).selector());
             fwdObjQueueHead.put(k, obj);
             super.forward(deviceId, (ForwardingObjective) obj);
         } else if (obj instanceof NextObjective) {
@@ -368,94 +415,4 @@
             }
         }
     }
-
-    private static class FiltObjQueueKey {
-        private DeviceId deviceId;
-        private int priority;
-        private Criterion key;
-
-        FiltObjQueueKey(DeviceId deviceId, int priority, Criterion key) {
-            this.deviceId = deviceId;
-            this.priority = priority;
-            this.key = key;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(deviceId, priority, key);
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (this == other) {
-                return true;
-            }
-            if (!(other instanceof FiltObjQueueKey)) {
-                return false;
-            }
-            FiltObjQueueKey that = (FiltObjQueueKey) other;
-            return Objects.equals(this.deviceId, that.deviceId) &&
-                    Objects.equals(this.priority, that.priority) &&
-                    Objects.equals(this.key, that.key);
-        }
-    }
-
-    private static class FwdObjQueueKey {
-        private DeviceId deviceId;
-        private int priority;
-        private TrafficSelector selector;
-
-        FwdObjQueueKey(DeviceId deviceId, int priority, TrafficSelector selector) {
-            this.deviceId = deviceId;
-            this.priority = priority;
-            this.selector = selector;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(deviceId, priority, selector);
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (this == other) {
-                return true;
-            }
-            if (!(other instanceof FwdObjQueueKey)) {
-                return false;
-            }
-            FwdObjQueueKey that = (FwdObjQueueKey) other;
-            return Objects.equals(this.deviceId, that.deviceId) &&
-                    Objects.equals(this.priority, that.priority) &&
-                    Objects.equals(this.selector, that.selector);
-        }
-    }
-
-    private static class NextObjQueueKey {
-        private DeviceId deviceId;
-        private int id;
-
-        NextObjQueueKey(DeviceId deviceId, int id) {
-            this.deviceId = deviceId;
-            this.id = id;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(deviceId, id);
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (this == other) {
-                return true;
-            }
-            if (!(other instanceof NextObjQueueKey)) {
-                return false;
-            }
-            NextObjQueueKey that = (NextObjQueueKey) other;
-            return Objects.equals(this.deviceId, that.deviceId) &&
-                    Objects.equals(this.id, that.id);
-        }
-    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java
index a765648..21f8ddc 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java
@@ -436,9 +436,4 @@
         // TODO Implementation deferred as this is an experimental component.
         return ImmutableList.of();
     }
-
-    @Override
-    public List<String> getPendingNexts() {
-        return ImmutableList.of();
-    }
 }