ONOS-5691 ONOS-5742 Fixing intent framework difficulties

- Refactoring AbstractAccumulator to use less blocking synchronization
- Fixing bug in AbstractAccumulator that could leave some items
  without firing
- Updated IntentStore for resubmitting pending operations

Change-Id: Iaf240da65e11ceb7d7d745cf4e25bfb8c26ed1eb
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java
index 56ee709..bb180c8 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java
@@ -210,6 +210,13 @@
     private void cleanup() {
         int corruptCount = 0, failedCount = 0, stuckCount = 0, pendingCount = 0;
 
+        // Check the pending map first, because the check of the current map
+        // will add items to the pending map.
+        for (IntentData intentData : store.getPendingData(true, periodMs)) {
+            resubmitPendingRequest(intentData);
+            pendingCount++;
+        }
+
         for (IntentData intentData : store.getIntentData(true, periodMs)) {
             switch (intentData.state()) {
                 case FAILED:
@@ -231,11 +238,6 @@
             }
         }
 
-        for (IntentData intentData : store.getPendingData(true, periodMs)) {
-            resubmitPendingRequest(intentData);
-            pendingCount++;
-        }
-
         if (corruptCount + failedCount + stuckCount + pendingCount > 0) {
             log.debug("Intent cleanup ran and resubmitted {} corrupt, {} failed, {} stuck, and {} pending intents",
                     corruptCount, failedCount, stuckCount, pendingCount);
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentInstaller.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentInstaller.java
index 8ea910b..631151b 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentInstaller.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentInstaller.java
@@ -53,7 +53,7 @@
  */
 class IntentInstaller {
 
-    private static final Logger log = getLogger(IntentManager.class);
+    private static final Logger log = getLogger(IntentInstaller.class);
 
     private IntentStore store;
     private ObjectiveTrackerService trackerService;
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
index 12c636c..5524d63 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java
@@ -49,6 +49,7 @@
 import org.onosproject.net.intent.impl.compiler.PointToPointIntentCompiler;
 import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
 import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
+import org.onosproject.net.intent.impl.phase.Skipped;
 import org.osgi.service.component.ComponentContext;
 import org.onosproject.net.resource.ResourceService;
 import org.slf4j.Logger;
@@ -428,7 +429,8 @@
                                     //FIXME
                                     log.warn("Future failed: {}", e);
                                     return null;
-                                })).collect(Collectors.toList());
+                                }))
+                        .collect(Collectors.toList());
 
                 // write multiple data to store in order
                 store.batchWrite(Tools.allOf(futures).join().stream()
@@ -449,6 +451,16 @@
     }
 
     private IntentProcessPhase createInitialPhase(IntentData data) {
+        IntentData pending = store.getPendingData(data.key());
+        if (pending == null || pending.version().isNewerThan(data.version())) {
+            /*
+                If the pending map is null, then this intent was compiled by a
+                previous batch iteration, so we can skip it.
+                If the pending map has a newer request, it will get compiled as
+                part of the next batch, so we can skip it.
+             */
+            return Skipped.getPhase();
+        }
         IntentData current = store.getIntentData(data.key());
         return newInitialPhase(processor, data, current);
     }
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Skipped.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Skipped.java
new file mode 100644
index 0000000..a8afde6
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Skipped.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.intent.impl.phase;
+
+import org.onosproject.net.intent.IntentData;
+
+/**
+ * Represents a phase where an intent is not compiled.
+ * <p>
+ * This should be used if a new version of the intent will immediately override
+ * this one.
+ * </p>
+ */
+public final class Skipped extends FinalIntentProcessPhase {
+
+    private static final Skipped SINGLETON = new Skipped();
+
+    /**
+     * Returns a shared skipped phase.
+     *
+     * @return skipped phase
+     */
+    public static Skipped getPhase() {
+        return SINGLETON;
+    }
+
+    // Prevent object construction; use getPhase()
+    private Skipped() {
+    }
+
+    @Override
+    public IntentData data() {
+        return null;
+    }
+}