Implement IntentInstallers
IntentInstallers for:
- PathFlowIntent
- SingleDstTreeFlowIntent
- SingleSrcTreeFlowIntent
This resolves ONOS-1884, ONOS-1885, and ONOS-1886.
Change-Id: Ie0eac4bab9a2898b582edf2e4291498f0a583d71
diff --git a/src/main/java/net/onrc/onos/core/newintent/AbstractIntentInstaller.java b/src/main/java/net/onrc/onos/core/newintent/AbstractIntentInstaller.java
new file mode 100644
index 0000000..9d21771
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/AbstractIntentInstaller.java
@@ -0,0 +1,185 @@
+package net.onrc.onos.core.newintent;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import net.onrc.onos.api.flowmanager.Flow;
+import net.onrc.onos.api.flowmanager.FlowBatchHandle;
+import net.onrc.onos.api.flowmanager.FlowBatchStateChangedEvent;
+import net.onrc.onos.api.flowmanager.FlowId;
+import net.onrc.onos.api.flowmanager.FlowManagerListener;
+import net.onrc.onos.api.flowmanager.FlowManagerService;
+import net.onrc.onos.api.flowmanager.FlowState;
+import net.onrc.onos.api.flowmanager.FlowStateChange;
+import net.onrc.onos.api.flowmanager.FlowStatesChangedEvent;
+import net.onrc.onos.api.newintent.InstallableIntent;
+import net.onrc.onos.api.newintent.Intent;
+import net.onrc.onos.api.newintent.IntentInstaller;
+
+import java.util.concurrent.CountDownLatch;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static net.onrc.onos.api.flowmanager.FlowState.FAILED;
+import static net.onrc.onos.api.flowmanager.FlowState.INSTALLED;
+import static net.onrc.onos.api.flowmanager.FlowState.WITHDRAWN;
+
+// TODO: consider naming because to call Flow manager's API will be removed
+// in long-term refactoring
+// TODO: consider unifying the install() and remove() by pulling up to this class
+/**
+ * Base class for implementing an intent installer, which use Flow Manager's API.
+ *
+ * @param <T> the type of intent
+ */
+public abstract class AbstractIntentInstaller<T extends InstallableIntent>
+ implements IntentInstaller<T> {
+ protected final FlowManagerService flowManager;
+
+ /**
+ * Constructs a base class with the specified Flow Manager service.
+ *
+ * @param flowManager Flow manager service, which is used to install/remove
+ * an intent
+ */
+ protected AbstractIntentInstaller(FlowManagerService flowManager) {
+ this.flowManager = flowManager;
+ }
+
+ protected void installFlow(Intent intent, Flow flow) {
+ InstallationListener listener = new InstallationListener(flow.getId());
+ flowManager.addListener(listener);
+
+ FlowBatchHandle handle = flowManager.addFlow(flow);
+ if (handle == null) {
+ throw new IntentInstallationException("intent installation failed: " + intent);
+ }
+
+ try {
+ listener.await();
+ if (listener.getFinalState() == FAILED) {
+ throw new IntentInstallationException("intent installation failed: " + intent);
+ }
+ } catch (InterruptedException e) {
+ throw new IntentInstallationException("intent installation failed: " + intent, e);
+ } finally {
+ flowManager.removeListener(listener);
+ }
+ }
+
+ protected void removeFlow(Intent intent, Flow flow) {
+ RemovalListener listener = new RemovalListener(flow.getId());
+ flowManager.addListener(listener);
+
+ FlowBatchHandle handle = flowManager.removeFlow(flow.getId());
+ if (handle == null) {
+ throw new IntentRemovalException("intent removal failed: " + intent);
+ }
+
+
+ try {
+ listener.await();
+ if (listener.getFinalState() == FAILED) {
+ throw new IntentInstallationException("intent removal failed: " + intent);
+ }
+ } catch (InterruptedException e) {
+ throw new IntentInstallationException("intent removal failed: " + intent, e);
+ } finally {
+ flowManager.removeListener(listener);
+ }
+ }
+
+ protected abstract static class SyncListener implements FlowManagerListener {
+ protected final FlowId target;
+ protected final CountDownLatch latch = new CountDownLatch(1);
+ protected FlowState finalState;
+
+ protected SyncListener(FlowId target) {
+ this.target = checkNotNull(target);
+ }
+
+ protected Optional<FlowStateChange> findTargetFlow(FlowStatesChangedEvent event) {
+ return Iterables.tryFind(event.getStateChanges(), new Predicate<FlowStateChange>() {
+ @Override
+ public boolean apply(FlowStateChange stateChange) {
+ return stateChange.getFlowId().equals(target);
+ }
+ });
+ }
+
+ public FlowState getFinalState() {
+ return finalState;
+ }
+
+ public void await() throws InterruptedException {
+ latch.await();
+ }
+ }
+
+ protected static class InstallationListener extends SyncListener {
+ public InstallationListener(FlowId target) {
+ super(target);
+ }
+
+ @Override
+ public void flowStatesChanged(FlowStatesChangedEvent event) {
+ Optional<FlowStateChange> optional = findTargetFlow(event);
+
+ if (!optional.isPresent()) {
+ return;
+ }
+
+ FlowStateChange stateChange = optional.get();
+ switch (stateChange.getCurrentState()) {
+ case INSTALLED:
+ latch.countDown();
+ finalState = INSTALLED;
+ break;
+ case FAILED:
+ latch.countDown();
+ finalState = FAILED;
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void flowBatchStateChanged(FlowBatchStateChangedEvent event) {
+ // nop
+ }
+ }
+
+ protected static class RemovalListener extends SyncListener {
+ public RemovalListener(FlowId target) {
+ super(target);
+ }
+
+ @Override
+ public void flowStatesChanged(FlowStatesChangedEvent event) {
+ Optional<FlowStateChange> optional = findTargetFlow(event);
+
+ if (!optional.isPresent()) {
+ return;
+ }
+
+ FlowStateChange stateChange = optional.get();
+ switch (stateChange.getCurrentState()) {
+ case WITHDRAWN:
+ latch.countDown();
+ finalState = WITHDRAWN;
+ break;
+ case FAILED:
+ latch.countDown();
+ finalState = FAILED;
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void flowBatchStateChanged(FlowBatchStateChangedEvent event) {
+ // nop
+ }
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/IdBlockAllocatorBasedIntentIdGenerator.java b/src/main/java/net/onrc/onos/core/newintent/IdBlockAllocatorBasedIntentIdGenerator.java
index 2e09698..9137b29 100644
--- a/src/main/java/net/onrc/onos/core/newintent/IdBlockAllocatorBasedIntentIdGenerator.java
+++ b/src/main/java/net/onrc/onos/core/newintent/IdBlockAllocatorBasedIntentIdGenerator.java
@@ -3,8 +3,8 @@
import net.onrc.onos.api.newintent.IntentId;
import net.onrc.onos.api.newintent.IntentIdGenerator;
import net.onrc.onos.core.util.IdBlock;
-import net.onrc.onos.core.util.UnavailableIdException;
import net.onrc.onos.core.util.IdBlockAllocator;
+import net.onrc.onos.core.util.UnavailableIdException;
import static com.google.common.base.Preconditions.checkNotNull;
diff --git a/src/main/java/net/onrc/onos/core/newintent/IntentInstallationException.java b/src/main/java/net/onrc/onos/core/newintent/IntentInstallationException.java
new file mode 100644
index 0000000..4dca400
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/IntentInstallationException.java
@@ -0,0 +1,22 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.newintent.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/src/main/java/net/onrc/onos/core/newintent/IntentRemovalException.java b/src/main/java/net/onrc/onos/core/newintent/IntentRemovalException.java
new file mode 100644
index 0000000..1c8549f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/IntentRemovalException.java
@@ -0,0 +1,22 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.newintent.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/src/main/java/net/onrc/onos/core/newintent/PathFlowIntentInstaller.java b/src/main/java/net/onrc/onos/core/newintent/PathFlowIntentInstaller.java
new file mode 100644
index 0000000..7066503
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/PathFlowIntentInstaller.java
@@ -0,0 +1,30 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.flowmanager.FlowManagerService;
+
+/**
+ * An intent installer for {@link PathFlowIntent}.
+ */
+public class PathFlowIntentInstaller
+ extends AbstractIntentInstaller<PathFlowIntent> {
+ /**
+ * Constructs an intent installer for {@link PathFlowIntent} with the
+ * specified Flow Manager service, which is used in this installer.
+ *
+ * @param flowManager Flow Manager service, which is used
+ * to install/remove an intent
+ */
+ public PathFlowIntentInstaller(FlowManagerService flowManager) {
+ super(flowManager);
+ }
+
+ @Override
+ public void install(PathFlowIntent intent) {
+ installFlow(intent, intent.getFlow());
+ }
+
+ @Override
+ public void remove(PathFlowIntent intent) {
+ removeFlow(intent, intent.getFlow());
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/SingleDstTreeFlowIntentInstaller.java b/src/main/java/net/onrc/onos/core/newintent/SingleDstTreeFlowIntentInstaller.java
new file mode 100644
index 0000000..f79237b
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/SingleDstTreeFlowIntentInstaller.java
@@ -0,0 +1,31 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.flowmanager.FlowManagerService;
+
+/**
+ * An intent installer for {@link SingleDstTreeFlowIntent}.
+ */
+public class SingleDstTreeFlowIntentInstaller
+ extends AbstractIntentInstaller<SingleDstTreeFlowIntent> {
+
+ /**
+ * Constructs an intent installer for {@link SingleDstTreeFlowIntent} with
+ * the specified Flow Manager service, which is used in this installer.
+ *
+ * @param flowManager Flow Manager service, which is used
+ * to install/remove an intent
+ */
+ public SingleDstTreeFlowIntentInstaller(FlowManagerService flowManager) {
+ super(flowManager);
+ }
+
+ @Override
+ public void install(SingleDstTreeFlowIntent intent) {
+ installFlow(intent, intent.getTree());
+ }
+
+ @Override
+ public void remove(SingleDstTreeFlowIntent intent) {
+ removeFlow(intent, intent.getTree());
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/newintent/SingleSrcTreeFlowIntentInstaller.java b/src/main/java/net/onrc/onos/core/newintent/SingleSrcTreeFlowIntentInstaller.java
new file mode 100644
index 0000000..38aec87
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/newintent/SingleSrcTreeFlowIntentInstaller.java
@@ -0,0 +1,31 @@
+package net.onrc.onos.core.newintent;
+
+import net.onrc.onos.api.flowmanager.FlowManagerService;
+
+/**
+ * An intent installer for {@link SingleSrcTreeFlowIntent}.
+ */
+public class SingleSrcTreeFlowIntentInstaller
+ extends AbstractIntentInstaller<SingleSrcTreeFlowIntent> {
+
+ /**
+ * Constructs an intent installer for {@link SingleSrcTreeFlowIntent}
+ * with the specified Flow Manager service, which is used in this class.
+ *
+ * @param flowManager Flow Manager service, which is used
+ * to install/remove an intent
+ */
+ public SingleSrcTreeFlowIntentInstaller(FlowManagerService flowManager) {
+ super(flowManager);
+ }
+
+ @Override
+ public void install(SingleSrcTreeFlowIntent intent) {
+ installFlow(intent, intent.getTree());
+ }
+
+ @Override
+ public void remove(SingleSrcTreeFlowIntent intent) {
+ removeFlow(intent, intent.getTree());
+ }
+}