Adding Intent Framework API
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/AbstractIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/AbstractIntent.java
new file mode 100644
index 0000000..eefe750
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/AbstractIntent.java
@@ -0,0 +1,49 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * Base intent implementation.
+ */
+public abstract class AbstractIntent implements Intent {
+
+    private final IntentId id;
+
+    /**
+     * Creates a base intent with the specified identifier.
+     *
+     * @param id intent identifier
+     */
+    protected AbstractIntent(IntentId id) {
+        this.id = id;
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected AbstractIntent() {
+        this.id = null;
+    }
+
+    @Override
+    public IntentId getId() {
+        return id;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        AbstractIntent that = (AbstractIntent) o;
+        return id.equals(that.id);
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperation.java b/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperation.java
new file mode 100644
index 0000000..12bd02b
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperation.java
@@ -0,0 +1,98 @@
+package org.onlab.onos.net.intent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A list of BatchOperationEntry.
+ *
+ * @param <T> the enum of operators <br>
+ *        This enum must be defined in each sub-classes.
+ *
+ */
+public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> {
+    private List<T> ops;
+
+    /**
+     * Creates new {@link BatchOperation} object.
+     */
+    public BatchOperation() {
+        ops = new LinkedList<>();
+    }
+
+    /**
+     * Creates {@link BatchOperation} object from a list of batch operation
+     * entries.
+     *
+     * @param batchOperations the list of batch operation entries.
+     */
+    public BatchOperation(List<T> batchOperations) {
+        ops = new LinkedList<>(checkNotNull(batchOperations));
+    }
+
+    /**
+     * Removes all operations maintained in this object.
+     */
+    public void clear() {
+        ops.clear();
+    }
+
+    /**
+     * Returns the number of operations in this object.
+     *
+     * @return the number of operations in this object
+     */
+    public int size() {
+        return ops.size();
+    }
+
+    /**
+     * Returns the operations in this object.
+     *
+     * @return the operations in this object
+     */
+    public List<T> getOperations() {
+        return Collections.unmodifiableList(ops);
+    }
+
+    /**
+     * Adds an operation.
+     *
+     * @param entry the operation to be added
+     * @return this object if succeeded, null otherwise
+     */
+    public BatchOperation<T> addOperation(T entry) {
+        return ops.add(entry) ? this : null;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (o == null) {
+            return false;
+        }
+
+        if (getClass() != o.getClass()) {
+            return false;
+        }
+        BatchOperation<?> other = (BatchOperation<?>) o;
+
+        return this.ops.equals(other.ops);
+    }
+
+    @Override
+    public int hashCode() {
+        return ops.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return ops.toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationEntry.java b/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationEntry.java
new file mode 100644
index 0000000..781e3d1
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationEntry.java
@@ -0,0 +1,81 @@
+package org.onlab.onos.net.intent;
+
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * A super class for batch operation entry classes.
+ * <p>
+ * This is the interface to classes which are maintained by BatchOperation as
+ * its entries.
+ */
+public class BatchOperationEntry<T extends Enum<?>, U extends BatchOperationTarget> {
+    private final T operator;
+    private final U target;
+
+    /**
+     * Default constructor for serializer.
+     */
+    @Deprecated
+    protected BatchOperationEntry() {
+        this.operator = null;
+        this.target = null;
+    }
+
+    /**
+     * Constructs new instance for the entry of the BatchOperation.
+     *
+     * @param operator the operator of this operation
+     * @param target the target object of this operation
+     */
+    public BatchOperationEntry(T operator, U target) {
+        this.operator = operator;
+        this.target = target;
+    }
+
+    /**
+     * Gets the target object of this operation.
+     *
+     * @return the target object of this operation
+     */
+    public U getTarget() {
+        return target;
+    }
+
+    /**
+     * Gets the operator of this operation.
+     *
+     * @return the operator of this operation
+     */
+    public T getOperator() {
+        return operator;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        BatchOperationEntry<?, ?> other = (BatchOperationEntry<?, ?>) o;
+        return (this.operator == other.operator) &&
+            Objects.equals(this.target, other.target);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(operator, target);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("operator", operator)
+            .add("target", target)
+            .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationTarget.java b/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationTarget.java
new file mode 100644
index 0000000..5583240
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationTarget.java
@@ -0,0 +1,8 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * An interface of the class which is assigned to BatchOperation.
+ */
+public interface BatchOperationTarget {
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/ConnectivityIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/ConnectivityIntent.java
new file mode 100644
index 0000000..629a9d1
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/ConnectivityIntent.java
@@ -0,0 +1,84 @@
+package org.onlab.onos.net.intent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+
+import com.google.common.base.Objects;
+
+/**
+ * Abstraction of connectivity intent for traffic matching some criteria.
+ */
+public abstract class ConnectivityIntent extends AbstractIntent {
+
+    // TODO: other forms of intents should be considered for this family:
+    //   point-to-point with constraints (waypoints/obstacles)
+    //   multi-to-single point with constraints (waypoints/obstacles)
+    //   single-to-multi point with constraints (waypoints/obstacles)
+    //   concrete path (with alternate)
+    //   ...
+
+    private final TrafficSelector selector;
+    // TODO: should consider which is better for multiple actions,
+    // defining compound action class or using list of actions.
+    private final TrafficTreatment treatment;
+
+    /**
+     * Creates a connectivity intent that matches on the specified intent
+     * and applies the specified action.
+     *
+     * @param id    intent identifier
+     * @param match traffic match
+     * @param action action
+     * @throws NullPointerException if the match or action is null
+     */
+    protected ConnectivityIntent(IntentId id, TrafficSelector match, TrafficTreatment action) {
+        super(id);
+        this.selector = checkNotNull(match);
+        this.treatment = checkNotNull(action);
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected ConnectivityIntent() {
+        super();
+        this.selector = null;
+        this.treatment = null;
+    }
+
+    /**
+     * Returns the match specifying the type of traffic.
+     *
+     * @return traffic match
+     */
+    public TrafficSelector getTrafficSelector() {
+        return selector;
+    }
+
+    /**
+     * Returns the action applied to the traffic.
+     *
+     * @return applied action
+     */
+    public TrafficTreatment getTrafficTreatment() {
+        return treatment;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!super.equals(o)) {
+            return false;
+        }
+        ConnectivityIntent that = (ConnectivityIntent) o;
+        return Objects.equal(this.selector, that.selector)
+                && Objects.equal(this.treatment, that.treatment);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(super.hashCode(), selector, treatment);
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/InstallableIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/InstallableIntent.java
new file mode 100644
index 0000000..66bc759
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/InstallableIntent.java
@@ -0,0 +1,8 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * Abstraction of an intent that can be installed into
+ * the underlying system without additional compilation.
+ */
+public interface InstallableIntent extends Intent {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/Intent.java b/core/api/src/main/java/org/onlab/onos/net/intent/Intent.java
new file mode 100644
index 0000000..b239ede
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/Intent.java
@@ -0,0 +1,15 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * Abstraction of an application level intent.
+ *
+ * Make sure that an Intent should be immutable when a new type is defined.
+ */
+public interface Intent extends BatchOperationTarget {
+    /**
+     * Returns the intent identifier.
+     *
+     * @return intent identifier
+     */
+    IntentId getId();
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchOperation.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchOperation.java
new file mode 100644
index 0000000..b450d71
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchOperation.java
@@ -0,0 +1,39 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * A list of intent operations.
+ */
+public class IntentBatchOperation extends
+        BatchOperation<BatchOperationEntry<IntentBatchOperation.Operator, ?>> {
+    /**
+     * The intent operators.
+     */
+    public enum Operator {
+        ADD,
+        REMOVE,
+    }
+
+    /**
+     * Adds an add-intent operation.
+     *
+     * @param intent the intent to be added
+     * @return the IntentBatchOperation object if succeeded, null otherwise
+     */
+    public IntentBatchOperation addAddIntentOperation(Intent intent) {
+        return (null == super.addOperation(
+                new BatchOperationEntry<Operator, Intent>(Operator.ADD, intent)))
+                ? null : this;
+    }
+
+    /**
+     * Adds a remove-intent operation.
+     *
+     * @param id the ID of intent to be removed
+     * @return the IntentBatchOperation object if succeeded, null otherwise
+     */
+    public IntentBatchOperation addRemoveIntentOperation(IntentId id) {
+        return (null == super.addOperation(
+                new BatchOperationEntry<Operator, IntentId>(Operator.REMOVE, id)))
+                ? null : this;
+    }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java
new file mode 100644
index 0000000..dbc3cc4
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java
@@ -0,0 +1,20 @@
+package org.onlab.onos.net.intent;
+
+import java.util.List;
+
+/**
+ * Abstraction of a compiler which is capable of taking an intent
+ * and translating it to other, potentially installable, intents.
+ *
+ * @param <T> the type of intent
+ */
+public interface IntentCompiler<T extends Intent> {
+    /**
+     * Compiles the specified intent into other intents.
+     *
+     * @param intent intent to be compiled
+     * @return list of resulting intents
+     * @throws IntentException if issues are encountered while compiling the intent
+     */
+    List<Intent> compile(T intent);
+}
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
new file mode 100644
index 0000000..27ae834
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentEvent.java
@@ -0,0 +1,113 @@
+package org.onlab.onos.net.intent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * A class to represent an intent related event.
+ */
+public class IntentEvent {
+
+    // TODO: determine a suitable parent class; if one does not exist, consider introducing one
+
+    private final long time;
+    private final Intent intent;
+    private final IntentState state;
+    private final IntentState previous;
+
+    /**
+     * Creates an event describing a state change of an intent.
+     *
+     * @param intent subject intent
+     * @param state new intent state
+     * @param previous previous intent state
+     * @param time time the event created in milliseconds since start of epoch
+     * @throws NullPointerException if the intent or state is null
+     */
+    public IntentEvent(Intent intent, IntentState state, IntentState previous, long time) {
+        this.intent = checkNotNull(intent);
+        this.state = checkNotNull(state);
+        this.previous = previous;
+        this.time = time;
+    }
+
+    /**
+     * 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
+     */
+    public IntentState getState() {
+        return state;
+    }
+
+    /**
+     * Returns the previous state of the intent which caused the event.
+     *
+     * @return the previous state of the intent
+     */
+    public IntentState getPreviousState() {
+        return previous;
+    }
+
+    /**
+     * Returns the intent associated with the event.
+     *
+     * @return the intent
+     */
+    public Intent getIntent() {
+        return intent;
+    }
+
+    /**
+     * Returns the time at which the event was created.
+     *
+     * @return the time in milliseconds since start of epoch
+     */
+    public long getTime() {
+        return time;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        IntentEvent that = (IntentEvent) o;
+        return Objects.equals(this.intent, that.intent)
+                && Objects.equals(this.state, that.state)
+                && Objects.equals(this.previous, that.previous)
+                && Objects.equals(this.time, that.time);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(intent, state, previous, time);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("intent", intent)
+                .add("state", state)
+                .add("previous", previous)
+                .add("time", time)
+                .toString();
+    }
+}
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
new file mode 100644
index 0000000..f59ecfc
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentEventListener.java
@@ -0,0 +1,13 @@
+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/IntentException.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentException.java
new file mode 100644
index 0000000..4148dea
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentException.java
@@ -0,0 +1,35 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * Represents an intent related error.
+ */
+public class IntentException extends RuntimeException {
+
+    private static final long serialVersionUID = 1907263634145241319L;
+
+    /**
+     * Constructs an exception with no message and no underlying cause.
+     */
+    public IntentException() {
+    }
+
+    /**
+     * Constructs an exception with the specified message.
+     *
+     * @param message the message describing the specific nature of the error
+     */
+    public IntentException(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 IntentException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentExtensionService.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentExtensionService.java
new file mode 100644
index 0000000..c6338a7f
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentExtensionService.java
@@ -0,0 +1,57 @@
+package org.onlab.onos.net.intent;
+
+import java.util.Map;
+
+/**
+ * Service for extending the capability of intent framework by
+ * adding additional compilers or/and installers.
+ */
+public interface IntentExtensionService {
+    /**
+     * Registers the specified compiler for the given intent class.
+     *
+     * @param cls intent class
+     * @param compiler intent compiler
+     * @param <T> the type of intent
+     */
+    <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler);
+
+    /**
+     * Unregisters the compiler for the specified intent class.
+     *
+     * @param cls intent class
+     * @param <T> the type of intent
+     */
+    <T extends Intent> void unregisterCompiler(Class<T> cls);
+
+    /**
+     * Returns immutable set of bindings of currently registered intent compilers.
+     *
+     * @return the set of compiler bindings
+     */
+    Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers();
+
+    /**
+     * Registers the specified installer for the given installable intent class.
+     *
+     * @param cls installable intent class
+     * @param installer intent installer
+     * @param <T> the type of installable intent
+     */
+    <T extends InstallableIntent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer);
+
+    /**
+     * Unregisters the installer for the given installable intent class.
+     *
+     * @param cls installable intent class
+     * @param <T> the type of installable intent
+     */
+    <T extends InstallableIntent> void unregisterInstaller(Class<T> cls);
+
+    /**
+     * Returns immutable set of bindings of currently registered intent installers.
+     *
+     * @return the set of installer bindings
+     */
+    Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> getInstallers();
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentId.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentId.java
new file mode 100644
index 0000000..798e00c
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentId.java
@@ -0,0 +1,68 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * Intent identifier suitable as an external key.
+ *
+ * This class is immutable.
+ */
+public final class IntentId implements BatchOperationTarget {
+
+    private static final int DEC = 10;
+    private static final int HEX = 16;
+
+    private final long id;
+
+    /**
+     * Creates an intent identifier from the specified string representation.
+     *
+     * @param value long value
+     * @return intent identifier
+     */
+    public static IntentId valueOf(String value) {
+        long id = value.toLowerCase().startsWith("0x")
+                ? Long.parseLong(value.substring(2), HEX)
+                : Long.parseLong(value, DEC);
+        return new IntentId(id);
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected IntentId() {
+        this.id = 0;
+    }
+
+    /**
+     * Constructs the ID corresponding to a given long value.
+     *
+     * @param id the underlying value of this ID
+     */
+    public IntentId(long id) {
+        this.id = id;
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) (id ^ (id >>> 32));
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (!(obj instanceof IntentId)) {
+            return false;
+        }
+
+        IntentId that = (IntentId) obj;
+        return this.id == that.id;
+    }
+
+    @Override
+    public String toString() {
+        return "0x" + Long.toHexString(id);
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java
new file mode 100644
index 0000000..738be04
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java
@@ -0,0 +1,22 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * Abstraction of entity capable of installing intents to the environment.
+ */
+public interface IntentInstaller<T extends InstallableIntent> {
+    /**
+     * Installs the specified intent to the environment.
+     *
+     * @param intent intent to be installed
+     * @throws IntentException if issues are encountered while installing the intent
+     */
+    void install(T intent);
+
+    /**
+     * Uninstalls the specified intent from the environment.
+     *
+     * @param intent intent to be uninstalled
+     * @throws IntentException if issues are encountered while uninstalling the intent
+     */
+    void uninstall(T intent);
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java
new file mode 100644
index 0000000..470d98b
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java
@@ -0,0 +1,10 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * Abstraction of a batch of intent submit/withdraw operations.
+ */
+public interface IntentOperations {
+
+    // TODO: elaborate once the revised BatchOperation scheme is in place
+
+}
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
new file mode 100644
index 0000000..2b4fb59
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java
@@ -0,0 +1,76 @@
+package org.onlab.onos.net.intent;
+
+import java.util.Set;
+
+/**
+ * Service for application submitting or withdrawing their intents.
+ */
+public interface IntentService {
+    /**
+     * Submits an intent into the system.
+     *
+     * This is an asynchronous request meaning that any compiling
+     * or installation activities may be done at later time.
+     *
+     * @param intent intent to be submitted
+     */
+    void submit(Intent intent);
+
+    /**
+     * Withdraws an intent from the system.
+     *
+     * This is an asynchronous request meaning that the environment
+     * may be affected at later time.
+     *
+     * @param intent intent to be withdrawn
+     */
+    void withdraw(Intent intent);
+
+    /**
+     * 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.
+     *
+     * @param operations batch of intent operations
+     */
+    void execute(IntentOperations operations);
+
+    /**
+     * Returns immutable set of intents currently in the system.
+     *
+     * @return set of intents
+     */
+    Set<Intent> getIntents();
+
+    /**
+     * Retrieves the intent specified by its identifier.
+     *
+     * @param id intent identifier
+     * @return the intent or null if one with the given identifier is not found
+     */
+    Intent getIntent(IntentId id);
+
+    /**
+     * 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
+     */
+    IntentState getIntentState(IntentId id);
+
+    /**
+     * Adds the specified listener for intent events.
+     *
+     * @param listener listener to be added
+     */
+    void addListener(IntentEventListener listener);
+
+    /**
+     * Removes the specified listener for intent events.
+     *
+     * @param listener listener to be removed
+     */
+    void removeListener(IntentEventListener listener);
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentState.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentState.java
new file mode 100644
index 0000000..20476e5
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentState.java
@@ -0,0 +1,55 @@
+package org.onlab.onos.net.intent;
+
+/**
+ * This class represents the states of an intent.
+ *
+ * <p>
+ * Note: The state is expressed as enum, but there is possibility
+ * in the future that we define specific class instead of enum to improve
+ * the extensibility of state definition.
+ * </p>
+ */
+public enum IntentState {
+    // FIXME: requires discussion on State vs. EventType and a solid state-transition diagram
+    // TODO: consider the impact of conflict detection
+    // TODO: consider the impact that external events affect an installed intent
+    /**
+     * The beginning state.
+     *
+     * All intent in the runtime take this state first.
+     */
+    SUBMITTED,
+
+    /**
+     * The intent compilation has been completed.
+     *
+     * An intent translation graph (tree) is completely created.
+     * Leaves of the graph are installable intent type.
+     */
+    COMPILED,
+
+    /**
+     * The intent has been successfully installed.
+     */
+    INSTALLED,
+
+    /**
+     * The intent is being withdrawn.
+     *
+     * When {@link IntentService#withdraw(Intent)} is called,
+     * the intent takes this state first.
+     */
+    WITHDRAWING,
+
+    /**
+     * The intent has been successfully withdrawn.
+     */
+    WITHDRAWN,
+
+    /**
+     * The intent has failed to be compiled, installed, or withdrawn.
+     *
+     * When the intent failed to be withdrawn, it is still, at least partially installed.
+     */
+    FAILED,
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntent.java
new file mode 100644
index 0000000..1e421ab
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntent.java
@@ -0,0 +1,110 @@
+package org.onlab.onos.net.intent;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+import java.util.Set;
+
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Sets;
+
+/**
+ * Abstraction of multiple source to single destination connectivity intent.
+ */
+public class MultiPointToSinglePointIntent extends ConnectivityIntent {
+
+    private final Set<ConnectPoint> ingressPorts;
+    private final ConnectPoint egressPort;
+
+    /**
+     * Creates a new multi-to-single point connectivity intent for the specified
+     * traffic match and action.
+     *
+     * @param id           intent identifier
+     * @param match        traffic match
+     * @param action       action
+     * @param ingressPorts set of ports from which ingress traffic originates
+     * @param egressPort   port to which traffic will egress
+     * @throws NullPointerException if {@code ingressPorts} or
+     * {@code egressPort} is null.
+     * @throws IllegalArgumentException if the size of {@code ingressPorts} is
+     * not more than 1
+     */
+    public MultiPointToSinglePointIntent(IntentId id, TrafficSelector match, TrafficTreatment action,
+            Set<ConnectPoint> ingressPorts, ConnectPoint egressPort) {
+        super(id, match, action);
+
+        checkNotNull(ingressPorts);
+        checkArgument(!ingressPorts.isEmpty(),
+                "there should be at least one ingress port");
+
+        this.ingressPorts = Sets.newHashSet(ingressPorts);
+        this.egressPort = checkNotNull(egressPort);
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected MultiPointToSinglePointIntent() {
+        super();
+        this.ingressPorts = null;
+        this.egressPort = null;
+    }
+
+    /**
+     * Returns the set of ports on which ingress traffic should be connected to
+     * the egress port.
+     *
+     * @return set of ingress ports
+     */
+    public Set<ConnectPoint> getIngressPorts() {
+        return ingressPorts;
+    }
+
+    /**
+     * Returns the port on which the traffic should egress.
+     *
+     * @return egress port
+     */
+    public ConnectPoint getEgressPort() {
+        return egressPort;
+    }
+
+    @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;
+        }
+
+        MultiPointToSinglePointIntent that = (MultiPointToSinglePointIntent) o;
+        return Objects.equals(this.ingressPorts, that.ingressPorts)
+                && Objects.equals(this.egressPort, that.egressPort);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), ingressPorts, egressPort);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("id", getId())
+                .add("match", getTrafficSelector())
+                .add("action", getTrafficTreatment())
+                .add("ingressPorts", getIngressPorts())
+                .add("egressPort", getEgressPort())
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/OpticalConnectivityIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/OpticalConnectivityIntent.java
new file mode 100644
index 0000000..d11dc7c
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/OpticalConnectivityIntent.java
@@ -0,0 +1,58 @@
+package org.onlab.onos.net.intent;
+
+import org.onlab.onos.net.ConnectPoint;
+
+// TODO: consider if this intent should be sub-class of ConnectivityIntent
+/**
+ * An optical layer Intent for a connectivity from a transponder port to another
+ * transponder port.
+ * <p>
+ * This class doesn't accepts lambda specifier. This class computes path between
+ * ports and assign lambda automatically. The lambda can be specified using
+ * OpticalPathFlow class.
+ */
+public class OpticalConnectivityIntent extends AbstractIntent {
+    protected ConnectPoint srcConnectPoint;
+    protected ConnectPoint dstConnectPoint;
+
+    /**
+     * Constructor.
+     *
+     * @param id ID for this new Intent object.
+     * @param srcConnectPoint The source transponder port.
+     * @param dstConnectPoint The destination transponder port.
+     */
+    public OpticalConnectivityIntent(IntentId id,
+            ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) {
+        super(id);
+        this.srcConnectPoint = srcConnectPoint;
+        this.dstConnectPoint = dstConnectPoint;
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected OpticalConnectivityIntent() {
+        super();
+        this.srcConnectPoint = null;
+        this.dstConnectPoint = null;
+    }
+
+    /**
+     * Gets source transponder port.
+     *
+     * @return The source transponder port.
+     */
+    public ConnectPoint getSrcConnectPoint() {
+        return srcConnectPoint;
+    }
+
+    /**
+     * Gets destination transponder port.
+     *
+     * @return The source transponder port.
+     */
+    public ConnectPoint getDstConnectPoint() {
+        return dstConnectPoint;
+    }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/PacketConnectivityIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/PacketConnectivityIntent.java
new file mode 100644
index 0000000..893d70e
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/PacketConnectivityIntent.java
@@ -0,0 +1,177 @@
+package org.onlab.onos.net.intent;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.flow.TrafficSelector;
+
+// TODO: consider if this intent should be sub-class of Connectivity intent
+/**
+ * A packet layer Intent for a connectivity from a set of ports to a set of
+ * ports.
+ * <p>
+ * TODO: Design methods to support the ReactiveForwarding and the SDN-IP. <br>
+ * NOTE: Should this class support modifier methods? Should this object a
+ * read-only object?
+ */
+public class PacketConnectivityIntent extends AbstractIntent {
+    protected Set<ConnectPoint> srcConnectPoints;
+    protected TrafficSelector selector;
+    protected Set<ConnectPoint> dstConnectPoints;
+    protected boolean canSetupOpticalFlow;
+    protected int idleTimeoutValue;
+    protected int hardTimeoutValue;
+
+    /**
+     * Creates a connectivity intent for the packet layer.
+     * <p>
+     * When the "canSetupOpticalFlow" option is true, this intent will compute
+     * the packet/optical converged path, decompose it to the OpticalPathFlow
+     * and the PacketPathFlow objects, and execute the operations to add them
+     * considering the dependency between the packet and optical layers.
+     *
+     * @param id ID for this new Intent object.
+     * @param srcConnectPoints The set of source switch ports.
+     * @param match Traffic specifier for this object.
+     * @param dstConnectPoints The set of destination switch ports.
+     * @param canSetupOpticalFlow The flag whether this intent can create
+     *        optical flows if needed.
+     */
+    public PacketConnectivityIntent(IntentId id,
+            Collection<ConnectPoint> srcConnectPoints, TrafficSelector match,
+            Collection<ConnectPoint> dstConnectPoints, boolean canSetupOpticalFlow) {
+        super(id);
+        this.srcConnectPoints = new HashSet<ConnectPoint>(srcConnectPoints);
+        this.selector = match;
+        this.dstConnectPoints = new HashSet<ConnectPoint>(dstConnectPoints);
+        this.canSetupOpticalFlow = canSetupOpticalFlow;
+        this.idleTimeoutValue = 0;
+        this.hardTimeoutValue = 0;
+
+        // TODO: check consistency between these parameters.
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected PacketConnectivityIntent() {
+        super();
+        this.srcConnectPoints = null;
+        this.selector = null;
+        this.dstConnectPoints = null;
+        this.canSetupOpticalFlow = false;
+        this.idleTimeoutValue = 0;
+        this.hardTimeoutValue = 0;
+    }
+
+    /**
+     * Gets the set of source switch ports.
+     *
+     * @return the set of source switch ports.
+     */
+    public Collection<ConnectPoint> getSrcConnectPoints() {
+        return Collections.unmodifiableCollection(srcConnectPoints);
+    }
+
+    /**
+     * Gets the traffic specifier.
+     *
+     * @return The traffic specifier.
+     */
+    public TrafficSelector getMatch() {
+        return selector;
+    }
+
+    /**
+     * Gets the set of destination switch ports.
+     *
+     * @return the set of destination switch ports.
+     */
+    public Collection<ConnectPoint> getDstConnectPoints() {
+        return Collections.unmodifiableCollection(dstConnectPoints);
+    }
+
+    /**
+     * Adds the specified port to the set of source ports.
+     *
+     * @param port ConnectPoint object to be added
+     */
+    public void addSrcConnectPoint(ConnectPoint port) {
+        // TODO implement it.
+    }
+
+    /**
+     * Adds the specified port to the set of destination ports.
+     *
+     * @param port ConnectPoint object to be added
+     */
+    public void addDstConnectPoint(ConnectPoint port) {
+        // TODO implement it.
+    }
+
+    /**
+     * Removes the specified port from the set of source ports.
+     *
+     * @param port ConnectPoint object to be removed
+     */
+    public void removeSrcConnectPoint(ConnectPoint port) {
+        // TODO implement it.
+    }
+
+    /**
+     * Removes the specified port from the set of destination ports.
+     *
+     * @param port ConnectPoint object to be removed
+     */
+    public void removeDstConnectPoint(ConnectPoint port) {
+        // TODO implement it.
+    }
+
+    /**
+     * Sets idle-timeout value.
+     *
+     * @param timeout Idle-timeout value (seconds)
+     */
+    public void setIdleTimeout(int timeout) {
+        idleTimeoutValue = timeout;
+    }
+
+    /**
+     * Sets hard-timeout value.
+     *
+     * @param timeout Hard-timeout value (seconds)
+     */
+    public void setHardTimeout(int timeout) {
+        hardTimeoutValue = timeout;
+    }
+
+    /**
+     * Gets idle-timeout value.
+     *
+     * @return Idle-timeout value (seconds)
+     */
+    public int getIdleTimeout() {
+        return idleTimeoutValue;
+    }
+
+    /**
+     * Gets hard-timeout value.
+     *
+     * @return Hard-timeout value (seconds)
+     */
+    public int getHardTimeout() {
+        return hardTimeoutValue;
+    }
+
+    /**
+     * Returns whether this intent can create optical flows if needed.
+     *
+     * @return whether this intent can create optical flows.
+     */
+    public boolean canSetupOpticalFlow() {
+        return canSetupOpticalFlow;
+    }
+}
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
new file mode 100644
index 0000000..39ad011
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
@@ -0,0 +1,89 @@
+package org.onlab.onos.net.intent;
+
+import java.util.Objects;
+
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.Path;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Abstraction of explicitly path specified connectivity intent.
+ */
+public class PathIntent extends PointToPointIntent {
+
+    private final Path path;
+
+    /**
+     * Creates a new point-to-point intent with the supplied ingress/egress
+     * ports and using the specified explicit path.
+     *
+     * @param id          intent identifier
+     * @param match       traffic match
+     * @param action      action
+     * @param ingressPort ingress port
+     * @param egressPort  egress port
+     * @param path        traversed links
+     * @throws NullPointerException {@code path} is null
+     */
+    public PathIntent(IntentId id, TrafficSelector match, TrafficTreatment action,
+                      ConnectPoint ingressPort, ConnectPoint egressPort,
+                      Path path) {
+        super(id, match, action, ingressPort, egressPort);
+        this.path = path;
+    }
+
+    protected PathIntent() {
+        super();
+        this.path = null;
+    }
+
+    /**
+     * Returns the links which the traffic goes along.
+     *
+     * @return traversed links
+     */
+    public Path getPath() {
+        return path;
+    }
+
+    @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;
+        }
+
+        PathIntent that = (PathIntent) o;
+
+        if (!path.equals(that.path)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), path);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("id", getId())
+                .add("match", getTrafficSelector())
+                .add("action", getTrafficTreatment())
+                .add("ingressPort", getIngressPort())
+                .add("egressPort", getEgressPort())
+                .add("path", path)
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntent.java
new file mode 100644
index 0000000..b1d18ee
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntent.java
@@ -0,0 +1,100 @@
+package org.onlab.onos.net.intent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+
+import org.onlab.onos.net.ConnectPoint;
+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 PointToPointIntent extends ConnectivityIntent {
+
+    private final ConnectPoint ingressPort;
+    private final ConnectPoint egressPort;
+
+    /**
+     * 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 PointToPointIntent(IntentId id, TrafficSelector match, TrafficTreatment action,
+                              ConnectPoint ingressPort, ConnectPoint egressPort) {
+        super(id, match, action);
+        this.ingressPort = checkNotNull(ingressPort);
+        this.egressPort = checkNotNull(egressPort);
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected PointToPointIntent() {
+        super();
+        this.ingressPort = null;
+        this.egressPort = null;
+    }
+
+    /**
+     * Returns the port on which the ingress traffic should be connected to
+     * the egress.
+     *
+     * @return ingress port
+     */
+    public ConnectPoint getIngressPort() {
+        return ingressPort;
+    }
+
+    /**
+     * Returns the port on which the traffic should egress.
+     *
+     * @return egress port
+     */
+    public ConnectPoint getEgressPort() {
+        return egressPort;
+    }
+
+    @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;
+        }
+
+        PointToPointIntent that = (PointToPointIntent) o;
+        return Objects.equals(this.ingressPort, that.ingressPort)
+                && Objects.equals(this.egressPort, that.egressPort);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), ingressPort, egressPort);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("id", getId())
+                .add("match", getTrafficSelector())
+                .add("action", getTrafficTreatment())
+                .add("ingressPort", ingressPort)
+                .add("egressPort", egressPort)
+                .toString();
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java
new file mode 100644
index 0000000..e69a740
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java
@@ -0,0 +1,110 @@
+package org.onlab.onos.net.intent;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Objects;
+import java.util.Set;
+
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Sets;
+
+/**
+ * Abstraction of single source, multiple destination connectivity intent.
+ */
+public class SinglePointToMultiPointIntent extends ConnectivityIntent {
+
+    private final ConnectPoint ingressPort;
+    private final Set<ConnectPoint> egressPorts;
+
+    /**
+     * Creates a new single-to-multi point connectivity intent.
+     *
+     * @param id          intent identifier
+     * @param match       traffic match
+     * @param action      action
+     * @param ingressPort port on which traffic will ingress
+     * @param egressPorts set of ports on which traffic will egress
+     * @throws NullPointerException if {@code ingressPort} or
+     * {@code egressPorts} is null
+     * @throws IllegalArgumentException if the size of {@code egressPorts} is
+     * not more than 1
+     */
+    public SinglePointToMultiPointIntent(IntentId id, TrafficSelector match, TrafficTreatment action,
+                                         ConnectPoint ingressPort,
+                                         Set<ConnectPoint> egressPorts) {
+        super(id, match, action);
+
+        checkNotNull(egressPorts);
+        checkArgument(!egressPorts.isEmpty(),
+                "there should be at least one egress port");
+
+        this.ingressPort = checkNotNull(ingressPort);
+        this.egressPorts = Sets.newHashSet(egressPorts);
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected SinglePointToMultiPointIntent() {
+        super();
+        this.ingressPort = null;
+        this.egressPorts = null;
+    }
+
+    /**
+     * Returns the port on which the ingress traffic should be connected to the egress.
+     *
+     * @return ingress port
+     */
+    public ConnectPoint getIngressPort() {
+        return ingressPort;
+    }
+
+    /**
+     * Returns the set of ports on which the traffic should egress.
+     *
+     * @return set of egress ports
+     */
+    public Set<ConnectPoint> getEgressPorts() {
+        return egressPorts;
+    }
+
+    @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;
+        }
+
+        SinglePointToMultiPointIntent that = (SinglePointToMultiPointIntent) o;
+        return Objects.equals(this.ingressPort, that.ingressPort)
+                && Objects.equals(this.egressPorts, that.egressPorts);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), ingressPort, egressPorts);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("id", getId())
+                .add("match", getTrafficSelector())
+                .add("action", getTrafficTreatment())
+                .add("ingressPort", ingressPort)
+                .add("egressPort", egressPorts)
+                .toString();
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/package-info.java b/core/api/src/main/java/org/onlab/onos/net/intent/package-info.java
new file mode 100644
index 0000000..e1e6782
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Intent Package. TODO
+ */
+
+package org.onlab.onos.net.intent;
\ No newline at end of file