[ONOS-6163] (vnet) revise intent service for vnets
Revise intent service for virtual networks.
Change-Id: I4955cde2296e58d8f0e356d19483e84f51193318
diff --git a/apps/evpnopenflow/pom.xml b/apps/evpnopenflow/pom.xml
index a1ec1b8..da130fa 100644
--- a/apps/evpnopenflow/pom.xml
+++ b/apps/evpnopenflow/pom.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
- ~ Copyright 2017-present Open Networking Laboratory
+ ~ Copyright 2017-present Open Networking Foundation
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
diff --git a/apps/evpnopenflow/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/evpnopenflow/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index bb55858..fcc09bf 100644
--- a/apps/evpnopenflow/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/evpnopenflow/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright 2017-present Open Networking Laboratory
+ ~ Copyright 2017-present Open Networking Foundation
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentCompiler.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentCompiler.java
new file mode 100644
index 0000000..e76bf6e
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentCompiler.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.intent;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.intent.Intent;
+
+import java.util.List;
+
+/**
+ * Abstraction of a compiler which is capable of taking an intent
+ * and translating it to other, potentially installable, intents for virtual networks.
+ *
+ * @param <T> the type of intent
+ */
+@Beta
+public interface VirtualIntentCompiler<T extends Intent> {
+ /**
+ * Compiles the specified intent into other intents.
+ *
+ * @param networkId network identifier
+ * @param intent intent to be compiled
+ * @param installable previous compilation result; optional
+ * @return list of resulting intents
+ * @throws VirtualIntentException if issues are encountered while compiling the intent
+ */
+ List<Intent> compile(NetworkId networkId, T intent, List<Intent> installable);
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentException.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentException.java
new file mode 100644
index 0000000..49cb908
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentException.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.intent;
+
+public class VirtualIntentException extends RuntimeException {
+
+ //FIXME: how to obatin UID?
+ private static final long serialVersionUID = 1907263634145241319L;
+
+ /**
+ * Constructs an exception with no message and no underlying cause.
+ */
+ public VirtualIntentException() {
+ }
+
+ /**
+ * Constructs an exception with the specified message.
+ *
+ * @param message the message describing the specific nature of the error
+ */
+ public VirtualIntentException(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 VirtualIntentException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/intent/package-info.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/intent/package-info.java
new file mode 100644
index 0000000..c5673ac
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/intent/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Set of abstractions for conveying high-level intents for treatment of
+ * selected network traffic by allowing applications to express the
+ * <em>what</em> rather than the <em>how</em> for virtual networks.
+ */
+package org.onosproject.incubator.net.virtual.intent;
\ No newline at end of file
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java
index a133c66..e40bf4e 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManager.java
@@ -16,7 +16,7 @@
package org.onosproject.incubator.net.virtual.impl;
-import com.google.common.collect.Iterators;
+import org.onlab.util.Tools;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
import org.onosproject.incubator.net.virtual.VirtualNetworkIntentStore;
@@ -25,26 +25,46 @@
import org.onosproject.incubator.net.virtual.VirtualPort;
import org.onosproject.incubator.net.virtual.VnetService;
import org.onosproject.incubator.net.virtual.event.AbstractVirtualListenerManager;
+import org.onosproject.incubator.net.virtual.impl.intent.phase.VirtualFinalIntentProcessPhase;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentInstallCoordinator;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentAccumulator;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentCompilerRegistry;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentInstallerRegistry;
+import org.onosproject.incubator.net.virtual.impl.intent.phase.VirtualIntentProcessPhase;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentProcessor;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentSkipped;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.group.GroupService;
import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentBatchDelegate;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentEvent;
import org.onosproject.net.intent.IntentListener;
-import org.onosproject.net.intent.WorkPartitionService;
+import org.onosproject.net.intent.IntentStoreDelegate;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.Key;
+import org.onosproject.net.resource.ResourceConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.*;
+import static org.onlab.util.BoundedThreadPool.newFixedThreadPool;
+import static org.onlab.util.BoundedThreadPool.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.incubator.net.virtual.impl.intent.phase.VirtualIntentProcessPhase.newInitialPhase;
+import static org.onosproject.net.intent.IntentState.FAILED;
/**
* Intent service implementation built on the virtual network service.
@@ -55,6 +75,9 @@
private final Logger log = LoggerFactory.getLogger(getClass());
+ private static final int DEFAULT_NUM_THREADS = 12;
+ private int numThreads = DEFAULT_NUM_THREADS;
+
private static final String NETWORK_ID_NULL = "Network ID cannot be null";
private static final String DEVICE_NULL = "Device cannot be null";
private static final String INTENT_NULL = "Intent cannot be null";
@@ -63,10 +86,28 @@
private static final String INTENT_KEY_NULL = "Intent key cannot be null";
private static final String CP_NULL = "Connect Point cannot be null";
- protected IntentService intentService;
- protected VirtualNetworkStore store;
+ //FIXME: Tracker service for vnet.
+
+ //ONOS core services
+ protected VirtualNetworkStore virtualNetworkStore;
protected VirtualNetworkIntentStore intentStore;
- protected WorkPartitionService partitionService;
+
+ //Virtual network services
+ protected GroupService groupService;
+
+ private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
+ private final InternalIntentProcessor processor = new InternalIntentProcessor();
+ private final IntentStoreDelegate delegate = new InternalStoreDelegate();
+ private final VirtualIntentCompilerRegistry compilerRegistry =
+ VirtualIntentCompilerRegistry.getInstance();
+ private final VirtualIntentInstallerRegistry installerRegistry =
+ VirtualIntentInstallerRegistry.getInstance();
+ private final VirtualIntentAccumulator accumulator =
+ new VirtualIntentAccumulator(batchDelegate);
+
+ private VirtualIntentInstallCoordinator installCoordinator;
+ private ExecutorService batchExecutor;
+ private ExecutorService workerExecutor;
/**
* Creates a new VirtualNetworkIntentService object.
@@ -79,10 +120,18 @@
super(virtualNetworkManager, networkId, IntentEvent.class);
- this.store = serviceDirectory.get(VirtualNetworkStore.class);
+ this.virtualNetworkStore = serviceDirectory.get(VirtualNetworkStore.class);
this.intentStore = serviceDirectory.get(VirtualNetworkIntentStore.class);
- this.intentService = serviceDirectory.get(IntentService.class);
- this.partitionService = serviceDirectory.get(WorkPartitionService.class);
+
+ this.groupService = manager.get(networkId, GroupService.class);
+
+ intentStore.setDelegate(networkId, delegate);
+ batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch", log));
+ workerExecutor = newFixedThreadPool(numThreads, groupedThreads("onos/intent", "worker-%d", log));
+
+ installCoordinator = new VirtualIntentInstallCoordinator(networkId, installerRegistry, intentStore);
+ log.info("Started");
+
}
@Override
@@ -91,7 +140,8 @@
checkState(intent instanceof VirtualNetworkIntent, "Only VirtualNetworkIntent is supported.");
checkArgument(validateIntent((VirtualNetworkIntent) intent), "Invalid Intent");
- intentService.submit(intent);
+ IntentData data = IntentData.submit(intent);
+ intentStore.addPending(networkId, data);
}
/**
@@ -146,37 +196,19 @@
@Override
public void withdraw(Intent intent) {
checkNotNull(intent, INTENT_NULL);
- // Withdraws the physical intents created due to the virtual intents.
- store.getTunnelIds(intent).forEach(tunnelId -> {
- Key intentKey = Key.of(tunnelId.id(), intent.appId());
- Intent physicalIntent = intentService.getIntent(intentKey);
- checkNotNull(physicalIntent, INTENT_NULL);
-
- // Withdraw the physical intent(s)
- log.debug("Withdrawing pt-pt intent: " + physicalIntent);
- intentService.withdraw(physicalIntent);
- });
- // Now withdraw the virtual intent
- log.debug("Withdrawing virtual intent: " + intent);
- intentService.withdraw(intent);
+ IntentData data = IntentData.withdraw(intent);
+ intentStore.addPending(networkId, data);
}
@Override
public void purge(Intent intent) {
checkNotNull(intent, INTENT_NULL);
- // Purges the physical intents created for each tunnelId.
- store.getTunnelIds(intent)
- .forEach(tunnelId -> {
- Key intentKey = Key.of(tunnelId.id(), intent.appId());
- Intent physicalIntent = intentService.getIntent(intentKey);
- checkNotNull(physicalIntent, INTENT_NULL);
- // Purge the physical intent(s)
- intentService.purge(physicalIntent);
- store.removeTunnelId(intent, tunnelId);
- });
- // Now purge the virtual intent
- intentService.purge(intent);
+ IntentData data = IntentData.purge(intent);
+ intentStore.addPending(networkId, data);
+
+ // remove associated group if there is one
+ // FIXME: Remove P2P intent for vnets
}
@Override
@@ -192,7 +224,9 @@
@Override
public void addPending(IntentData intentData) {
- intentService.addPending(intentData);
+ checkNotNull(intentData, INTENT_NULL);
+ //TODO we might consider further checking / assertions
+ intentStore.addPending(networkId, intentData);
}
@Override
@@ -202,38 +236,177 @@
@Override
public long getIntentCount() {
- return Iterators.size(getIntents().iterator());
+ return intentStore.getIntentCount(networkId);
}
@Override
public IntentState getIntentState(Key intentKey) {
checkNotNull(intentKey, KEY_NULL);
- return Optional.ofNullable(intentStore.getIntentData(networkId, intentKey))
- .map(IntentData::state)
- .orElse(null);
+ return intentStore.getIntentState(networkId, intentKey);
}
@Override
public List<Intent> getInstallableIntents(Key intentKey) {
- List<Intent> intents = new ArrayList<>();
- getIntentData().forEach(intentData -> {
- if (intentData.intent().key().equals(intentKey)) {
- intents.addAll(intentData.installables());
- }
- });
- return intents;
+ return intentStore.getInstallableIntents(networkId, intentKey);
}
@Override
public boolean isLocal(Key intentKey) {
- checkNotNull(intentKey, INTENT_KEY_NULL);
- Intent intent = getIntent(intentKey);
- checkNotNull(intent, INTENT_NULL);
- return partitionService.isMine(intentKey, Key::hash);
+ return intentStore.isMaster(networkId, intentKey);
}
@Override
public Iterable<Intent> getPending() {
- return null;
+ return intentStore.getPending(networkId);
+ }
+
+ // Store delegate to re-post events emitted from the store.
+ private class InternalStoreDelegate implements IntentStoreDelegate {
+ @Override
+ public void notify(IntentEvent event) {
+ post(event);
+ switch (event.type()) {
+ case WITHDRAWN:
+ //FIXME: release resources
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void process(IntentData data) {
+ accumulator.add(data);
+ }
+
+ @Override
+ public void onUpdate(IntentData intentData) {
+ //FIXME: track intent
+ }
+
+ private void releaseResources(Intent intent) {
+ // If a resource group is set on the intent, the resource consumer is
+ // set equal to it. Otherwise it's set to the intent key
+ ResourceConsumer resourceConsumer =
+ intent.resourceGroup() != null ? intent.resourceGroup() : intent.key();
+
+ // By default the resource doesn't get released
+ boolean removeResource = false;
+
+ if (intent.resourceGroup() == null) {
+ // If the intent doesn't have a resource group, it means the
+ // resource was registered using the intent key, so it can be
+ // released
+ removeResource = true;
+ } else {
+ // When a resource group is set, we make sure there are no other
+ // intents using the same resource group, before deleting the
+ // related resources.
+ Long remainingIntents =
+ Tools.stream(intentStore.getIntents(networkId))
+ .filter(i -> {
+ return i.resourceGroup() != null
+ && i.resourceGroup().equals(intent.resourceGroup());
+ })
+ .count();
+ if (remainingIntents == 0) {
+ removeResource = true;
+ }
+ }
+
+ if (removeResource) {
+ // Release resources allocated to withdrawn intent
+ // FIXME: confirm resources are released
+ }
+ }
+ }
+
+ private class InternalBatchDelegate implements IntentBatchDelegate {
+ @Override
+ public void execute(Collection<IntentData> operations) {
+ log.debug("Execute {} operation(s).", operations.size());
+ log.trace("Execute operations: {}", operations);
+
+ // batchExecutor is single-threaded, so only one batch is in flight at a time
+ CompletableFuture.runAsync(() -> {
+ // process intent until the phase reaches one of the final phases
+ List<CompletableFuture<IntentData>> futures = operations.stream()
+ .map(data -> {
+ log.debug("Start processing of {} {}@{}", data.request(), data.key(), data.version());
+ return data;
+ })
+ .map(x -> CompletableFuture.completedFuture(x)
+ .thenApply(VirtualNetworkIntentManager.this::createInitialPhase)
+ .thenApplyAsync(VirtualIntentProcessPhase::process, workerExecutor)
+ .thenApply(VirtualFinalIntentProcessPhase::data)
+ .exceptionally(e -> {
+ // When the future fails, we update the Intent to simulate the failure of
+ // the installation/withdrawal phase and we save in the current map. In
+ // the next round the CleanUp Thread will pick this Intent again.
+ log.warn("Future failed", e);
+ log.warn("Intent {} - state {} - request {}",
+ x.key(), x.state(), x.request());
+ switch (x.state()) {
+ case INSTALL_REQ:
+ case INSTALLING:
+ case WITHDRAW_REQ:
+ case WITHDRAWING:
+ // TODO should we swtich based on current
+ IntentData current = intentStore.getIntentData(networkId, x.key());
+ return IntentData.nextState(current, FAILED);
+ default:
+ return null;
+ }
+ }))
+ .collect(Collectors.toList());
+
+ // write multiple data to store in order
+ intentStore.batchWrite(networkId, Tools.allOf(futures).join().stream()
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList()));
+ }, batchExecutor).exceptionally(e -> {
+ log.error("Error submitting batches:", e);
+ // FIXME incomplete Intents should be cleaned up
+ // (transition to FAILED, etc.)
+
+ // the batch has failed
+ // TODO: maybe we should do more?
+ log.error("Walk the plank, matey...");
+ return null;
+ }).thenRun(accumulator::ready);
+
+ }
+ }
+
+ private VirtualIntentProcessPhase createInitialPhase(IntentData data) {
+ IntentData pending = intentStore.getPendingData(networkId, data.key());
+ if (pending == null || pending.version().isNewerThan(data.version())) {
+ /*
+ If the pending map is null, then this intent was compiled by a
+ previous batch iteration, so we can skip it.
+ If the pending map has a newer request, it will get compiled as
+ part of the next batch, so we can skip it.
+ */
+ return VirtualIntentSkipped.getPhase();
+ }
+ IntentData current = intentStore.getIntentData(networkId, data.key());
+ return newInitialPhase(networkId, processor, data, current);
+ }
+
+ private class InternalIntentProcessor implements VirtualIntentProcessor {
+ @Override
+ public List<Intent> compile(NetworkId networkId,
+ Intent intent,
+ List<Intent> previousInstallables) {
+ return compilerRegistry.compile(networkId, intent, previousInstallables);
+ }
+
+ @Override
+ public void apply(NetworkId networkId,
+ Optional<IntentData> toUninstall,
+ Optional<IntentData> toInstall) {
+
+ installCoordinator.installIntents(toUninstall, toInstall);
+ }
}
}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentAccumulator.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentAccumulator.java
new file mode 100644
index 0000000..0328383
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentAccumulator.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent;
+
+import com.google.common.collect.Maps;
+import org.onlab.util.AbstractAccumulator;
+import org.onosproject.net.intent.IntentBatchDelegate;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.Key;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+
+/**
+ * An accumulator for building batches of intent operations for virtual network.
+ * Only one batch should be in process per instance at a time.
+ */
+public class VirtualIntentAccumulator extends AbstractAccumulator<IntentData> {
+ private static final int DEFAULT_MAX_EVENTS = 1000;
+ private static final int DEFAULT_MAX_IDLE_MS = 10;
+ private static final int DEFAULT_MAX_BATCH_MS = 50;
+
+ // FIXME: Replace with a system-wide timer instance;
+ // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt
+ private static final Timer TIMER = new Timer("virtual-intent-op-batching");
+
+ private final IntentBatchDelegate delegate;
+
+ private volatile boolean ready;
+
+ /**
+ * Creates an intent operation accumulator.
+ *
+ * @param delegate the intent batch delegate
+ */
+ public VirtualIntentAccumulator(IntentBatchDelegate delegate) {
+ super(TIMER, DEFAULT_MAX_EVENTS, DEFAULT_MAX_BATCH_MS, DEFAULT_MAX_IDLE_MS);
+ this.delegate = delegate;
+ // Assume that the delegate is ready for work at the start
+ ready = true; //TODO validate the assumption that delegate is ready
+ }
+
+ @Override
+ public void processItems(List<IntentData> items) {
+ ready = false;
+ delegate.execute(reduce(items));
+ }
+
+ private Collection<IntentData> reduce(List<IntentData> ops) {
+ Map<Key, IntentData> map = Maps.newHashMap();
+ for (IntentData op : ops) {
+ map.put(op.key(), op);
+ }
+ //TODO check the version... or maybe store will handle this.
+ return map.values();
+ }
+
+ @Override
+ public boolean isReady() {
+ return ready;
+ }
+
+ public void ready() {
+ ready = true;
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentCompilerRegistry.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentCompilerRegistry.java
new file mode 100644
index 0000000..f922c22
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentCompilerRegistry.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.intent.VirtualIntentCompiler;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentException;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public final class VirtualIntentCompilerRegistry {
+ private final ConcurrentMap<Class<? extends Intent>,
+ VirtualIntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
+
+ // non-instantiable (except for our Singleton)
+ private VirtualIntentCompilerRegistry() {
+
+ }
+
+ public static VirtualIntentCompilerRegistry getInstance() {
+ return SingletonHelper.INSTANCE;
+ }
+
+ /**
+ * Registers the specified compiler for the given intent class.
+ *
+ * @param cls intent class
+ * @param compiler intent compiler
+ * @param <T> the type of intent
+ */
+ public <T extends Intent> void registerCompiler(Class<T> cls,
+ VirtualIntentCompiler<T> compiler) {
+ compilers.put(cls, compiler);
+ }
+
+ /**
+ * Unregisters the compiler for the specified intent class.
+ *
+ * @param cls intent class
+ * @param <T> the type of intent
+ */
+ public <T extends Intent> void unregisterCompiler(Class<T> cls) {
+ compilers.remove(cls);
+ }
+
+ /**
+ * Returns immutable set of bindings of currently registered intent compilers.
+ *
+ * @return the set of compiler bindings
+ */
+ public Map<Class<? extends Intent>, VirtualIntentCompiler<? extends Intent>> getCompilers() {
+ return ImmutableMap.copyOf(compilers);
+ }
+
+ /**
+ * Compiles an intent recursively.
+ *
+ * @param networkId network identifier
+ * @param intent intent
+ * @param previousInstallables previous intent installables
+ * @return result of compilation
+ */
+ public List<Intent> compile(NetworkId networkId,
+ Intent intent, List<Intent> previousInstallables) {
+ if (intent.isInstallable()) {
+ return ImmutableList.of(intent);
+ }
+
+ // FIXME: get previous resources
+ List<Intent> installables = new ArrayList<>();
+ Queue<Intent> compileQueue = new LinkedList<>();
+ compileQueue.add(intent);
+
+ Intent compiling;
+ while ((compiling = compileQueue.poll()) != null) {
+ registerSubclassCompilerIfNeeded(compiling);
+
+ List<Intent> compiled = getCompiler(compiling)
+ .compile(networkId, compiling, previousInstallables);
+
+ compiled.forEach(i -> {
+ if (i.isInstallable()) {
+ installables.add(i);
+ } else {
+ compileQueue.add(i);
+ }
+ });
+ }
+ return installables;
+ }
+
+ /**
+ * 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> VirtualIntentCompiler<T> getCompiler(T intent) {
+ @SuppressWarnings("unchecked")
+ VirtualIntentCompiler<T> compiler =
+ (VirtualIntentCompiler<T>) compilers.get(intent.getClass());
+ if (compiler == null) {
+ throw new IntentException("no compiler for class " + intent.getClass());
+ }
+ return compiler;
+ }
+
+ /**
+ * 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)) {
+ VirtualIntentCompiler<?> compiler = compilers.get(cls);
+ if (compiler != null) {
+ compilers.put(intent.getClass(), compiler);
+ return;
+ }
+ }
+ cls = cls.getSuperclass();
+ }
+ }
+ }
+
+ /**
+ * Prevents object instantiation from external.
+ */
+ private static final class SingletonHelper {
+ private static final String ILLEGAL_ACCESS_MSG =
+ "Should not instantiate this class.";
+ private static final VirtualIntentCompilerRegistry INSTANCE =
+ new VirtualIntentCompilerRegistry();
+
+ private SingletonHelper() {
+ throw new IllegalAccessError(ILLEGAL_ACCESS_MSG);
+ }
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentInstallCoordinator.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentInstallCoordinator.java
new file mode 100644
index 0000000..4a09250
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentInstallCoordinator.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntentStore;
+import org.onosproject.incubator.net.virtual.impl.VirtualNetworkIntentManager;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentInstallationContext;
+import org.onosproject.net.intent.IntentInstaller;
+import org.onosproject.net.intent.IntentOperationContext;
+import org.slf4j.Logger;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.onosproject.net.intent.IntentState.*;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of IntentInstallCoordinator for virtual network.
+ */
+public class VirtualIntentInstallCoordinator {
+ private static final String INSTALLER_NOT_FOUND = "Intent installer not found, Intent: {}";
+ private final Logger log = getLogger(VirtualNetworkIntentManager.class);
+
+ NetworkId networkId;
+ private VirtualIntentInstallerRegistry installerRegistry;
+ private VirtualNetworkIntentStore intentStore;
+
+ /**
+ * Creates an InstallCoordinator.
+ *
+ * @param networkId virtual network identifier
+ * @param installerRegistry the installer registry
+ * @param intentStore the Intent store
+ */
+ public VirtualIntentInstallCoordinator(NetworkId networkId,
+ VirtualIntentInstallerRegistry installerRegistry,
+ VirtualNetworkIntentStore intentStore) {
+ this.networkId = networkId;
+ this.installerRegistry = installerRegistry;
+ this.intentStore = intentStore;
+ }
+
+ /**
+ * Applies Intent data to be uninstalled and to be installed.
+ *
+ * @param toUninstall Intent data to be uninstalled
+ * @param toInstall Intent data to be installed
+ */
+ public void installIntents(Optional<IntentData> toUninstall,
+ Optional<IntentData> toInstall) {
+ // If no any Intents to be uninstalled or installed, ignore it.
+ if (!toUninstall.isPresent() && !toInstall.isPresent()) {
+ return;
+ }
+
+ // Classify installable Intents to different installers.
+ ArrayListMultimap<IntentInstaller, Intent> uninstallInstallers;
+ ArrayListMultimap<IntentInstaller, Intent> installInstallers;
+ Set<IntentInstaller> allInstallers = Sets.newHashSet();
+
+ if (toUninstall.isPresent()) {
+ uninstallInstallers = getInstallers(toUninstall.get());
+ allInstallers.addAll(uninstallInstallers.keySet());
+ } else {
+ uninstallInstallers = ArrayListMultimap.create();
+ }
+
+ if (toInstall.isPresent()) {
+ installInstallers = getInstallers(toInstall.get());
+ allInstallers.addAll(installInstallers.keySet());
+ } else {
+ installInstallers = ArrayListMultimap.create();
+ }
+
+ // Generates an installation context for the high level Intent.
+ IntentInstallationContext installationContext =
+ new IntentInstallationContext(toUninstall.orElse(null), toInstall.orElse(null));
+
+ //Generates different operation context for different installable Intents.
+ Map<IntentInstaller, IntentOperationContext> contexts = Maps.newHashMap();
+ allInstallers.forEach(installer -> {
+ List<Intent> intentsToUninstall = uninstallInstallers.get(installer);
+ List<Intent> intentsToInstall = installInstallers.get(installer);
+
+ // Connect context to high level installation context
+ IntentOperationContext context =
+ new IntentOperationContext(intentsToUninstall, intentsToInstall,
+ installationContext);
+ installationContext.addPendingContext(context);
+ contexts.put(installer, context);
+ });
+
+ // Apply contexts to installers
+ contexts.forEach((installer, context) -> {
+ installer.apply(context);
+ });
+ }
+
+ /**
+ * Generates a mapping for installable Intents to installers.
+ *
+ * @param intentData the Intent data which contains installable Intents
+ * @return the mapping for installable Intents to installers
+ */
+ private ArrayListMultimap<IntentInstaller, Intent> getInstallers(IntentData intentData) {
+ ArrayListMultimap<IntentInstaller, Intent> intentInstallers = ArrayListMultimap.create();
+ intentData.installables().forEach(intent -> {
+ IntentInstaller installer = installerRegistry.getInstaller(intent.getClass());
+ if (installer != null) {
+ intentInstallers.put(installer, intent);
+ } else {
+ log.warn(INSTALLER_NOT_FOUND, intent);
+ }
+ });
+ return intentInstallers;
+ }
+
+ /**
+ * Handles success operation context.
+ *
+ * @param context the operation context
+ */
+ public void success(IntentOperationContext context) {
+ IntentInstallationContext intentInstallationContext =
+ context.intentInstallationContext();
+ intentInstallationContext.removePendingContext(context);
+
+ if (intentInstallationContext.isPendingContextsEmpty()) {
+ finish(intentInstallationContext);
+ }
+ }
+
+ /**
+ * Handles failed operation context.
+ *
+ * @param context the operation context
+ */
+ public void failed(IntentOperationContext context) {
+ IntentInstallationContext intentInstallationContext =
+ context.intentInstallationContext();
+ intentInstallationContext.addErrorContext(context);
+ intentInstallationContext.removePendingContext(context);
+
+ if (intentInstallationContext.isPendingContextsEmpty()) {
+ finish(intentInstallationContext);
+ }
+ }
+
+ /**
+ * Completed the installation context and update the Intent store.
+ *
+ * @param intentInstallationContext the installation context
+ */
+ private void finish(IntentInstallationContext intentInstallationContext) {
+ Set<IntentOperationContext> errCtxs = intentInstallationContext.errorContexts();
+ Optional<IntentData> toUninstall = intentInstallationContext.toUninstall();
+ Optional<IntentData> toInstall = intentInstallationContext.toInstall();
+
+ // Intent install success
+ if (errCtxs == null || errCtxs.isEmpty()) {
+ if (toInstall.isPresent()) {
+ IntentData installData = toInstall.get();
+ log.debug("Completed installing: {}", installData.key());
+ installData = new IntentData(installData, installData.installables());
+ installData.setState(INSTALLED);
+ intentStore.write(networkId, installData);
+ } else if (toUninstall.isPresent()) {
+ IntentData uninstallData = toUninstall.get();
+ uninstallData = new IntentData(uninstallData, Collections.emptyList());
+ log.debug("Completed withdrawing: {}", uninstallData.key());
+ switch (uninstallData.request()) {
+ case INSTALL_REQ:
+ log.warn("{} was requested to withdraw during installation?",
+ uninstallData.intent());
+ uninstallData.setState(FAILED);
+ break;
+ case WITHDRAW_REQ:
+ default: //TODO "default" case should not happen
+ uninstallData.setState(WITHDRAWN);
+ break;
+ }
+ // Intent has been withdrawn; we can clear the installables
+ intentStore.write(networkId, uninstallData);
+ }
+ } else {
+ // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
+ if (toInstall.isPresent()) {
+ IntentData installData = toInstall.get();
+ installData.setState(CORRUPT);
+ installData.incrementErrorCount();
+ intentStore.write(networkId, installData);
+ }
+ // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
+ if (toUninstall.isPresent()) {
+ IntentData uninstallData = toUninstall.get();
+ uninstallData.setState(CORRUPT);
+ uninstallData.incrementErrorCount();
+ intentStore.write(networkId, uninstallData);
+ }
+ }
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentInstallerRegistry.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentInstallerRegistry.java
new file mode 100644
index 0000000..a0e6448
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentInstallerRegistry.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentInstaller;
+
+import java.util.Map;
+
+/**
+ * The local registry for Intent installer for virtual networks.
+ */
+public final class VirtualIntentInstallerRegistry {
+ private final Map<Class<? extends Intent>,
+ IntentInstaller<? extends Intent>> installers;
+
+ // non-instantiable (except for our Singleton)
+ private VirtualIntentInstallerRegistry() {
+ installers = Maps.newConcurrentMap();
+ }
+
+ public static VirtualIntentInstallerRegistry getInstance() {
+ return SingletonHelper.INSTANCE;
+ }
+
+ /**
+ * Registers the specific installer for the given intent class.
+ *
+ * @param cls intent class
+ * @param installer intent installer
+ * @param <T> the type of intent
+ */
+ public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
+ installers.put(cls, installer);
+ }
+
+ /**
+ * Unregisters the installer for the specific intent class.
+ *
+ * @param cls intent class
+ * @param <T> the type of intent
+ */
+ public <T extends Intent> void unregisterInstaller(Class<T> cls) {
+ installers.remove(cls);
+ }
+
+ /**
+ * Returns immutable set of binding of currently registered intent installers.
+ *
+ * @return the set of installer bindings
+ */
+ public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
+ return ImmutableMap.copyOf(installers);
+ }
+
+ /**
+ * Get an Intent installer by given Intent type.
+ *
+ * @param cls the Intent type
+ * @param <T> the Intent type
+ * @return the Intent installer of the Intent type if exists; null otherwise
+ */
+ public <T extends Intent> IntentInstaller<T> getInstaller(Class<T> cls) {
+ return (IntentInstaller<T>) installers.get(cls);
+ }
+
+ /**
+ * Prevents object instantiation from external.
+ */
+ private static final class SingletonHelper {
+ private static final String ILLEGAL_ACCESS_MSG =
+ "Should not instantiate this class.";
+ private static final VirtualIntentInstallerRegistry INSTANCE =
+ new VirtualIntentInstallerRegistry();
+
+ private SingletonHelper() {
+ throw new IllegalAccessError(ILLEGAL_ACCESS_MSG);
+ }
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentProcessor.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentProcessor.java
new file mode 100644
index 0000000..a7719f9
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentProcessor.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * A collection of methods to process an intent for virtual networks.
+ *
+ * This interface is public, but intended to be used only by IntentManager and
+ * IntentProcessPhase subclasses stored under phase package.
+ */
+public interface VirtualIntentProcessor {
+ /**
+ * Compiles an intent recursively.
+ *
+ * @param networkId virtual network identifier
+ * @param intent intent
+ * @param previousInstallables previous intent installables
+ * @return result of compilation
+ */
+ List<Intent> compile(NetworkId networkId, Intent intent, List<Intent> previousInstallables);
+
+ /**
+ * Applies intents.
+ *
+ * @param networkId virtual network identifier
+ * @param toUninstall Intent data describing flows to uninstall.
+ * @param toInstall Intent data describing flows to install.
+ */
+ void apply(NetworkId networkId, Optional<IntentData> toUninstall,
+ Optional<IntentData> toInstall);
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentSkipped.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentSkipped.java
new file mode 100644
index 0000000..df7f451
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/VirtualIntentSkipped.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent;
+
+import org.onosproject.incubator.net.virtual.impl.intent.phase.VirtualFinalIntentProcessPhase;
+import org.onosproject.net.intent.IntentData;
+
+/**
+ * Represents a phase where an intent is not compiled for a virtual network.
+ * This should be used if a new version of the intent will immediately override
+ * this one.
+ */
+public final class VirtualIntentSkipped extends VirtualFinalIntentProcessPhase {
+
+ private static final VirtualIntentSkipped SINGLETON = new VirtualIntentSkipped();
+
+ /**
+ * Returns a shared skipped phase.
+ *
+ * @return skipped phase
+ */
+ public static VirtualIntentSkipped getPhase() {
+ return SINGLETON;
+ }
+
+ // Prevent object construction; use getPhase()
+ private VirtualIntentSkipped() {
+ }
+
+ @Override
+ public IntentData data() {
+ return null;
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/package-info.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/package-info.java
new file mode 100644
index 0000000..c6758ae
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Core subsystem for tracking high-level intents for treatment of selected
+ * network traffic for virtual networks.
+ */
+package org.onosproject.incubator.net.virtual.impl.intent;
\ No newline at end of file
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualFinalIntentProcessPhase.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualFinalIntentProcessPhase.java
new file mode 100644
index 0000000..978c95c
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualFinalIntentProcessPhase.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.net.intent.IntentData;
+
+import java.util.Optional;
+
+/**
+ * Represents a final phase of processing an intent for virtual networks.
+ */
+public abstract class VirtualFinalIntentProcessPhase
+ implements VirtualIntentProcessPhase {
+
+ @Override
+ public final Optional<VirtualIntentProcessPhase> execute() {
+ preExecute();
+ return Optional.empty();
+ }
+
+ /**
+ * Executes operations that must take place before the phase starts.
+ */
+ protected void preExecute() {}
+
+ /**
+ * Returns the IntentData object being acted on by this phase.
+ *
+ * @return intent data object for the phase
+ */
+ public abstract IntentData data();
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentCompiling.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentCompiling.java
new file mode 100644
index 0000000..639c04c
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentCompiling.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentProcessor;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents a phase where an intent is being compiled or recompiled
+ * for virtual networks.
+ */
+public class VirtualIntentCompiling implements VirtualIntentProcessPhase {
+ private static final Logger log = LoggerFactory.getLogger(VirtualIntentCompiling.class);
+
+ private final NetworkId networkId;
+ private final VirtualIntentProcessor processor;
+ private final IntentData data;
+ private final Optional<IntentData> stored;
+
+ /**
+ * Creates a intent recompiling phase.
+ *
+ * @param networkId virtual network identifier
+ * @param processor intent processor that does work for recompiling
+ * @param data intent data containing an intent to be recompiled
+ * @param stored intent data stored in the store
+ */
+ VirtualIntentCompiling(NetworkId networkId, VirtualIntentProcessor processor,
+ IntentData data, Optional<IntentData> stored) {
+ this.networkId = checkNotNull(networkId);
+ this.processor = checkNotNull(processor);
+ this.data = checkNotNull(data);
+ this.stored = checkNotNull(stored);
+ }
+
+ @Override
+ public Optional<VirtualIntentProcessPhase> execute() {
+ try {
+ List<Intent> compiled = processor
+ .compile(networkId, data.intent(),
+ //TODO consider passing an optional here in the future
+ stored.map(IntentData::installables).orElse(null));
+ return Optional.of(new VirtualIntentInstalling(networkId, processor,
+ IntentData.compiled(data, compiled), stored));
+ } catch (IntentException e) {
+ log.warn("Unable to compile intent {} due to:", data.intent(), e);
+ if (stored.filter(x -> !x.installables().isEmpty()).isPresent()) {
+ // removing orphaned flows and deallocating resources
+ return Optional.of(
+ new VirtualIntentWithdrawing(networkId, processor,
+ new IntentData(data, stored.get().installables())));
+ } else {
+ return Optional.of(new VirtualIntentFailed(data));
+ }
+ }
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentFailed.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentFailed.java
new file mode 100644
index 0000000..dff1d13
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentFailed.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.net.intent.IntentData;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.intent.IntentState.FAILED;
+
+/**
+ * Represents a phase where the compile has failed.
+ */
+public class VirtualIntentFailed extends VirtualFinalIntentProcessPhase {
+
+ private final IntentData data;
+
+ /**
+ * Create an instance with the specified data.
+ *
+ * @param data intentData
+ */
+ VirtualIntentFailed(IntentData data) {
+ this.data = IntentData.nextState(checkNotNull(data), FAILED);
+ }
+
+ @Override
+ public IntentData data() {
+ return data;
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentInstallRequest.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentInstallRequest.java
new file mode 100644
index 0000000..08bfec7
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentInstallRequest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentProcessor;
+import org.onosproject.net.intent.IntentData;
+
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.incubator.net.virtual.impl.intent.phase.VirtualIntentProcessPhase.transferErrorCount;
+
+/**
+ * Represents a phase where intent installation has been requested
+ * for a virtual network.
+ */
+final class VirtualIntentInstallRequest implements VirtualIntentProcessPhase {
+
+ private final NetworkId networkId;
+ private final VirtualIntentProcessor processor;
+ private final IntentData data;
+ private final Optional<IntentData> stored;
+
+ /**
+ * Creates an install request phase.
+ *
+ * @param networkId virtual network identifier
+ * @param processor intent processor to be passed to intent process phases
+ * generated after this phase
+ * @param intentData intent data to be processed
+ * @param stored intent data stored in the store
+ */
+ VirtualIntentInstallRequest(NetworkId networkId, VirtualIntentProcessor processor,
+ IntentData intentData, Optional<IntentData> stored) {
+ this.networkId = checkNotNull(networkId);
+ this.processor = checkNotNull(processor);
+ this.data = checkNotNull(intentData);
+ this.stored = checkNotNull(stored);
+ }
+
+ @Override
+ public Optional<VirtualIntentProcessPhase> execute() {
+ transferErrorCount(data, stored);
+
+ return Optional.of(new VirtualIntentCompiling(networkId, processor, data, stored));
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentInstalling.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentInstalling.java
new file mode 100644
index 0000000..cd8a185
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentInstalling.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentProcessor;
+import org.onosproject.net.intent.IntentData;
+
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.intent.IntentState.INSTALLING;
+
+/**
+ * Represents a phase where an intent is being installed for a virtual network.
+ */
+//FIXME: better way to implement intent phase and processing for virtual networks?
+public class VirtualIntentInstalling extends VirtualFinalIntentProcessPhase {
+
+ private final NetworkId networkId;
+ private final VirtualIntentProcessor processor;
+ private final IntentData data;
+ private final Optional<IntentData> stored;
+
+ /**
+ * Create an installing phase.
+ *
+ * @param networkId virtual network identifier
+ * @param processor intent processor that does work for installing
+ * @param data intent data containing an intent to be installed
+ * @param stored intent data already stored
+ */
+ VirtualIntentInstalling(NetworkId networkId, VirtualIntentProcessor processor,
+ IntentData data,
+ Optional<IntentData> stored) {
+ this.networkId = checkNotNull(networkId);
+ this.processor = checkNotNull(processor);
+ this.data = checkNotNull(data);
+ this.stored = checkNotNull(stored);
+ this.data.setState(INSTALLING);
+ }
+
+ @Override
+ public void preExecute() {
+ processor.apply(networkId, stored, Optional.of(data));
+ }
+
+ @Override
+ public IntentData data() {
+ return data;
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentProcessPhase.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentProcessPhase.java
new file mode 100644
index 0000000..99fab54
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentProcessPhase.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentProcessor;
+import org.onosproject.net.intent.IntentData;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * Represents a phase of processing an intent.
+ */
+public interface VirtualIntentProcessPhase {
+ /**
+ * Execute the procedure represented by the instance
+ * and generates the next update instance.
+ *
+ * @return next update
+ */
+ Optional<VirtualIntentProcessPhase> execute();
+
+ /**
+ * Create a starting intent process phase according to intent data this class holds.
+ *
+ * @param networkId virtual network identifier
+ * @param processor intent processor to be passed to intent process phases
+ * generated while this instance is working
+ * @param data intent data to be processed
+ * @param current intent date that is stored in the store
+ * @return starting intent process phase
+ */
+ static VirtualIntentProcessPhase newInitialPhase(NetworkId networkId,
+ VirtualIntentProcessor processor,
+ IntentData data, IntentData current) {
+ switch (data.request()) {
+ case INSTALL_REQ:
+ return new VirtualIntentInstallRequest(networkId, processor, data,
+ Optional.ofNullable(current));
+ case WITHDRAW_REQ:
+ return new VirtualIntentWithdrawRequest(networkId, processor, data,
+ Optional.ofNullable(current));
+ case PURGE_REQ:
+ return new VirtualIntentPurgeRequest(data, Optional.ofNullable(current));
+ default:
+ // illegal state
+ return new VirtualIntentFailed(data);
+ }
+ }
+
+ static VirtualFinalIntentProcessPhase process(VirtualIntentProcessPhase initial) {
+ Optional<VirtualIntentProcessPhase> currentPhase = Optional.of(initial);
+ VirtualIntentProcessPhase previousPhase = initial;
+
+ while (currentPhase.isPresent()) {
+ previousPhase = currentPhase.get();
+ currentPhase = previousPhase.execute();
+ }
+ return (VirtualFinalIntentProcessPhase) previousPhase;
+ }
+
+ static void transferErrorCount(IntentData data, Optional<IntentData> stored) {
+ stored.ifPresent(storedData -> {
+ if (Objects.equals(data.intent(), storedData.intent()) &&
+ Objects.equals(data.request(), storedData.request())) {
+ data.setErrorCount(storedData.errorCount());
+ } else {
+ data.setErrorCount(0);
+ }
+ });
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentPurgeRequest.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentPurgeRequest.java
new file mode 100644
index 0000000..a6f29ea
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentPurgeRequest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentState;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Represents a phase of requesting a purge of an intent for a virtual network.
+ * Note: The purge will only succeed if the intent is FAILED or WITHDRAWN.
+ */
+final class VirtualIntentPurgeRequest extends VirtualFinalIntentProcessPhase {
+ private static final Logger log = getLogger(VirtualIntentPurgeRequest.class);
+
+ private final IntentData data;
+ protected final Optional<IntentData> stored;
+
+ VirtualIntentPurgeRequest(IntentData intentData, Optional<IntentData> stored) {
+ this.data = checkNotNull(intentData);
+ this.stored = checkNotNull(stored);
+ }
+
+ private boolean shouldAcceptPurge() {
+ if (!stored.isPresent()) {
+ log.info("Purge for intent {}, but intent is not present",
+ data.key());
+ return true;
+ }
+
+ IntentData storedData = stored.get();
+ if (storedData.state() == IntentState.WITHDRAWN
+ || storedData.state() == IntentState.FAILED) {
+ return true;
+ }
+ log.info("Purge for intent {} is rejected because intent state is {}",
+ data.key(), storedData.state());
+ return false;
+ }
+
+ @Override
+ public IntentData data() {
+ if (shouldAcceptPurge()) {
+ return data;
+ } else {
+ return stored.get();
+ }
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentWithdrawRequest.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentWithdrawRequest.java
new file mode 100644
index 0000000..ce8dfc9
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentWithdrawRequest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentProcessor;
+import org.onosproject.net.intent.IntentData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.incubator.net.virtual.impl.intent.phase.VirtualIntentProcessPhase.transferErrorCount;
+
+/**
+ * Represents a phase of requesting a withdraw of an intent for a virtual network.
+ */
+final class VirtualIntentWithdrawRequest implements VirtualIntentProcessPhase {
+ private static final Logger log = LoggerFactory.getLogger(VirtualIntentWithdrawRequest.class);
+
+ private final NetworkId networkId;
+ private final VirtualIntentProcessor processor;
+ private final IntentData data;
+ private final Optional<IntentData> stored;
+
+ /**
+ * Creates a withdraw request phase.
+ *
+ * @param networkId virtual network identifier
+ * @param processor intent processor to be passed to intent process phases
+ * generated after this phase
+ * @param intentData intent data to be processed
+ * @param stored intent data stored in the store
+ */
+ VirtualIntentWithdrawRequest(NetworkId networkId, VirtualIntentProcessor processor,
+ IntentData intentData, Optional<IntentData> stored) {
+ this.networkId = checkNotNull(networkId);
+ this.processor = checkNotNull(processor);
+ this.data = checkNotNull(intentData);
+ this.stored = checkNotNull(stored);
+ }
+
+ @Override
+ public Optional<VirtualIntentProcessPhase> execute() {
+ //TODO perhaps we want to validate that the pending and current are the
+ // same version i.e. they are the same
+ // Note: this call is not just the symmetric version of submit
+
+ transferErrorCount(data, stored);
+
+ if (!stored.isPresent() || stored.get().installables().isEmpty()) {
+ switch (data.request()) {
+ case INSTALL_REQ:
+ // illegal state?
+ log.warn("{} was requested to withdraw during installation?", data.intent());
+ return Optional.of(new VirtualIntentFailed(data));
+ case WITHDRAW_REQ:
+ default: //TODO "default" case should not happen
+ return Optional.of(new VirtualIntentWithdrawn(data));
+ }
+ }
+
+ return Optional.of(new VirtualIntentWithdrawing(networkId, processor,
+ new IntentData(data, stored.get().installables())));
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentWithdrawing.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentWithdrawing.java
new file mode 100644
index 0000000..f7a2867
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentWithdrawing.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.impl.intent.VirtualIntentProcessor;
+import org.onosproject.net.intent.IntentData;
+
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.intent.IntentState.WITHDRAWING;
+
+/**
+ * Represents a phase where an intent is withdrawing.
+ */
+final class VirtualIntentWithdrawing extends VirtualFinalIntentProcessPhase {
+
+ private final NetworkId networkId;
+ private final VirtualIntentProcessor processor;
+ private final IntentData data;
+
+ /**
+ * Creates a withdrawing phase.
+ *
+ * @param networkId virtual network identifier
+ * @param processor intent processor that does work for withdrawing
+ * @param data intent data containing an intent to be withdrawn
+ */
+ VirtualIntentWithdrawing(NetworkId networkId, VirtualIntentProcessor processor,
+ IntentData data) {
+ this.networkId = checkNotNull(networkId);
+ this.processor = checkNotNull(processor);
+ this.data = checkNotNull(data);
+ this.data.setState(WITHDRAWING);
+ }
+
+ @Override
+ protected void preExecute() {
+ processor.apply(networkId, Optional.of(data), Optional.empty());
+ }
+
+ @Override
+ public IntentData data() {
+ return data;
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentWithdrawn.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentWithdrawn.java
new file mode 100644
index 0000000..7e592c2
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/VirtualIntentWithdrawn.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
+
+import org.onosproject.net.intent.IntentData;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.net.intent.IntentState.WITHDRAWN;
+
+/**
+ * Represents a phase where an intent has been withdrawn for a virtual network.
+ */
+final class VirtualIntentWithdrawn extends VirtualFinalIntentProcessPhase {
+
+ private final IntentData data;
+
+ /**
+ * Create a withdrawn phase.
+ *
+ * @param data intent data containing an intent to be withdrawn
+ */
+ VirtualIntentWithdrawn(IntentData data) {
+ this.data = IntentData.nextState(checkNotNull(data), WITHDRAWN);
+ }
+
+ @Override
+ public IntentData data() {
+ return data;
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/package-info.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/package-info.java
new file mode 100644
index 0000000..5fac168
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/intent/phase/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implementations of various intent processing phases for virtual networks.
+ */
+package org.onosproject.incubator.net.virtual.impl.intent.phase;
\ No newline at end of file
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManagerTest.java
index 0695d4e..60521b4 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentManagerTest.java
@@ -217,9 +217,7 @@
virtualNetworkManagerStore.updateLink(link4, link4.tunnelId(), Link.State.ACTIVE);
vnetIntentService = new VirtualNetworkIntentManager(manager, virtualNetwork.id());
- vnetIntentService.intentService = intentService;
vnetIntentService.intentStore = intentStore;
- vnetIntentService.partitionService = workPartitionService;
return virtualNetwork;
}
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManagerTest.java
index d47caed..7f5a5fe 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManagerTest.java
@@ -44,6 +44,7 @@
import org.onosproject.incubator.net.virtual.VirtualNetworkFlowRuleStore;
import org.onosproject.incubator.net.virtual.VirtualNetworkGroupStore;
import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntentStore;
import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
import org.onosproject.incubator.net.virtual.VirtualNetworkPacketStore;
import org.onosproject.incubator.net.virtual.VirtualPort;
@@ -58,6 +59,7 @@
import org.onosproject.incubator.store.virtual.impl.SimpleVirtualFlowObjectiveStore;
import org.onosproject.incubator.store.virtual.impl.SimpleVirtualFlowRuleStore;
import org.onosproject.incubator.store.virtual.impl.SimpleVirtualGroupStore;
+import org.onosproject.incubator.store.virtual.impl.SimpleVirtualIntentStore;
import org.onosproject.incubator.store.virtual.impl.SimpleVirtualPacketStore;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
@@ -854,11 +856,10 @@
validateServiceGetReturnsSavedInstance(virtualNetwork.id(), DeviceService.class);
validateServiceGetReturnsSavedInstance(virtualNetwork.id(), LinkService.class);
validateServiceGetReturnsSavedInstance(virtualNetwork.id(), TopologyService.class);
- validateServiceGetReturnsSavedInstance(virtualNetwork.id(), IntentService.class);
validateServiceGetReturnsSavedInstance(virtualNetwork.id(), HostService.class);
validateServiceGetReturnsSavedInstance(virtualNetwork.id(), PathService.class);
- // extra setup needed for FlowRuleService, PacketService, GroupService
+ // extra setup needed for FlowRuleService, PacketService, GroupService, and IntentService
VirtualProviderManager virtualProviderManager = new VirtualProviderManager();
virtualProviderManager.registerProvider(new DefaultVirtualFlowRuleProvider());
virtualProviderManager.registerProvider(new DefaultVirtualPacketProvider());
@@ -870,12 +871,14 @@
.add(VirtualNetworkFlowRuleStore.class, new SimpleVirtualFlowRuleStore())
.add(VirtualNetworkPacketStore.class, new SimpleVirtualPacketStore())
.add(VirtualNetworkGroupStore.class, new SimpleVirtualGroupStore())
+ .add(VirtualNetworkIntentStore.class, new SimpleVirtualIntentStore())
.add(VirtualNetworkFlowObjectiveStore.class, new SimpleVirtualFlowObjectiveStore());
validateServiceGetReturnsSavedInstance(virtualNetwork.id(), FlowRuleService.class);
validateServiceGetReturnsSavedInstance(virtualNetwork.id(), FlowObjectiveService.class);
validateServiceGetReturnsSavedInstance(virtualNetwork.id(), PacketService.class);
validateServiceGetReturnsSavedInstance(virtualNetwork.id(), GroupService.class);
+ validateServiceGetReturnsSavedInstance(virtualNetwork.id(), IntentService.class);
}
/**