Adding Intent Impl and shell command to install simple intent
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