Reworked intent states to the new set of states.
Separate intent state from intent event type.
Implemented new state transitions in IntentManager.
Implemented ObjectiveTracker.
Re-route now works.
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
index 541a702..de61e8e 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
@@ -71,11 +71,11 @@
     private Intent createPathIntent(Path path, Host src, Host dst,
                                     HostToHostIntent intent) {
 
-        TrafficSelector selector = builder(intent.getTrafficSelector())
+        TrafficSelector selector = builder(intent.selector())
                 .matchEthSrc(src.mac()).matchEthDst(dst.mac()).build();
 
         return new PathIntent(intentIdGenerator.getNewId(),
-                              selector, intent.getTrafficTreatment(),
+                              selector, intent.treatment(),
                               path.src(), path.dst(), path);
     }
 
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
index 6268245..197c2b2 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
@@ -28,11 +28,15 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.onos.net.intent.IntentState.*;
+import static org.onlab.util.Tools.namedThreads;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -56,6 +60,8 @@
     private final AbstractListenerRegistry<IntentEvent, IntentListener>
             listenerRegistry = new AbstractListenerRegistry<>();
 
+    private ExecutorService executor = newSingleThreadExecutor(namedThreads("onos-intents"));
+
     private final IntentStoreDelegate delegate = new InternalStoreDelegate();
     private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
 
@@ -63,7 +69,7 @@
     protected IntentStore store;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected FlowTrackerService trackerService;
+    protected ObjectiveTrackerService trackerService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected EventDeliveryService eventDispatcher;
@@ -89,21 +95,16 @@
         checkNotNull(intent, INTENT_NULL);
         registerSubclassCompilerIfNeeded(intent);
         IntentEvent event = store.createIntent(intent);
-        processStoreEvent(event);
+        if (event != null) {
+            eventDispatcher.post(event);
+            executor.execute(new IntentTask(COMPILING, intent));
+        }
     }
 
     @Override
     public void withdraw(Intent intent) {
         checkNotNull(intent, INTENT_NULL);
-        IntentEvent event = store.setState(intent, WITHDRAWING);
-        List<InstallableIntent> installables = store.getInstallableIntents(intent.getId());
-        if (installables != null) {
-            for (InstallableIntent installable : installables) {
-                trackerService.removeTrackedResources(intent.getId(),
-                                                      installable.requiredLinks());
-            }
-        }
-        processStoreEvent(event);
+        executor.execute(new IntentTask(WITHDRAWING, intent));
     }
 
     // FIXME: implement this method
@@ -207,56 +208,122 @@
     }
 
     /**
-     * Compiles an intent.
+     * Compiles the specified intent.
      *
-     * @param intent intent
+     * @param intent intent to be compiled
      */
