Adding Intent Impl and shell command to install simple intent
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/IntentInstallCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/IntentInstallCommand.java
new file mode 100644
index 0000000..379d6a8
--- /dev/null
+++ b/cli/src/main/java/org/onlab/onos/cli/net/IntentInstallCommand.java
@@ -0,0 +1,61 @@
+package org.onlab.onos.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.onos.cli.AbstractShellCommand;
+import org.onlab.onos.net.HostId;
+import org.onlab.onos.net.flow.DefaultTrafficSelector;
+import org.onlab.onos.net.flow.DefaultTrafficTreatment;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.intent.HostToHostIntent;
+import org.onlab.onos.net.intent.IntentId;
+import org.onlab.onos.net.intent.IntentService;
+
+/**
+ * Lists all shortest-paths paths between the specified source and
+ * destination devices.
+ */
+@Command(scope = "onos", name = "add-intent",
+         description = "Installs HostToHostIntent between the specified source and destination devices")
+public class IntentInstallCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "src", description = "Source device ID",
+              required = true, multiValued = false)
+    String src = null;
+
+    @Argument(index = 1, name = "dst", description = "Destination device ID",
+              required = true, multiValued = false)
+    String dst = null;
+
+    private static long id = 1;
+
+    @Override
+    protected void execute() {
+        IntentService service = get(IntentService.class);
+        HostService hosts = get(HostService.class);
+
+        HostId srcId = HostId.hostId(src);
+        HostId dstId = HostId.hostId(dst);
+
+        TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder();
+        builder
+            .matchEthSrc(hosts.getHost(srcId).mac())
+            .matchEthDst(hosts.getHost(dstId).mac());
+
+        TrafficTreatment.Builder treat = new DefaultTrafficTreatment.Builder();
+
+        HostToHostIntent intent = new HostToHostIntent(
+                new IntentId(id++),
+                srcId,
+                dstId,
+                builder.build(),
+                treat.build());
+
+        log.info("Adding intent {}", intent);
+
+        service.submit(intent);
+    }
+
+}
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 16b5672..a096735 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -57,6 +57,13 @@
             </completers>
         </command>
         <command>
+            <action class="org.onlab.onos.cli.net.IntentInstallCommand"/>
+            <completers>
+                <ref component-id="hostIdCompleter"/>
+            </completers>
+        </command>
+
+        <command>
             <action class="org.onlab.onos.cli.net.ClustersListCommand"/>
         </command>
         <command>
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java
new file mode 100644
index 0000000..ff6e7c6
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java
@@ -0,0 +1,92 @@
+package org.onlab.onos.net.intent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+import org.onlab.onos.net.HostId;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Abstraction of point-to-point connectivity.
+ */
+public class HostToHostIntent extends ConnectivityIntent {
+
+    private final HostId src;
+    private final HostId dst;
+
+    /**
+     * Creates a new point-to-point intent with the supplied ingress/egress
+     * ports.
+     *
+     * @param id intent identifier
+     * @param match traffic match
+     * @param action action
+     * @param ingressPort ingress port
+     * @param egressPort egress port
+     * @throws NullPointerException if {@code ingressPort} or {@code egressPort}
+     *         is null.
+     */
+    public HostToHostIntent(IntentId id, HostId src, HostId dst,
+            TrafficSelector selector, TrafficTreatment treatment) {
+        super(id, selector, treatment);
+        this.src = checkNotNull(src);
+        this.dst = checkNotNull(dst);
+    }
+
+    /**
+     * Returns the port on which the ingress traffic should be connected to the
+     * egress.
+     *
+     * @return ingress port
+     */
+    public HostId getSrc() {
+        return src;
+    }
+
+    /**
+     * Returns the port on which the traffic should egress.
+     *
+     * @return egress port
+     */
+    public HostId getDst() {
+        return dst;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        if (!super.equals(o)) {
+            return false;
+        }
+
+        HostToHostIntent that = (HostToHostIntent) o;
+        return Objects.equals(this.src, that.src)
+                && Objects.equals(this.dst, that.dst);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), src, dst);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("id", getId())
+                .add("selector", getTrafficSelector())
+                .add("treatmetn", getTrafficTreatment())
+                .add("src", src)
+                .add("dst", dst)
+                .toString();
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentEvent.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentEvent.java
index 27ae834..b8f0344 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentEvent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentEvent.java
@@ -4,14 +4,17 @@
 
 import java.util.Objects;
 
+import org.onlab.onos.event.AbstractEvent;
+
 import com.google.common.base.MoreObjects;
 
 /**
  * A class to represent an intent related event.
  */
-public class IntentEvent {
+public class IntentEvent extends AbstractEvent<IntentState, Intent> {
 
-    // TODO: determine a suitable parent class; if one does not exist, consider introducing one
+    // TODO: determine a suitable parent class; if one does not exist, consider
+    // introducing one
 
     private final long time;
     private final Intent intent;
@@ -28,6 +31,7 @@
      * @throws NullPointerException if the intent or state is null
      */
     public IntentEvent(Intent intent, IntentState state, IntentState previous, long time) {
+        super(state, intent);
         this.intent = checkNotNull(intent);
         this.state = checkNotNull(state);
         this.previous = previous;
@@ -35,16 +39,6 @@
     }
 
     /**
-     * Constructor for serializer.
-     */
-    protected IntentEvent() {
-        this.intent = null;
-        this.state = null;
-        this.previous = null;
-        this.time = 0;
-    }
-
-    /**
      * Returns the state of the intent which caused the event.
      *
      * @return the state of the intent
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentEventListener.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentEventListener.java
deleted file mode 100644
index f59ecfc..0000000
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentEventListener.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.onlab.onos.net.intent;
-
-/**
- * Listener for {@link IntentEvent intent events}.
- */
-public interface IntentEventListener {
-    /**
-     * Processes the specified intent event.
-     *
-     * @param event the event to process
-     */
-    void event(IntentEvent event);
-}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentListener.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentListener.java
new file mode 100644
index 0000000..c00c1f6
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentListener.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.intent;
+
+import org.onlab.onos.event.EventListener;
+
+/**
+ * Listener for {@link IntentEvent intent events}.
+ */
+public interface IntentListener extends EventListener<IntentEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java
index 2b4fb59..8d550e8 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java
@@ -1,6 +1,5 @@
 package org.onlab.onos.net.intent;
 
-import java.util.Set;
 
 /**
  * Service for application submitting or withdrawing their intents.
@@ -9,8 +8,8 @@
     /**
      * Submits an intent into the system.
      *
-     * This is an asynchronous request meaning that any compiling
-     * or installation activities may be done at later time.
+     * This is an asynchronous request meaning that any compiling or
+     * installation activities may be done at later time.
      *
      * @param intent intent to be submitted
      */
@@ -19,8 +18,8 @@
     /**
      * Withdraws an intent from the system.
      *
-     * This is an asynchronous request meaning that the environment
-     * may be affected at later time.
+     * This is an asynchronous request meaning that the environment may be
+     * affected at later time.
      *
      * @param intent intent to be withdrawn
      */
@@ -30,19 +29,26 @@
      * Submits a batch of submit &amp; withdraw operations. Such a batch is
      * assumed to be processed together.
      *
-     * This is an asynchronous request meaning that the environment
-     * may be affected at later time.
+     * This is an asynchronous request meaning that the environment may be
+     * affected at later time.
      *
      * @param operations batch of intent operations
      */
     void execute(IntentOperations operations);
 
     /**
-     * Returns immutable set of intents currently in the system.
+     * Returns an iterable of intents currently in the system.
      *
      * @return set of intents
      */
-    Set<Intent> getIntents();
+    Iterable<Intent> getIntents();
+
+    /**
+     * Returns the number of intents currently in the system.
+     *
+     * @return number of intents
+     */
+    long getIntentCount();
 
     /**
      * Retrieves the intent specified by its identifier.
@@ -56,7 +62,8 @@
      * Retrieves the state of an intent by its identifier.
      *
      * @param id intent identifier
-     * @return the intent state or null if one with the given identifier is not found
+     * @return the intent state or null if one with the given identifier is not
+     *         found
      */
     IntentState getIntentState(IntentId id);
 
@@ -65,12 +72,12 @@
      *
      * @param listener listener to be added
      */
-    void addListener(IntentEventListener listener);
+    void addListener(IntentListener listener);
 
     /**
      * Removes the specified listener for intent events.
      *
      * @param listener listener to be removed
      */
-    void removeListener(IntentEventListener listener);
+    void removeListener(IntentListener listener);
 }
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentStore.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentStore.java
new file mode 100644
index 0000000..792398e
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentStore.java
@@ -0,0 +1,64 @@
+package org.onlab.onos.net.intent;
+
+import java.util.List;
+
+import org.onlab.onos.store.Store;
+
+/**
+ * Manages inventory of end-station intents; not intended for direct use.
+ */
+public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
+
+    /**
+     * Creates a new intent.
+     *
+     * @param intent intent
+     * @return appropriate event or null if no change resulted
+     */
+    IntentEvent createIntent(Intent intent);
+
+    /**
+     * Removes the specified intent from the inventory.
+     *
+     * @param intentId intent identification
+     * @return remove event or null if intent was not found
+     */
+    IntentEvent removeIntent(IntentId intent);
+
+    /**
+     * Returns the number of intents in the store.
+     *
+     */
+    long getIntentCount();
+
+    /**
+     * Returns a collection of all intents in the store.
+     *
+     * @return iterable collection of all intents
+     */
+    Iterable<Intent> getIntents();
+
+    /**
+     * Returns the intent with the specified identifer.
+     *
+     * @param intentId intent identification
+     * @return intent or null if not found
+     */
+    Intent getIntent(IntentId intentId);
+
+    IntentState getIntentState(IntentId id);
+
+    /**
+     * Sets the state of the specified intent to the new state.
+     *
+     * @param intent intent whose state is to be changed
+     * @param newState new state
+     */
+    IntentEvent setState(Intent intent, IntentState newState);
+
+    IntentEvent addInstallableIntents(IntentId intentId, List<InstallableIntent> result);
+
+    List<InstallableIntent> getInstallableIntents(IntentId intentId);
+
+    void removeInstalledIntents(IntentId intentId);
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentStoreDelegate.java
new file mode 100644
index 0000000..5a4da1a
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.intent;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Infrastructure link store delegate abstraction.
+ */
+public interface IntentStoreDelegate extends StoreDelegate<IntentEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
index 39ad011..6809ce2 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
@@ -12,7 +12,7 @@
 /**
  * Abstraction of explicitly path specified connectivity intent.
  */
-public class PathIntent extends PointToPointIntent {
+public class PathIntent extends PointToPointIntent implements InstallableIntent {
 
     private final Path path;
 
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java b/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java
index df46ec5..349749e 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java
@@ -11,19 +11,19 @@
 import java.util.concurrent.Executors;
 
 /**
- * Fake implementation of the intent service to assist in developing tests
- * of the interface contract.
+ * Fake implementation of the intent service to assist in developing tests of
+ * the interface contract.
  */
 public class FakeIntentManager implements TestableIntentService {
 
     private final Map<IntentId, Intent> intents = new HashMap<>();
     private final Map<IntentId, IntentState> intentStates = new HashMap<>();
     private final Map<IntentId, List<InstallableIntent>> installables = new HashMap<>();
-    private final Set<IntentEventListener> listeners = new HashSet<>();
+    private final Set<IntentListener> listeners = new HashSet<>();
 
     private final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers = new HashMap<>();
-    private final Map<Class<? extends InstallableIntent>,
-            IntentInstaller<? extends InstallableIntent>> installers = new HashMap<>();
+    private final Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> installers
+        = new HashMap<>();
 
     private final ExecutorService executor = Executors.newSingleThreadExecutor();
     private final List<IntentException> exceptions = new ArrayList<>();
@@ -76,7 +76,8 @@
 
     private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) {
         @SuppressWarnings("unchecked")
-        IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
+        IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent
+                .getClass());
         if (installer == null) {
             throw new IntentException("no installer for class " + intent.getClass());
         }
@@ -125,7 +126,6 @@
         }
     }
 
-
     // Sets the internal state for the given intent and dispatches an event
     private void setState(Intent intent, IntentState state) {
         IntentState previous = intentStates.get(intent.getId());
@@ -175,6 +175,11 @@
     }
 
     @Override
+    public long getIntentCount() {
+        return intents.size();
+    }
+
+    @Override
     public Intent getIntent(IntentId id) {
         return intents.get(id);
     }
@@ -185,23 +190,24 @@
     }
 
     @Override
