Distributed IntentStore family: relax state transition check

- allow INSTALLED -> INSTALLED
- allow WITHDRWAN -> SUBMITTED

Change-Id: I7ba9c7c6e29b39ce005fb15bfd68feb1751cb0af
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/DistributedIntentStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/DistributedIntentStore.java
index 62bb77c..d777a45 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/DistributedIntentStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/DistributedIntentStore.java
@@ -56,7 +56,7 @@
         implements IntentStore {
 
     /** Valid parking state, which can transition to INSTALLED. */
-    private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(SUBMITTED, FAILED);
+    private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(SUBMITTED, INSTALLED, FAILED);
 
     /** Valid parking state, which can transition to WITHDRAWN. */
     private static final Set<IntentState> PRE_WITHDRAWN = EnumSet.of(INSTALLED, FAILED);
@@ -177,11 +177,16 @@
         switch (state) {
         case SUBMITTED:
             prevParking = states.get(id);
-            verify(prevParking == null,
-                   "Illegal state transition attempted from %s to SUBMITTED",
-                   prevParking);
-            updated = states.putIfAbsent(id, SUBMITTED);
-            verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
+            if (prevParking == null) {
+                updated = states.putIfAbsent(id, SUBMITTED);
+                verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
+            } else {
+                verify(prevParking == WITHDRAWN,
+                        "Illegal state transition attempted from %s to SUBMITTED",
+                        prevParking);
+                updated = states.replace(id, prevParking, SUBMITTED);
+                verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
+            }
             type = IntentEvent.Type.SUBMITTED;
             break;
 
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/HazelcastIntentStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/HazelcastIntentStore.java
index 2f5d2e4..fecaf6a 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/HazelcastIntentStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/HazelcastIntentStore.java
@@ -56,7 +56,7 @@
         implements IntentStore {
 
     /** Valid parking state, which can transition to INSTALLED. */
-    private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(SUBMITTED, FAILED);
+    private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(SUBMITTED, INSTALLED, FAILED);
 
     /** Valid parking state, which can transition to WITHDRAWN. */
     private static final Set<IntentState> PRE_WITHDRAWN = EnumSet.of(INSTALLED, FAILED);
@@ -177,10 +177,17 @@
         // parking state transition
         switch (state) {
         case SUBMITTED:
-            prevParking = states.putIfAbsent(id, SUBMITTED);
-            verify(prevParking == null,
-                   "Illegal state transition attempted from %s to SUBMITTED",
-                   prevParking);
+            prevParking = states.get(id);
+            if (prevParking == null) {
+                IntentState existing = states.putIfAbsent(id, SUBMITTED);
+                verify(existing != null, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
+            } else {
+                verify(prevParking == WITHDRAWN,
+                        "Illegal state transition attempted from %s to SUBMITTED",
+                        prevParking);
+                boolean updated = states.replace(id, prevParking, SUBMITTED);
+                verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
+            }
             type = IntentEvent.Type.SUBMITTED;
             break;
         case INSTALLED: