Initial implementation of CORRUPT state (ONOS-1060)

- Added CORRUPT state to state machine and event type
- Simplified phases using new request field
- Improved null-safety by using Optionals

Change-Id: I1d576b719765b5664aef73477ee04593e8acc4fd
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/CompileFailed.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/CompileFailed.java
deleted file mode 100644
index 234e222..0000000
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/CompileFailed.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2015 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 the compile has failed.
- */
-public class CompileFailed extends AbstractFailed {
-
-    /**
-     * Create an instance with the specified data.
-     *
-     * @param intentData intentData
-     */
-    public CompileFailed(IntentData intentData) {
-        super(intentData);
-    }
-}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java
index fe2986f..5078b5d 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java
@@ -15,46 +15,59 @@
  */
 package org.onosproject.net.intent.impl.phase;
 
+import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentData;
 import org.onosproject.net.intent.IntentException;
 import org.onosproject.net.intent.impl.IntentProcessor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.List;
 import java.util.Optional;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * Represents a phase where an intent is being compiled.
+ * Represents a phase where an intent is being compiled or recompiled.
  */
-final class Compiling implements IntentProcessPhase {
+class Compiling implements IntentProcessPhase {
 
     private static final Logger log = LoggerFactory.getLogger(Compiling.class);
 
     private final IntentProcessor processor;
     private final IntentData data;
+    private final Optional<IntentData> stored;
 
     /**
-     * Creates an compiling phase.
+     * Creates a intent recompiling phase.
      *
-     * @param processor intent processor that does work for compiling
-     * @param data      intent data containing an intent to be compiled
+     * @param processor intent processor that does work for recompiling
+     * @param data      intent data containing an intent to be recompiled
+     * @param stored    intent data stored in the store
      */
-    Compiling(IntentProcessor processor, IntentData data) {
+    Compiling(IntentProcessor processor, IntentData data, Optional<IntentData> stored) {
         this.processor = checkNotNull(processor);
         this.data = checkNotNull(data);
+        this.stored = checkNotNull(stored);
     }
 
     @Override
     public Optional<IntentProcessPhase> execute() {
         try {
-            data.setInstallables(processor.compile(data.intent(), null));
-            return Optional.of(new Installing(processor, data, null));
+            List<Intent> compiled = processor.compile(data.intent(),
+                    //TODO consider passing an optional here in the future
+                    stored.isPresent() ? stored.get().installables() : null);
+            data.setInstallables(compiled);
+            return Optional.of(new Installing(processor, data, stored));
         } catch (IntentException e) {
             log.debug("Unable to compile intent {} due to: {}", data.intent(), e);
-            return Optional.of(new CompileFailed(data));
+            if (stored.isPresent() && !stored.get().installables().isEmpty()) {
+                // removing orphaned flows and deallocating resources
+                data.setInstallables(stored.get().installables());
+                return Optional.of(new Withdrawing(processor, data));
+            } else {
+                return Optional.of(new Failed(data));
+            }
         }
     }
-
 }
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/AbstractFailed.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Corrupt.java
similarity index 78%
copy from core/net/src/main/java/org/onosproject/net/intent/impl/phase/AbstractFailed.java
copy to core/net/src/main/java/org/onosproject/net/intent/impl/phase/Corrupt.java
index 8c2734b..2fbe164 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/AbstractFailed.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Corrupt.java
@@ -18,13 +18,12 @@
 import org.onosproject.net.intent.IntentData;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.intent.IntentState.FAILED;
+import static org.onosproject.net.intent.IntentState.CORRUPT;
 
 /**
- * A common parent class of a class representing failure
- * as IntentUpdate subclass.
+ * A class representing errors removing or installing intents.
  */
-abstract class AbstractFailed extends FinalIntentProcessPhase {
+public class Corrupt extends FinalIntentProcessPhase {
 
     private final IntentData intentData;
 
@@ -33,9 +32,9 @@
      *
      * @param intentData intentData
      */
-    AbstractFailed(IntentData intentData) {
+    Corrupt(IntentData intentData) {
         this.intentData = checkNotNull(intentData);
-        this.intentData.setState(FAILED);
+        this.intentData.setState(CORRUPT);
     }
 
     @Override
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/AbstractFailed.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Failed.java
similarity index 85%
rename from core/net/src/main/java/org/onosproject/net/intent/impl/phase/AbstractFailed.java
rename to core/net/src/main/java/org/onosproject/net/intent/impl/phase/Failed.java
index 8c2734b..7f628e3 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/AbstractFailed.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Failed.java
@@ -21,10 +21,9 @@
 import static org.onosproject.net.intent.IntentState.FAILED;
 
 /**
- * A common parent class of a class representing failure
- * as IntentUpdate subclass.
+ * Represents a phase where the compile has failed.
  */
-abstract class AbstractFailed extends FinalIntentProcessPhase {
+public class Failed extends FinalIntentProcessPhase {
 
     private final IntentData intentData;
 
@@ -33,7 +32,7 @@
      *
      * @param intentData intentData
      */
-    AbstractFailed(IntentData intentData) {
+    Failed(IntentData intentData) {
         this.intentData = checkNotNull(intentData);
         this.intentData.setState(FAILED);
     }
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java
index 9e09788..03f73eb 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java
@@ -47,10 +47,6 @@
 
     @Override
     public Optional<IntentProcessPhase> execute() {
-        if (!stored.isPresent() || stored.get().installables() == null || stored.get().installables().isEmpty()) {
-            return Optional.of(new Compiling(processor, data));
-        } else {
-            return Optional.of(new Recompiling(processor, data, stored.get()));
-        }
+        return Optional.of(new Compiling(processor, data, stored));
     }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java
index b1a2e24..2ff7ca8 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java
@@ -18,6 +18,8 @@
 import org.onosproject.net.intent.IntentData;
 import org.onosproject.net.intent.impl.IntentProcessor;
 
+import java.util.Optional;
+
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.net.intent.IntentState.INSTALLING;
 
@@ -28,7 +30,7 @@
 
     private final IntentProcessor processor;
     private final IntentData data;
-    private final IntentData stored;
+    private final Optional<IntentData> stored;
 
     /**
      * Create an installing phase.
@@ -37,16 +39,16 @@
      * @param data      intent data containing an intent to be installed
      * @param stored    intent data already stored
      */
-    Installing(IntentProcessor processor, IntentData data, IntentData stored) {
+    Installing(IntentProcessor processor, IntentData data, Optional<IntentData> stored) {
         this.processor = checkNotNull(processor);
         this.data = checkNotNull(data);
+        this.stored = checkNotNull(stored);
         this.data.setState(INSTALLING);
-        this.stored = stored;
     }
 
     @Override
     public void preExecute() {
-        processor.apply(stored, data);
+        processor.apply(stored, Optional.of(data));
     }
 
     @Override
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentProcessPhase.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentProcessPhase.java
index ea5a590..1ed42fd 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentProcessPhase.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentProcessPhase.java
@@ -20,8 +20,6 @@
 
 import java.util.Optional;
 
-import static org.onlab.util.Tools.isNullOrEmpty;
-
 /**
  * Represents a phase of processing an intent.
  */
@@ -46,20 +44,16 @@
      */
     static IntentProcessPhase newInitialPhase(IntentProcessor processor,
                                               IntentData data, IntentData current) {
-        switch (data.state()) {
+        switch (data.request()) {
             case INSTALL_REQ:
                 return new InstallRequest(processor, data, Optional.ofNullable(current));
             case WITHDRAW_REQ:
-                if (current == null || isNullOrEmpty(current.installables())) {
-                    return new Withdrawn(data);
-                } else {
-                    return new WithdrawRequest(processor, data, current);
-                }
+                return new WithdrawRequest(processor, data, Optional.ofNullable(current));
             case PURGE_REQ:
                 return new PurgeRequest(data, current);
             default:
                 // illegal state
-                return new CompileFailed(data);
+                return new Failed(data);
         }
     }
 
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Recompiling.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Recompiling.java
deleted file mode 100644
index 9e27070..0000000
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Recompiling.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2015 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.Intent;
-import org.onosproject.net.intent.IntentData;
-import org.onosproject.net.intent.IntentException;
-import org.onosproject.net.intent.impl.IntentProcessor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.List;
-import java.util.Optional;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * Represents a phase where an intent is being recompiled.
- */
-class Recompiling implements IntentProcessPhase {
-
-    private static final Logger log = LoggerFactory.getLogger(Recompiling.class);
-
-    private final IntentProcessor processor;
-    private final IntentData data;
-    private final IntentData stored;
-
-    /**
-     * Creates a intent recompiling phase.
-     *
-     * @param processor intent processor that does work for recompiling
-     * @param data      intent data containing an intent to be recompiled
-     * @param stored    intent data stored in the store
-     */
-    Recompiling(IntentProcessor processor, IntentData data, IntentData stored) {
-        this.processor = checkNotNull(processor);
-        this.data = checkNotNull(data);
-        this.stored = checkNotNull(stored);
-    }
-
-    @Override
-    public Optional<IntentProcessPhase> execute() {
-        try {
-            List<Intent> compiled = processor.compile(data.intent(), stored.installables());
-            data.setInstallables(compiled);
-            return Optional.of(new Installing(processor, data, stored));
-        } catch (IntentException e) {
-            log.debug("Unable to recompile intent {} due to: {}", data.intent(), e);
-            // FIXME we need to removed orphaned flows and deallocate resources
-            return Optional.of(new CompileFailed(data));
-        }
-    }
-}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/ReplaceFailed.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/ReplaceFailed.java
deleted file mode 100644
index 3fcf97b..0000000
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/ReplaceFailed.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2015 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;
-
-/**
- * Represent a phase where the install has failed.
- */
-class ReplaceFailed extends AbstractFailed {
-
-    /**
-     * Create an instance with the specified data.
-     *
-     * @param intentData intentData
-     */
-    ReplaceFailed(IntentData intentData) {
-        super(intentData);
-    }
-}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java
index 004bb33..73a6510 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java
@@ -29,7 +29,7 @@
 
     private final IntentProcessor processor;
     private final IntentData data;
-    private final IntentData stored;
+    private final Optional<IntentData> stored;
 
     /**
      * Creates a withdraw request phase.
@@ -39,7 +39,7 @@
      * @param intentData intent data to be processed
      * @param stored     intent data stored in the store
      */
-    WithdrawRequest(IntentProcessor processor, IntentData intentData, IntentData stored) {
+    WithdrawRequest(IntentProcessor processor, IntentData intentData, Optional<IntentData> stored) {
         this.processor = checkNotNull(processor);
         this.data = checkNotNull(intentData);
         this.stored = checkNotNull(stored);
@@ -50,7 +50,18 @@
         //TODO perhaps we want to validate that the pending and current are the
         // same version i.e. they are the same
         // Note: this call is not just the symmetric version of submit
-        data.setInstallables(stored.installables());
+
+        if (!stored.isPresent() || stored.get().installables().isEmpty()) {
+            switch (data.request()) {
+                case INSTALL_REQ:
+                    return Optional.of(new Failed(data));
+                case WITHDRAW_REQ:
+                default: //TODO "default" case should not happen
+                    return Optional.of(new Withdrawn(data));
+            }
+        }
+
+        data.setInstallables(stored.get().installables());
         return Optional.of(new Withdrawing(processor, data));
     }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java
index 052cfb5..29bc471 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java
@@ -18,6 +18,8 @@
 import org.onosproject.net.intent.IntentData;
 import org.onosproject.net.intent.impl.IntentProcessor;
 
+import java.util.Optional;
+
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.net.intent.IntentState.WITHDRAWING;
 
@@ -38,13 +40,12 @@
     Withdrawing(IntentProcessor processor, IntentData data) {
         this.processor = checkNotNull(processor);
         this.data = checkNotNull(data);
-
         this.data.setState(WITHDRAWING);
     }
 
     @Override
     protected void preExecute() {
-        processor.apply(data, null);
+        processor.apply(Optional.of(data), Optional.empty());
     }
 
     @Override