-    public void addListener(IntentEventListener listener) {
+    public void addListener(IntentListener listener) {
         listeners.add(listener);
     }
 
     @Override
-    public void removeListener(IntentEventListener listener) {
+    public void removeListener(IntentListener listener) {
         listeners.remove(listener);
     }
 
     private void dispatch(IntentEvent event) {
-        for (IntentEventListener listener : listeners) {
+        for (IntentListener listener : listeners) {
             listener.event(event);
         }
     }
 
     @Override
-    public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
+    public <T extends Intent> void registerCompiler(Class<T> cls,
+            IntentCompiler<T> compiler) {
         compilers.put(cls, compiler);
     }
 
@@ -216,7 +222,8 @@
     }
 
     @Override
-    public <T extends InstallableIntent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
+    public <T extends InstallableIntent> void registerInstaller(Class<T> cls,
+            IntentInstaller<T> installer) {
         installers.put(cls, installer);
     }
 
@@ -227,7 +234,7 @@
 
     @Override
     public Map<Class<? extends InstallableIntent>,
-            IntentInstaller<? extends InstallableIntent>> getInstallers() {
+    IntentInstaller<? extends InstallableIntent>> getInstallers() {
         return Collections.unmodifiableMap(installers);
     }
 
@@ -252,7 +259,8 @@
         if (!installers.containsKey(intent.getClass())) {
             Class<?> cls = intent.getClass();
             while (cls != Object.class) {
-                // As long as we're within the InstallableIntent class descendants
+                // As long as we're within the InstallableIntent class
+                // descendants
                 if (InstallableIntent.class.isAssignableFrom(cls)) {
                     IntentInstaller<?> installer = installers.get(cls);
                     if (installer != null) {
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/IntentServiceTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/IntentServiceTest.java
index c7682b1..825be86 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/IntentServiceTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/IntentServiceTest.java
@@ -51,7 +51,7 @@
     @Test
     public void basics() {
         // Make sure there are no intents
-        assertEquals("incorrect intent count", 0, service.getIntents().size());
+        assertEquals("incorrect intent count", 0, service.getIntentCount());
 
         // Register a compiler and an installer both setup for success.
         service.registerCompiler(TestIntent.class, new TestCompiler(new TestInstallableIntent(INSTALLABLE_IID)));
@@ -73,8 +73,7 @@
         validateEvents(intent, SUBMITTED, COMPILED, INSTALLED);
 
         // Make sure there is just one intent (and is ours)
-        assertEquals("incorrect intent count", 1, service.getIntents().size());
-        assertEquals("incorrect intent", intent, service.getIntent(intent.getId()));
+        assertEquals("incorrect intent count", 1, service.getIntentCount());
 
         // Reset the listener events
         listener.events.clear();
@@ -250,7 +249,7 @@
 
 
     // Fixture to track emitted intent events
-    protected class TestListener implements IntentEventListener {
+    protected class TestListener implements IntentListener {
         final List<IntentEvent> events = new ArrayList<>();
 
         @Override
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/AbstractBlockAllocatorBasedIdGenerator.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/AbstractBlockAllocatorBasedIdGenerator.java
new file mode 100644
index 0000000..00b64da
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/AbstractBlockAllocatorBasedIdGenerator.java
@@ -0,0 +1,42 @@
+package org.onlab.onos.net.intent.impl;
+
+import org.onlab.onos.net.intent.IdGenerator;
+
+/**
+ * Base class of {@link IdGenerator} implementations which use {@link IdBlockAllocator} as
+ * backend.
+ *
+ * @param <T> the type of ID
+ */
+public abstract class AbstractBlockAllocatorBasedIdGenerator<T> implements IdGenerator<T> {
+    protected final IdBlockAllocator allocator;
+    protected IdBlock idBlock;
+
+    /**
+     * Constructs an ID generator which use {@link IdBlockAllocator} as backend.
+     *
+     * @param allocator
+     */
+    protected AbstractBlockAllocatorBasedIdGenerator(IdBlockAllocator allocator) {
+        this.allocator = allocator;
+        this.idBlock = allocator.allocateUniqueIdBlock();
+    }
+
+    @Override
+    public synchronized T getNewId() {
+        try {
+            return convertFrom(idBlock.getNextId());
+        } catch (UnavailableIdException e) {
+            idBlock = allocator.allocateUniqueIdBlock();
+            return convertFrom(idBlock.getNextId());
+        }
+    }
+
+    /**
+     * Returns an ID instance of {@code T} type from the long value.
+     *
+     * @param value original long value
+     * @return ID instance
+     */
+    protected abstract T convertFrom(long value);
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/DummyIdBlockAllocator.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/DummyIdBlockAllocator.java
new file mode 100644
index 0000000..f331aa2
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/DummyIdBlockAllocator.java
@@ -0,0 +1,31 @@
+package org.onlab.onos.net.intent.impl;
+
+public class DummyIdBlockAllocator implements IdBlockAllocator {
+    private long blockTop;
+    private static final long BLOCK_SIZE = 0x1000000L;
+
+    /**
+     * Returns a block of IDs which are unique and unused.
+     * Range of IDs is fixed size and is assigned incrementally as this method
+     * called.
+     *
+     * @return an IdBlock containing a set of unique IDs
+     */
+    @Override
+    public IdBlock allocateUniqueIdBlock() {
+        synchronized (this)  {
+            long blockHead = blockTop;
+            long blockTail = blockTop + BLOCK_SIZE;
+
+            IdBlock block = new IdBlock(blockHead, BLOCK_SIZE);
+            blockTop = blockTail;
+
+            return block;
+        }
+    }
+
+    @Override
+    public IdBlock allocateUniqueIdBlock(long range) {
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+}
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
new file mode 100644
index 0000000..a8bea2e
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
@@ -0,0 +1,67 @@
+package org.onlab.onos.net.intent.impl;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.Path;
+import org.onlab.onos.net.PortNumber;
+import org.onlab.onos.net.intent.HostToHostIntent;
+import org.onlab.onos.net.intent.IdGenerator;
+import org.onlab.onos.net.intent.Intent;
+import org.onlab.onos.net.intent.IntentCompiler;
+import org.onlab.onos.net.intent.IntentExtensionService;
+import org.onlab.onos.net.intent.IntentId;
+import org.onlab.onos.net.intent.PathIntent;
+import org.onlab.onos.net.topology.PathService;
+
+/**
+ * A intent compiler for {@link HostToHostIntent}.
+ */
+@Component(immediate = true)
+public class HostToHostIntentCompiler
+        implements IntentCompiler<HostToHostIntent> {
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentExtensionService intentManager;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PathService pathService;
+
+    private IdGenerator<IntentId> intentIdGenerator;
+
+    @Activate
+    public void activate() {
+        IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
+        intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator);
+        intentManager.registerCompiler(HostToHostIntent.class, this);
+    }
+
+    @Deactivate
+    public void deactivate() {
+        intentManager.unregisterCompiler(HostToHostIntent.class);
+    }
+
+    @Override
+    public List<Intent> compile(HostToHostIntent intent) {
+        Set<Path> paths = pathService.getPaths(intent.getSrc(), intent.getDst());
+        if (paths.isEmpty()) {
+            throw new PathNotFoundException();
+        }
+        Path path = paths.iterator().next();
+
+        return Arrays.asList((Intent) new PathIntent(
+                intentIdGenerator.getNewId(),
+                intent.getTrafficSelector(),
+                intent.getTrafficTreatment(),
+                new ConnectPoint(intent.getSrc(), PortNumber.ALL),
+                new ConnectPoint(intent.getDst(), PortNumber.ALL),
+                path));
+    }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlock.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlock.java
new file mode 100644
index 0000000..ce418ea
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlock.java
@@ -0,0 +1,111 @@
+package org.onlab.onos.net.intent.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicLong;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * A class representing an ID space.
+ */
+public final class IdBlock {
+    private final long start;
+    private final long size;
+
+    private final AtomicLong currentId;
+
+    /**
+     * Constructs a new ID block with the specified size and initial value.
+     *
+     * @param start initial value of the block
+     * @param size size of the block
+     * @throws IllegalArgumentException if the size is less than or equal to 0
+     */
+    public IdBlock(long start, long size) {
+        checkArgument(size > 0, "size should be more than 0, but %s", size);
+
+        this.start = start;
+        this.size = size;
+
+        this.currentId = new AtomicLong(start);
+    }
+
+    // TODO: consider if this method is needed or not
+    /**
+     * Returns the initial value.
+     *
+     * @return initial value
+     */
+    public long getStart() {
+        return start;
+    }
+
+    // TODO: consider if this method is needed or not
+    /**
+     * Returns the last value.
+     *
+     * @return last value
+     */
+    public long getEnd() {
+        return start + size - 1;
+    }
+
+    /**
+     * Returns the block size.
+     *
+     * @return block size
+     */
+    public long getSize() {
+        return size;
+    }
+
+    /**
+     * Returns the next ID in the block.
+     *
+     * @return next ID
+     * @throws UnavailableIdException if there is no available ID in the block.
+     */
+    public long getNextId() {
+        final long id = currentId.getAndIncrement();
+        if (id > getEnd()) {
+            throw new UnavailableIdException(String.format(
+                    "used all IDs in allocated space (size: %d, end: %d, current: %d)",
+                    size, getEnd(), id
+            ));
+        }
+
+        return id;
+    }
+
+    // TODO: Do we really need equals and hashCode? Should it contain currentId?
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        IdBlock that = (IdBlock) o;
+        return Objects.equals(this.start, that.start)
+                && Objects.equals(this.size, that.size)
+                && Objects.equals(this.currentId.get(), that.currentId.get());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(start, size, currentId);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("start", start)
+                .add("size", size)
+                .add("currentId", currentId)
+                .toString();
+    }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocator.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocator.java
new file mode 100644
index 0000000..1adac02
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocator.java
@@ -0,0 +1,21 @@
+package org.onlab.onos.net.intent.impl;
+
+/**
+ * An interface that gives unique ID spaces.
+ */
+public interface IdBlockAllocator {
+    /**
+     * Allocates a unique Id Block.
+     *
+     * @return Id Block.
+     */
+    IdBlock allocateUniqueIdBlock();
+
+    /**
+     * Allocates next unique id and retrieve a new range of ids if needed.
+     *
+     * @param range range to use for the identifier
+     * @return Id Block.
+     */
+    IdBlock allocateUniqueIdBlock(long range);
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocatorBasedIntentIdGenerator.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocatorBasedIntentIdGenerator.java
new file mode 100644
index 0000000..b8c5c9b
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocatorBasedIntentIdGenerator.java
@@ -0,0 +1,25 @@
+package org.onlab.onos.net.intent.impl;
+
+import org.onlab.onos.net.intent.IntentId;
+
+/**
+ * An implementation of {@link net.onrc.onos.core.util.IdGenerator} of intent ID,
+ * which uses {@link IdBlockAllocator}.
+ */
+public class IdBlockAllocatorBasedIntentIdGenerator extends AbstractBlockAllocatorBasedIdGenerator<IntentId> {
+
+    /**
+     * Constructs an intent ID generator, which uses the specified ID block allocator
+     * to generate a global unique intent ID.
+     *
+     * @param allocator the ID block allocator to use for generating intent IDs
+     */
+    public IdBlockAllocatorBasedIntentIdGenerator(IdBlockAllocator allocator) {
+        super(allocator);
+    }
+
+    @Override
+    protected IntentId convertFrom(long value) {
+        return new IntentId(value);
+    }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentCompilationException.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentCompilationException.java
new file mode 100644
index 0000000..bf739df
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentCompilationException.java
@@ -0,0 +1,22 @@
+package org.onlab.onos.net.intent.impl;
+
+import org.onlab.onos.net.intent.IntentException;
+
+/**
+ * An exception thrown when a intent compilation fails.
+ */
+public class IntentCompilationException extends IntentException {
+    private static final long serialVersionUID = 235237603018210810L;
+
+    public IntentCompilationException() {
+        super();
+    }
+
+    public IntentCompilationException(String message) {
+        super(message);
+    }
+
+    public IntentCompilationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentInstallationException.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentInstallationException.java
new file mode 100644
index 0000000..3b17cf1
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentInstallationException.java
@@ -0,0 +1,22 @@
+package org.onlab.onos.net.intent.impl;
+
+import org.onlab.onos.net.intent.IntentException;
+
+/**
+ * An exception thrown when intent installation fails.
+ */
+public class IntentInstallationException extends IntentException {
+    private static final long serialVersionUID = 3720268258616014168L;
+
+    public IntentInstallationException() {
+        super();
+    }
+
+    public IntentInstallationException(String message) {
+        super(message);
+    }
+
+    public IntentInstallationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
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
new file mode 100644
index 0000000..f1c9de3
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
@@ -0,0 +1,363 @@
+package org.onlab.onos.net.intent.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.onos.net.intent.IntentState.FAILED;
+import static org.onlab.onos.net.intent.IntentState.INSTALLED;
+import static org.onlab.onos.net.intent.IntentState.WITHDRAWING;
+import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.onos.event.AbstractListenerRegistry;
+import org.onlab.onos.event.EventDeliveryService;
+import org.onlab.onos.net.intent.InstallableIntent;
+import org.onlab.onos.net.intent.Intent;
+import org.onlab.onos.net.intent.IntentCompiler;
+import org.onlab.onos.net.intent.IntentEvent;
+import org.onlab.onos.net.intent.IntentException;
+import org.onlab.onos.net.intent.IntentExtensionService;
+import org.onlab.onos.net.intent.IntentId;
+import org.onlab.onos.net.intent.IntentInstaller;
+import org.onlab.onos.net.intent.IntentListener;
+import org.onlab.onos.net.intent.IntentOperations;
+import org.onlab.onos.net.intent.IntentService;
+import org.onlab.onos.net.intent.IntentState;
+import org.onlab.onos.net.intent.IntentStore;
+import org.onlab.onos.net.intent.IntentStoreDelegate;
+import org.slf4j.Logger;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * An implementation of Intent Manager.
+ */
+@Component(immediate = true)
+@Service
+public class IntentManager
+        implements IntentService, IntentExtensionService {
+    private final Logger log = getLogger(getClass());
+
+    public static final String INTENT_NULL = "Intent cannot be null";
+    public static final String INTENT_ID_NULL = "Intent ID cannot be null";
+
+    // Collections for compiler, installer, and listener are ONOS instance local
+    private final ConcurrentMap<Class<? extends Intent>,
+            IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
+    private final ConcurrentMap<Class<? extends InstallableIntent>,
+            IntentInstaller<? extends InstallableIntent>> installers = new ConcurrentHashMap<>();
+    private final CopyOnWriteArrayList<IntentListener> listeners = new CopyOnWriteArrayList<>();
+
+    private final AbstractListenerRegistry<IntentEvent, IntentListener>
+        listenerRegistry = new AbstractListenerRegistry<>();
+
+    private final IntentStoreDelegate delegate = new InternalStoreDelegate();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentStore store;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected EventDeliveryService eventDispatcher;
+
+    @Activate
+    public void activate() {
+        store.setDelegate(delegate);
+        eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
+
+//        this.intentEvents = new IntentMap<>("intentState", IntentEvent.class, collectionsService);
+//        this.installableIntents =
+//                new IntentMap<>("installableIntents", IntentCompilationResult.class, collectionsService);
+//
+//
+//        this.intentEvents.addListener(new InternalEntryListener(new InternalIntentEventListener()));
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        store.unsetDelegate(delegate);
+        eventDispatcher.removeSink(IntentEvent.class);
+        log.info("Stopped");
+    }
+
+    @Override
+    public void submit(Intent intent) {
+        checkNotNull(intent, INTENT_NULL);
+        registerSubclassCompilerIfNeeded(intent);
+        IntentEvent event = store.createIntent(intent);
+        eventDispatcher.post(event);
+        processStoreEvent(event);
+    }
+
+    @Override
+    public void withdraw(Intent intent) {
+        checkNotNull(intent, INTENT_NULL);
+        IntentEvent event = store.setState(intent, WITHDRAWING);
+        eventDispatcher.post(event);
+        processStoreEvent(event);
+    }
+
+    // FIXME: implement this method
+    @Override
+    public void execute(IntentOperations operations) {
+        throw new UnsupportedOperationException("execute() is not implemented yet");
+    }
+
+    @Override
+    public Iterable<Intent> getIntents() {
+        return store.getIntents();
+    }
+
+    @Override
+    public long getIntentCount() {
+        return store.getIntentCount();
+    }
+
+    @Override
+    public Intent getIntent(IntentId id) {
+        checkNotNull(id, INTENT_ID_NULL);
+        return store.getIntent(id);
+    }
+
+    @Override
+    public IntentState getIntentState(IntentId id) {
+        checkNotNull(id, INTENT_ID_NULL);
+        return store.getIntentState(id);
+    }
+
+    @Override
+    public void addListener(IntentListener listener) {
+        listenerRegistry.addListener(listener);
+    }
+
+    @Override
+    public void removeListener(IntentListener listener) {
+        listenerRegistry.removeListener(listener);
+    }
+
+    @Override
+    public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
+        compilers.put(cls, compiler);
+    }
+
+    @Override
+    public <T extends Intent> void unregisterCompiler(Class<T> cls) {
+        compilers.remove(cls);
+    }
+
+    @Override
+    public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
+        return ImmutableMap.copyOf(compilers);
+    }
+
+    @Override
+    public <T extends InstallableIntent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
+        installers.put(cls, installer);
+    }
+
+    @Override
+    public <T extends InstallableIntent> void unregisterInstaller(Class<T> cls) {
+        installers.remove(cls);
+    }
+
+    @Override
+    public Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> getInstallers() {
+        return ImmutableMap.copyOf(installers);
+    }
+
+    /**
+     * Invokes all of registered intent event listener.
+     *
+     * @param event event supplied to a listener as an argument
+     */
+    private void invokeListeners(IntentEvent event) {
+        for (IntentListener listener : listeners) {
+            listener.event(event);
+        }
+    }
+
+    /**
+     * Returns the corresponding intent compiler to the specified intent.
+     *
+     * @param intent intent
+     * @param <T> the type of intent
+     * @return intent compiler corresponding to the specified intent
+     */
+    private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
+        @SuppressWarnings("unchecked")
+        IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
+        if (compiler == null) {
+            throw new IntentException("no compiler for class " + intent.getClass());
+        }
+        return compiler;
+    }
+
+    /**
+     * Returns the corresponding intent installer to the specified installable intent.
+     * @param intent intent
+     * @param <T> the type of installable intent
+     * @return intent installer corresponding to the specified installable intent
+     */
+    private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) {
+        @SuppressWarnings("unchecked")
+        IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
+        if (installer == null) {
+            throw new IntentException("no installer for class " + intent.getClass());
+        }
+        return installer;
+    }
+
+    /**
+     * Compiles an intent.
+     *
+     * @param intent intent
+     */
+    private void compileIntent(Intent intent) {
+        // FIXME: To make SDN-IP workable ASAP, only single level compilation is implemented
+        // TODO: implement compilation traversing tree structure
+        List<InstallableIntent> installable = new ArrayList<>();
+        for (Intent compiled : getCompiler(intent).compile(intent)) {
+            installable.add((InstallableIntent) compiled);
+        }
+        IntentEvent event = store.addInstallableIntents(intent.getId(), installable);
+        eventDispatcher.post(event);
+        processStoreEvent(event);
+    }
+
+    /**
+     * Installs an intent.
+     *
+     * @param intent intent
+     */
+    private void installIntent(Intent intent) {
+        for (InstallableIntent installable : store.getInstallableIntents(intent.getId())) {
+            registerSubclassInstallerIfNeeded(installable);
+            getInstaller(installable).install(installable);
+        }
+
+        IntentEvent event = store.setState(intent, INSTALLED);
+        eventDispatcher.post(event);
+        processStoreEvent(event);
+
+    }
+
+    /**
+     * Uninstalls an intent.
+     *
+     * @param intent intent
+     */
+    private void uninstallIntent(Intent intent) {
+        for (InstallableIntent installable : store.getInstallableIntents(intent.getId())) {
+            getInstaller(installable).uninstall(installable);
+        }
+
+        store.removeInstalledIntents(intent.getId());
+        store.setState(intent, WITHDRAWN);
+    }
+
+    /**
+     * Registers an intent compiler of the specified intent if an intent compiler
+     * for the intent is not registered. This method traverses the class hierarchy of
+     * the intent. Once an intent compiler for a parent type is found, this method
+     * registers the found intent compiler.
+     *
+     * @param intent intent
+     */
+    private void registerSubclassCompilerIfNeeded(Intent intent) {
+        if (!compilers.containsKey(intent.getClass())) {
+            Class<?> cls = intent.getClass();
+            while (cls != Object.class) {
+                // As long as we're within the Intent class descendants
+                if (Intent.class.isAssignableFrom(cls)) {
+                    IntentCompiler<?> compiler = compilers.get(cls);
+                    if (compiler != null) {
+                        compilers.put(intent.getClass(), compiler);
+                        return;
+                    }
+                }
+                cls = cls.getSuperclass();
+            }
+        }
+    }
+
+    /**
+     * Registers an intent installer of the specified intent if an intent installer
+     * for the intent is not registered. This method traverses the class hierarchy of
+     * the intent. Once an intent installer for a parent type is found, this method
+     * registers the found intent installer.
+     *
+     * @param intent intent
+     */
+    private void registerSubclassInstallerIfNeeded(InstallableIntent intent) {
+        if (!installers.containsKey(intent.getClass())) {
+            Class<?> cls = intent.getClass();
+            while (cls != Object.class) {
+                // As long as we're within the InstallableIntent class descendants
+                if (InstallableIntent.class.isAssignableFrom(cls)) {
+                    IntentInstaller<?> installer = installers.get(cls);
+                    if (installer != null) {
+                        installers.put(intent.getClass(), installer);
+                        return;
+                    }
+                }
+                cls = cls.getSuperclass();
+            }
+        }
+    }
+
+    /**
+     * Handles state transition of submitted intents.
+     */
+    private void processStoreEvent(IntentEvent event) {
+            invokeListeners(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);
+        }
+    }
+
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentRemovalException.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentRemovalException.java
new file mode 100644
index 0000000..5ee4ee4
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentRemovalException.java
@@ -0,0 +1,22 @@
+package org.onlab.onos.net.intent.impl;
+
+import org.onlab.onos.net.intent.IntentException;
+
+/**
+ * An exception thrown when intent removal failed.
+ */
+public class IntentRemovalException extends IntentException {
+    private static final long serialVersionUID = -5259226322037891951L;
+
+    public IntentRemovalException() {
+        super();
+    }
+
+    public IntentRemovalException(String message) {
+        super(message);
+    }
+
+    public IntentRemovalException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
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
new file mode 100644
index 0000000..9202684
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java
@@ -0,0 +1,79 @@
+package org.onlab.onos.net.intent.impl;
+
+import java.util.Iterator;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.Link;
+import org.onlab.onos.net.flow.DefaultFlowRule;
+import org.onlab.onos.net.flow.DefaultTrafficSelector;
+import org.onlab.onos.net.flow.DefaultTrafficTreatment;
+import org.onlab.onos.net.flow.FlowRule;
+import org.onlab.onos.net.flow.FlowRuleService;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.flow.criteria.Criterion;
+import org.onlab.onos.net.intent.IntentExtensionService;
+import org.onlab.onos.net.intent.IntentInstaller;
+import org.onlab.onos.net.intent.PathIntent;
+
+/**
+ * An intent installer for {@link PathIntent}.
+ */
+@Component(immediate = true)
+public class PathIntentInstaller
+        implements IntentInstaller<PathIntent> {
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentExtensionService intentManager;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private FlowRuleService flowRuleService;
+
+    private final ApplicationId appId = ApplicationId.valueOf(1);
+
+    @Activate
+    public void activate() {
+        intentManager.registerInstaller(PathIntent.class, this);
+    }
+
+    @Deactivate
+    public void deactivate() {
+        intentManager.unregisterInstaller(PathIntent.class);
+    }
+
+    @Override
+    public void install(PathIntent intent) {
+        TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder();
+        TrafficSelector selector = intent.getTrafficSelector();
+        for (Criterion c : selector.criteria()) {
+            builder.add(c);
+        }
+
+        Iterator<Link> links = intent.getPath().links().iterator();
+        ConnectPoint prev = links.next().dst();
+        while (links.hasNext()) {
+            builder.matchInport(prev.port());
+            Link link = links.next();
+
+            TrafficTreatment.Builder treat = new DefaultTrafficTreatment.Builder();
+            treat.setOutput(link.src().port());
+
+            FlowRule f = new DefaultFlowRule(link.src().deviceId(),
+                    builder.build(), treat.build(), 0, appId);
+            flowRuleService.applyFlowRules(f);
+
+            prev = link.dst();
+        }
+
+    }
+
+    @Override
+    public void uninstall(PathIntent intent) {
+        //TODO
+    }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathNotFoundException.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathNotFoundException.java
new file mode 100644
index 0000000..a1fd63a
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathNotFoundException.java
@@ -0,0 +1,22 @@
+package org.onlab.onos.net.intent.impl;
+
+import org.onlab.onos.net.intent.IntentException;
+
+/**
+ * An exception thrown when a path is not found.
+ */
+public class PathNotFoundException extends IntentException {
+    private static final long serialVersionUID = -2087045731049914733L;
+
+    public PathNotFoundException() {
+        super();
+    }
+
+    public PathNotFoundException(String message) {
+        super(message);
+    }
+
+    public PathNotFoundException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/UnavailableIdException.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/UnavailableIdException.java
new file mode 100644
index 0000000..fd4f122
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/UnavailableIdException.java
@@ -0,0 +1,34 @@
+package org.onlab.onos.net.intent.impl;
+
+/**
+ * Represents that there is no available IDs.
+ */
+public class UnavailableIdException extends RuntimeException {
+
+    private static final long serialVersionUID = -2287403908433720122L;
+
+    /**
+     * Constructs an exception with no message and no underlying cause.
+     */
+    public UnavailableIdException() {
+    }
+
+    /**
+     * Constructs an exception with the specified message.
+     *
+     * @param message the message describing the specific nature of the error
+     */
+    public UnavailableIdException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an exception with the specified message and the underlying cause.
+     *
+     * @param message the message describing the specific nature of the error
+     * @param cause the underlying cause of this error
+     */
+    public UnavailableIdException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/package-info.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/package-info.java
new file mode 100644
index 0000000..fa8248e
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Intent Service Implementation. TODO
+ */
+package org.onlab.onos.net.intent.impl;
\ No newline at end of file
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java
new file mode 100644
index 0000000..4143548
--- /dev/null
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java
@@ -0,0 +1,107 @@
+package org.onlab.onos.store.trivial.impl;
+
+import static org.onlab.onos.net.intent.IntentState.COMPILED;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.onos.net.intent.InstallableIntent;
+import org.onlab.onos.net.intent.Intent;
+import org.onlab.onos.net.intent.IntentEvent;
+import org.onlab.onos.net.intent.IntentId;
+import org.onlab.onos.net.intent.IntentState;
+import org.onlab.onos.net.intent.IntentStore;
+import org.onlab.onos.net.intent.IntentStoreDelegate;
+import org.onlab.onos.store.AbstractStore;
+import org.slf4j.Logger;
+
+import com.google.common.collect.ImmutableSet;
+
+@Component(immediate = true)
+@Service
+public class SimpleIntentStore
+    extends AbstractStore<IntentEvent, IntentStoreDelegate>
+    implements IntentStore {
+
+    private final Logger log = getLogger(getClass());
+    private final Map<IntentId, Intent> intents = new HashMap<>();
+    private final Map<IntentId, IntentState> states = new HashMap<>();
+    private final Map<IntentId, List<InstallableIntent>> installable = new HashMap<>();
+
+    @Activate
+    public void activate() {
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public IntentEvent createIntent(Intent intent) {
+        intents.put(intent.getId(), intent);
+        return this.setState(intent, IntentState.SUBMITTED);
+    }
+
+    @Override
+    public IntentEvent removeIntent(IntentId intentId) {
+        Intent intent = intents.remove(intentId);
+        installable.remove(intentId);
+        IntentEvent event = this.setState(intent, IntentState.WITHDRAWN);
+        states.remove(intentId);
+        return event;
+    }
+
+    @Override
+    public long getIntentCount() {
+        return intents.size();
+    }
+
+    @Override
+    public Iterable<Intent> getIntents() {
+        return ImmutableSet.copyOf(intents.values());
+    }
+
+    @Override
+    public Intent getIntent(IntentId intentId) {
+        return intents.get(intentId);
+    }
+
+    @Override
+    public IntentState getIntentState(IntentId id) {
+        return states.get(id);
+    }
+
+    // TODO return dispatch event here... replace with state transition methods
+    @Override
+    public IntentEvent setState(Intent intent, IntentState newState) {
+        IntentId id = intent.getId();
+        IntentState oldState = states.get(id);
+        states.put(id, newState);
+        return new IntentEvent(intent, newState, oldState, System.currentTimeMillis());
+    }
+
+    @Override
+    public IntentEvent addInstallableIntents(IntentId intentId, List<InstallableIntent> result) {
+        installable.put(intentId, result);
+        return this.setState(intents.get(intentId), COMPILED);
+    }
+
+    @Override
+    public List<InstallableIntent> getInstallableIntents(IntentId intentId) {
+        return installable.get(intentId);
+    }
+
+    @Override
+    public void removeInstalledIntents(IntentId intentId) {
+        installable.remove(intentId);
+    }
+
+}