Define the new Intent Framework APIs (Intent Service)
- Define the base Intent class and sub-classes required in SDN-IP
- IntentService provides the APIs for application developers
- IntentExtensionService enables to define application specific intent types
- Provide event handling mechanism via IntentEventListener
This is for ONOS-1654.
Change-Id: Id1705f1fbc1acd4862b33fd9ab97aafe2e84a685
diff --git a/src/main/java/net/onrc/onos/api/newintent/AbstractIntent.java b/src/main/java/net/onrc/onos/api/newintent/AbstractIntent.java
new file mode 100644
index 0000000..f2e3d8a
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/AbstractIntent.java
@@ -0,0 +1,42 @@
+package net.onrc.onos.api.newintent;
+
+/**
+ * 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;
+ }
+
+ @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/src/main/java/net/onrc/onos/api/newintent/ConnectivityIntent.java b/src/main/java/net/onrc/onos/api/newintent/ConnectivityIntent.java
new file mode 100644
index 0000000..ecb1d6b
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/ConnectivityIntent.java
@@ -0,0 +1,74 @@
+package net.onrc.onos.api.newintent;
+
+import com.google.common.base.Objects;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.match.Match;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * 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 Match match;
+ // TODO: should consider which is better for multiple actions,
+ // defining compound action class or using list of actions.
+ private final Action action;
+
+ /**
+ * 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, Match match, Action action) {
+ super(id);
+ this.match = checkNotNull(match);
+ this.action = checkNotNull(action);
+ }
+
+ /**
+ * Returns the match specifying the type of traffic.
+ *
+ * @return traffic match
+ */
+ public Match getMatch() {
+ return match;
+ }
+
+ /**
+ * Returns the action applied to the traffic.
+ *
+ * @return applied action
+ */
+ public Action getAction() {
+ return action;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!super.equals(o)) {
+ return false;
+ }
+ ConnectivityIntent that = (ConnectivityIntent) o;
+ return Objects.equal(this.match, that.match)
+ && Objects.equal(this.action, that.action);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), match, action);
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/api/newintent/InstallableIntent.java b/src/main/java/net/onrc/onos/api/newintent/InstallableIntent.java
new file mode 100644
index 0000000..b31375d
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/InstallableIntent.java
@@ -0,0 +1,8 @@
+package net.onrc.onos.api.newintent;
+
+/**
+ * Abstraction of an intent that can be installed into
+ * the underlying system without additional compilation.
+ */
+public interface InstallableIntent extends Intent {
+}
diff --git a/src/main/java/net/onrc/onos/api/newintent/Intent.java b/src/main/java/net/onrc/onos/api/newintent/Intent.java
new file mode 100644
index 0000000..009725c
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/Intent.java
@@ -0,0 +1,15 @@
+package net.onrc.onos.api.newintent;
+
+/**
+ * Abstraction of an application level intent.
+ *
+ * Make sure that an Intent should be immutable when a new type is defined.
+ */
+public interface Intent {
+ /**
+ * Returns the intent identifier.
+ *
+ * @return intent identifier
+ */
+ IntentId getId();
+}
diff --git a/src/main/java/net/onrc/onos/api/newintent/IntentCompiler.java b/src/main/java/net/onrc/onos/api/newintent/IntentCompiler.java
new file mode 100644
index 0000000..c778c11
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentCompiler.java
@@ -0,0 +1,20 @@
+package net.onrc.onos.api.newintent;
+
+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/src/main/java/net/onrc/onos/api/newintent/IntentEvent.java b/src/main/java/net/onrc/onos/api/newintent/IntentEvent.java
new file mode 100644
index 0000000..670e87e
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentEvent.java
@@ -0,0 +1,101 @@
+package net.onrc.onos.api.newintent;
+
+import com.google.common.base.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * 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;
+ }
+
+ /**
+ * 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.equal(this.intent, that.intent)
+ && Objects.equal(this.state, that.state)
+ && Objects.equal(this.previous, that.previous)
+ && Objects.equal(this.time, that.time);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(intent, state, previous, time);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(getClass())
+ .add("intent", intent)
+ .add("state", state)
+ .add("previous", previous)
+ .add("time", time)
+ .toString();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/newintent/IntentEventListener.java b/src/main/java/net/onrc/onos/api/newintent/IntentEventListener.java
new file mode 100644
index 0000000..6d8bda2
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentEventListener.java
@@ -0,0 +1,13 @@
+package net.onrc.onos.api.newintent;
+
+/**
+ * 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/src/main/java/net/onrc/onos/api/newintent/IntentException.java b/src/main/java/net/onrc/onos/api/newintent/IntentException.java
new file mode 100644
index 0000000..fc966ee
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentException.java
@@ -0,0 +1,35 @@
+package net.onrc.onos.api.newintent;
+
+/**
+ * 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/src/main/java/net/onrc/onos/api/newintent/IntentExtensionService.java b/src/main/java/net/onrc/onos/api/newintent/IntentExtensionService.java
new file mode 100644
index 0000000..1686e5f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentExtensionService.java
@@ -0,0 +1,57 @@
+package net.onrc.onos.api.newintent;
+
+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/src/main/java/net/onrc/onos/api/newintent/IntentId.java b/src/main/java/net/onrc/onos/api/newintent/IntentId.java
new file mode 100644
index 0000000..6d10b35
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentId.java
@@ -0,0 +1,62 @@
+package net.onrc.onos.api.newintent;
+
+/**
+ * Intent identifier suitable as an external key.
+ *
+ * This class is immutable.
+ */
+public final class IntentId {
+
+ 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.startsWith("0x")
+ ? Long.parseLong(value.substring(2), HEX)
+ : Long.parseLong(value, DEC);
+ return new IntentId(id);
+ }
+
+
+ /**
+ * 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/src/main/java/net/onrc/onos/api/newintent/IntentInstaller.java b/src/main/java/net/onrc/onos/api/newintent/IntentInstaller.java
new file mode 100644
index 0000000..940d6ab
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentInstaller.java
@@ -0,0 +1,22 @@
+package net.onrc.onos.api.newintent;
+
+/**
+ * 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);
+
+ /**
+ * Removes the specified intent from the environment.
+ *
+ * @param intent intent to be removed
+ * @throws IntentException if issues are encountered while removing the intent
+ */
+ void remove(T intent); // TODO: consider calling this uninstall for symmetry
+}
diff --git a/src/main/java/net/onrc/onos/api/newintent/IntentOperations.java b/src/main/java/net/onrc/onos/api/newintent/IntentOperations.java
new file mode 100644
index 0000000..a556048
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentOperations.java
@@ -0,0 +1,10 @@
+package net.onrc.onos.api.newintent;
+
+/**
+ * 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/src/main/java/net/onrc/onos/api/newintent/IntentService.java b/src/main/java/net/onrc/onos/api/newintent/IntentService.java
new file mode 100644
index 0000000..14fa1dc
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentService.java
@@ -0,0 +1,76 @@
+package net.onrc.onos.api.newintent;
+
+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 & 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/src/main/java/net/onrc/onos/api/newintent/IntentState.java b/src/main/java/net/onrc/onos/api/newintent/IntentState.java
new file mode 100644
index 0000000..f272320
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/IntentState.java
@@ -0,0 +1,55 @@
+package net.onrc.onos.api.newintent;
+
+/**
+ * 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 net.onrc.onos.api.newintent.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/src/main/java/net/onrc/onos/api/newintent/MultiPointToSinglePointIntent.java b/src/main/java/net/onrc/onos/api/newintent/MultiPointToSinglePointIntent.java
new file mode 100644
index 0000000..99c1c02
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/MultiPointToSinglePointIntent.java
@@ -0,0 +1,96 @@
+package net.onrc.onos.api.newintent;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.util.SwitchPort;
+
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Abstraction of multiple source to single destination connectivity intent.
+ */
+public class MultiPointToSinglePointIntent extends ConnectivityIntent {
+
+ private final Set<SwitchPort> ingressPorts;
+ private final SwitchPort 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, Match match, Action action,
+ Set<SwitchPort> ingressPorts, SwitchPort egressPort) {
+ super(id, match, action);
+
+ checkNotNull(ingressPorts);
+ checkArgument(ingressPorts.size() > 1, "the number of ingress ports should be more than 1, " +
+ "but actually %s", ingressPorts.size());
+
+ this.ingressPorts = ImmutableSet.copyOf(ingressPorts);
+ this.egressPort = checkNotNull(egressPort);
+ }
+
+ /**
+ * Returns the set of ports on which ingress traffic should be connected to the egress port.
+ *
+ * @return set of ingress ports
+ */
+ public Set<SwitchPort> getIngressPorts() {
+ return ingressPorts;
+ }
+
+ /**
+ * Returns the port on which the traffic should egress.
+ *
+ * @return egress port
+ */
+ public SwitchPort 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.equal(this.ingressPorts, that.ingressPorts)
+ && Objects.equal(this.egressPort, that.egressPort);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), ingressPorts, egressPort);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(getClass())
+ .add("id", getId())
+ .add("match", getMatch())
+ .add("aciton", getAction())
+ .add("ingressPorts", getIngressPorts())
+ .add("egressPort", getEgressPort())
+ .toString();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/newintent/PathIntent.java b/src/main/java/net/onrc/onos/api/newintent/PathIntent.java
new file mode 100644
index 0000000..db11f4c
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/PathIntent.java
@@ -0,0 +1,86 @@
+package net.onrc.onos.api.newintent;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.util.LinkTuple;
+import net.onrc.onos.core.util.SwitchPort;
+
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Abstraction of explicitly path specified connectivity intent.
+ */
+public class PathIntent extends PointToPointIntent {
+
+ private final List<LinkTuple> 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, Match match, Action action,
+ SwitchPort ingressPort, SwitchPort egressPort,
+ List<LinkTuple> path) {
+ super(id, match, action, ingressPort, egressPort);
+ this.path = ImmutableList.copyOf(checkNotNull(path));
+ }
+
+ /**
+ * Returns the links which the traffic goes along.
+ *
+ * @return traversed links
+ */
+ public List<LinkTuple> 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.hashCode(super.hashCode(), path);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(getClass())
+ .add("id", getId())
+ .add("match", getMatch())
+ .add("action", getAction())
+ .add("ingressPort", getIngressPort())
+ .add("egressPort", getEgressPort())
+ .add("path", path)
+ .toString();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/api/newintent/PointToPointIntent.java b/src/main/java/net/onrc/onos/api/newintent/PointToPointIntent.java
new file mode 100644
index 0000000..9672690
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/PointToPointIntent.java
@@ -0,0 +1,89 @@
+package net.onrc.onos.api.newintent;
+
+import com.google.common.base.Objects;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.util.SwitchPort;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Abstraction of point-to-point connectivity.
+ */
+public class PointToPointIntent extends ConnectivityIntent {
+
+ private final SwitchPort ingressPort;
+ private final SwitchPort 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, Match match, Action action,
+ SwitchPort ingressPort, SwitchPort egressPort) {
+ super(id, match, action);
+ this.ingressPort = checkNotNull(ingressPort);
+ this.egressPort = checkNotNull(egressPort);
+ }
+
+
+ /**
+ * Returns the port on which the ingress traffic should be connected to
+ * the egress.
+ *
+ * @return ingress port
+ */
+ public SwitchPort getIngressPort() {
+ return ingressPort;
+ }
+
+ /**
+ * Returns the port on which the traffic should egress.
+ *
+ * @return egress port
+ */
+ public SwitchPort 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.equal(this.ingressPort, that.ingressPort)
+ && Objects.equal(this.egressPort, that.egressPort);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), ingressPort, egressPort);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(getClass())
+ .add("id", getId())
+ .add("match", getMatch())
+ .add("action", getAction())
+ .add("ingressPort", ingressPort)
+ .add("egressPort", egressPort)
+ .toString();
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/api/newintent/SinglePointToMultiPointIntent.java b/src/main/java/net/onrc/onos/api/newintent/SinglePointToMultiPointIntent.java
new file mode 100644
index 0000000..e2ee22f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/api/newintent/SinglePointToMultiPointIntent.java
@@ -0,0 +1,97 @@
+package net.onrc.onos.api.newintent;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import net.onrc.onos.core.matchaction.action.Action;
+import net.onrc.onos.core.matchaction.match.Match;
+import net.onrc.onos.core.util.SwitchPort;
+
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Abstraction of single source, multiple destination connectivity intent.
+ */
+public class SinglePointToMultiPointIntent extends ConnectivityIntent {
+
+ private final SwitchPort ingressPort;
+ private final Set<SwitchPort> 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, Match match, Action action,
+ SwitchPort ingressPort,
+ Set<SwitchPort> egressPorts) {
+ super(id, match, action);
+
+ checkNotNull(egressPorts);
+ checkArgument(egressPorts.size() > 1, "the number of egress ports should be more than 1, " +
+ "but actually %s", egressPorts.size());
+
+ this.ingressPort = checkNotNull(ingressPort);
+ this.egressPorts = ImmutableSet.copyOf(egressPorts);
+ }
+
+ /**
+ * Returns the port on which the ingress traffic should be connected to the egress.
+ *
+ * @return ingress port
+ */
+ public SwitchPort getIngressPort() {
+ return ingressPort;
+ }
+
+ /**
+ * Returns the set of ports on which the traffic should egress.
+ *
+ * @return set of egress ports
+ */
+ public Set<SwitchPort> 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.equal(this.ingressPort, that.ingressPort)
+ && Objects.equal(this.egressPorts, that.egressPorts);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), ingressPort, egressPorts);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(getClass())
+ .add("id", getId())
+ .add("match", getMatch())
+ .add("action", getAction())
+ .add("ingressPort", ingressPort)
+ .add("egressPort", egressPorts)
+ .toString();
+ }
+
+}