-    private void compileIntent(Intent intent) {
-        // FIXME: To make SDN-IP workable ASAP, only single level compilation is implemented
-        // TODO: implement compilation traversing tree structure
+    private void executeCompilingPhase(Intent intent) {
+        // Indicate that the intent is entering the compiling phase.
+        store.setState(intent, COMPILING);
+
+        try {
+            // Compile the intent into installable derivatives.
+            List<InstallableIntent> installable = compileIntent(intent);
+
+            // If all went well, associate the resulting list of installable
+            // intents with the top-level intent and proceed to install.
+            store.addInstallableIntents(intent.id(), installable);
+            executeInstallingPhase(intent);
+
+        } catch (Exception e) {
+            // If compilation failed, mark the intent as failed.
+            store.setState(intent, FAILED);
+        }
+    }
+
+    // FIXME: To make SDN-IP workable ASAP, only single level compilation is implemented
+    // TODO: implement compilation traversing tree structure
+    private List<InstallableIntent> compileIntent(Intent intent) {
         List<InstallableIntent> installable = new ArrayList<>();
         for (Intent compiled : getCompiler(intent).compile(intent)) {
             InstallableIntent installableIntent = (InstallableIntent) compiled;
             installable.add(installableIntent);
-            trackerService.addTrackedResources(intent.getId(),
+            trackerService.addTrackedResources(intent.id(),
                                                installableIntent.requiredLinks());
         }
-        IntentEvent event = store.addInstallableIntents(intent.getId(), installable);
-        processStoreEvent(event);
+        return installable;
     }
 
     /**
-     * Installs an intent.
+     * Installs all installable intents associated with the specified top-level
+     * intent.
      *
-     * @param intent intent
+     * @param intent intent to be installed
      */
-    private void installIntent(Intent intent) {
-        List<InstallableIntent> installables = store.getInstallableIntents(intent.getId());
-        if (installables != null) {
-            for (InstallableIntent installable : installables) {
-                registerSubclassInstallerIfNeeded(installable);
-                getInstaller(installable).install(installable);
+    private void executeInstallingPhase(Intent intent) {
+        // Indicate that the intent is entering the installing phase.
+        store.setState(intent, INSTALLING);
+
+        try {
+            List<InstallableIntent> installables = store.getInstallableIntents(intent.id());
+            if (installables != null) {
+                for (InstallableIntent installable : installables) {
+                    registerSubclassInstallerIfNeeded(installable);
+                    getInstaller(installable).install(installable);
+                }
             }
-        }
-        IntentEvent event = store.setState(intent, INSTALLED);
-        processStoreEvent(event);
+            eventDispatcher.post(store.setState(intent, INSTALLED));
 
+        } catch (Exception e) {
+            // If compilation failed, kick off the recompiling phase.
+            executeRecompilingPhase(intent);
+        }
     }
 
     /**
-     * Uninstalls an intent.
+     * Recompiles the specified intent.
      *
-     * @param intent intent
+     * @param intent intent to be recompiled
      */
-    private void uninstallIntent(Intent intent) {
-        List<InstallableIntent> installables = store.getInstallableIntents(intent.getId());
+    private void executeRecompilingPhase(Intent intent) {
+        // Indicate that the intent is entering the recompiling phase.
+        store.setState(intent, RECOMPILING);
+
+        try {
+            // Compile the intent into installable derivatives.
+            List<InstallableIntent> installable = compileIntent(intent);
+
+            // If all went well, compare the existing list of installable
+            // intents with the newly compiled list. If they are the same,
+            // bail, out since the previous approach was determined not to
+            // be viable.
+            List<InstallableIntent> originalInstallable =
+                    store.getInstallableIntents(intent.id());
+
+            if (Objects.equals(originalInstallable, installable)) {
+                eventDispatcher.post(store.setState(intent, FAILED));
+            } else {
+                // Otherwise, re-associate the newly compiled installable intents
+                // with the top-level intent and kick off installing phase.
+                store.addInstallableIntents(intent.id(), installable);
+                executeInstallingPhase(intent);
+            }
+        } catch (Exception e) {
+            // If compilation failed, mark the intent as failed.
+            eventDispatcher.post(store.setState(intent, FAILED));
+        }
+    }
+
+    /**
+     * Uninstalls the specified intent by uninstalling all of its associated
+     * installable derivatives.
+     *
+     * @param intent intent to be installed
+     */
+    private void executeWithdrawingPhase(Intent intent) {
+        // Indicate that the intent is being withdrawn.
+        store.setState(intent, WITHDRAWING);
+        List<InstallableIntent> installables = store.getInstallableIntents(intent.id());
         if (installables != null) {
             for (InstallableIntent installable : installables) {
                 getInstaller(installable).uninstall(installable);
             }
         }
-        store.removeInstalledIntents(intent.getId());
-        store.setState(intent, WITHDRAWN);
+
+        // If all went well, disassociate the top-level intent with its
+        // installable derivatives and mark it as withdrawn.
+        store.removeInstalledIntents(intent.id());
+        eventDispatcher.post(store.setState(intent, WITHDRAWN));
     }
 
     /**
@@ -309,55 +376,58 @@
         }
     }
 
-    /**
-     * Handles state transition of submitted intents.
-     */
-    private void processStoreEvent(IntentEvent event) {
-        eventDispatcher.post(event);
-        Intent intent = event.getIntent();
-        try {
-            switch (event.getState()) {
-                case SUBMITTED:
-                    compileIntent(intent);
-                    break;
-                case COMPILED:
-                    installIntent(intent);
-                    break;
-                case INSTALLED:
-                    break;
-                case WITHDRAWING:
-                    uninstallIntent(intent);
-                    break;
-                case WITHDRAWN:
-                    break;
-                case FAILED:
-                    break;
-                default:
-                    throw new IllegalStateException("the state of IntentEvent is illegal: " +
-                                                            event.getState());
-            }
-        } catch (IntentException e) {
-            store.setState(intent, FAILED);
-        }
-
-    }
-
     // Store delegate to re-post events emitted from the store.
     private class InternalStoreDelegate implements IntentStoreDelegate {
         @Override
         public void notify(IntentEvent event) {
-            processStoreEvent(event);
+            eventDispatcher.post(event);
+            if (event.type() == IntentEvent.Type.SUBMITTED) {
+                executor.execute(new IntentTask(COMPILING, event.subject()));
+            }
         }
     }
 
     // Topology change delegate
     private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
         @Override
-        public void bumpIntents(Iterable<IntentId> intentIds) {
+        public void triggerCompile(Iterable<IntentId> intentIds,
+                                   boolean compileAllFailed) {
+            // Attempt recompilation of the specified intents first.
             for (IntentId intentId : intentIds) {
-                compileIntent(getIntent(intentId));
+                executeRecompilingPhase(getIntent(intentId));
+            }
+
+            if (compileAllFailed) {
+                // If required, compile all currently failed intents.
+                for (Intent intent : getIntents()) {
+                    if (getIntentState(intent.id()) == FAILED) {
+                        executeCompilingPhase(intent);
+                    }
+                }
             }
         }
-
     }
+
+    // Auxiliary runnable to perform asynchronous tasks.
+    private class IntentTask implements Runnable {
+        private final IntentState state;
+        private final Intent intent;
+
+        public IntentTask(IntentState state, Intent intent) {
+            this.state = state;
+            this.intent = intent;
+        }
+
+        @Override
+        public void run() {
+            if (state == COMPILING) {
+                executeCompilingPhase(intent);
+            } else if (state == RECOMPILING) {
+                executeRecompilingPhase(intent);
+            } else if (state == WITHDRAWING) {
+                executeWithdrawingPhase(intent);
+            }
+        }
+    }
+
 }
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/FlowTracker.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTracker.java
similarity index 81%
rename from core/net/src/main/java/org/onlab/onos/net/intent/impl/FlowTracker.java
rename to core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTracker.java
index f69bf78..17d420b 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/FlowTracker.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTracker.java
@@ -19,12 +19,15 @@
 import org.slf4j.Logger;
 
 import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
 import static org.onlab.util.Tools.namedThreads;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -34,7 +37,7 @@
  */
 @Component
 @Service
-public class FlowTracker implements FlowTrackerService {
+public class ObjectiveTracker implements ObjectiveTrackerService {
 
     private final Logger log = getLogger(getClass());
 
@@ -110,14 +113,26 @@
         @Override
         public void run() {
             if (event.reasons() == null) {
-                delegate.bumpIntents(intentsByLink.values());
+                delegate.triggerCompile(null, false);
+
             } else {
+                Set<IntentId> toBeRecompiled = new HashSet<>();
+                boolean recompileOnly = true;
+
+                // Scan through the list of reasons and keep accruing all
+                // intents that need to be recompiled.
                 for (Event reason : event.reasons()) {
                     if (reason instanceof LinkEvent) {
                         LinkEvent linkEvent = (LinkEvent) reason;
-                        delegate.bumpIntents(intentsByLink.get(new LinkKey(linkEvent.subject())));
+                        if (linkEvent.type() == LINK_REMOVED) {
+                            Set<IntentId> intentIds = intentsByLink.get(new LinkKey(linkEvent.subject()));
+                            toBeRecompiled.addAll(intentIds);
+                        }
+                        recompileOnly = recompileOnly && linkEvent.type() == LINK_REMOVED;
                     }
                 }
+
+                delegate.triggerCompile(toBeRecompiled, !recompileOnly);
             }
         }
     }
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/FlowTrackerService.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTrackerService.java
similarity index 96%
rename from core/net/src/main/java/org/onlab/onos/net/intent/impl/FlowTrackerService.java
rename to core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTrackerService.java
index b96de7c..15496ff 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/FlowTrackerService.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTrackerService.java
@@ -9,7 +9,7 @@
  * Auxiliary service for tracking intent path flows and for notifying the
  * intent service of environment changes via topology change delegate.
  */
-public interface FlowTrackerService {
+public interface ObjectiveTrackerService {
 
     /**
      * Sets a topology change delegate.
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java
index f9cfa67..eb2e113 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java
@@ -49,8 +49,8 @@
     @Override
     public void install(PathIntent intent) {
         TrafficSelector.Builder builder =
-                DefaultTrafficSelector.builder(intent.getTrafficSelector());
-        Iterator<Link> links = intent.getPath().links().iterator();
+                DefaultTrafficSelector.builder(intent.selector());
+        Iterator<Link> links = intent.path().links().iterator();
         ConnectPoint prev = links.next().dst();
 
         while (links.hasNext()) {
@@ -70,8 +70,8 @@
     @Override
     public void uninstall(PathIntent intent) {
         TrafficSelector.Builder builder =
-                DefaultTrafficSelector.builder(intent.getTrafficSelector());
-        Iterator<Link> links = intent.getPath().links().iterator();
+                DefaultTrafficSelector.builder(intent.selector());
+        Iterator<Link> links = intent.path().links().iterator();
         ConnectPoint prev = links.next().dst();
 
         while (links.hasNext()) {
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/TopologyChangeDelegate.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/TopologyChangeDelegate.java
index d8a5a95..7a9fd12 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/TopologyChangeDelegate.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/TopologyChangeDelegate.java
@@ -9,10 +9,14 @@
 
     /**
      * Notifies that topology has changed in such a way that the specified
-     * intents should be recompiled.
+     * intents should be recompiled. If the {@code compileAllFailed} parameter
+     * is true, the all intents in {@link org.onlab.onos.net.intent.IntentState#FAILED}
+     * state should be compiled as well.
      *
      * @param intentIds intents that should be recompiled
+     * @param compileAllFailed true implies full compile is required; false for
+     *                         selective recompile only
      */
-    void bumpIntents(Iterable<IntentId> intentIds);
+    void triggerCompile(Iterable<IntentId> intentIds, boolean compileAllFailed);
 
 }