ONOS-2184 - Initial implementation of Virtual network Intent service.

Change-Id: I03103b4eca797cd32480fbd0e3b4cf0385b50ef2
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntent.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntent.java
new file mode 100644
index 0000000..acdbe44
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntent.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.ConnectivityIntent;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Key;
+
+import java.util.Collections;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Abstraction of VirtualNetworkIntent connectivity.
+ */
+@Beta
+public final class VirtualNetworkIntent extends ConnectivityIntent {
+
+    private final NetworkId networkId;
+    private final ConnectPoint ingressPoint;
+    private final ConnectPoint egressPoint;
+
+    private static final String NETWORK_ID_NULL = "Network ID cannot be null";
+
+    /**
+     * Returns a new point to point intent builder. The application id,
+     * ingress point and egress point are required fields.  If they are
+     * not set by calls to the appropriate methods, an exception will
+     * be thrown.
+     *
+     * @return point to point builder
+     */
+    public static VirtualNetworkIntent.Builder builder() {
+        return new VirtualNetworkIntent.Builder();
+    }
+
+    /**
+     * Builder of a point to point intent.
+     */
+    public static final class Builder extends ConnectivityIntent.Builder {
+        NetworkId networkId;
+        ConnectPoint ingressPoint;
+        ConnectPoint egressPoint;
+
+        /**
+         * Builder constructor.
+         */
+        private Builder() {
+            // Hide constructor
+        }
+
+        @Override
+        public VirtualNetworkIntent.Builder appId(ApplicationId appId) {
+            return (VirtualNetworkIntent.Builder) super.appId(appId);
+        }
+
+        @Override
+        public VirtualNetworkIntent.Builder key(Key key) {
+            return (VirtualNetworkIntent.Builder) super.key(key);
+        }
+
+        @Override
+        public VirtualNetworkIntent.Builder selector(TrafficSelector selector) {
+            return (VirtualNetworkIntent.Builder) super.selector(selector);
+        }
+
+        @Override
+        public VirtualNetworkIntent.Builder treatment(TrafficTreatment treatment) {
+            return (VirtualNetworkIntent.Builder) super.treatment(treatment);
+        }
+
+        @Override
+        public VirtualNetworkIntent.Builder constraints(List<Constraint> constraints) {
+            return (VirtualNetworkIntent.Builder) super.constraints(constraints);
+        }
+
+        @Override
+        public VirtualNetworkIntent.Builder priority(int priority) {
+            return (VirtualNetworkIntent.Builder) super.priority(priority);
+        }
+
+        /**
+         * Sets the virtual network of the virtual network intent.
+         *
+         * @param networkId virtual network identifier
+         * @return this builder
+         */
+        public VirtualNetworkIntent.Builder networkId(NetworkId networkId) {
+            this.networkId = networkId;
+            return this;
+        }
+
+        /**
+         * Sets the ingress point of the virtual network intent that will be built.
+         *
+         * @param ingressPoint ingress connect point
+         * @return this builder
+         */
+        public VirtualNetworkIntent.Builder ingressPoint(ConnectPoint ingressPoint) {
+            this.ingressPoint = ingressPoint;
+            return this;
+        }
+
+        /**
+         * Sets the egress point of the virtual network intent that will be built.
+         *
+         * @param egressPoint egress connect point
+         * @return this builder
+         */
+        public VirtualNetworkIntent.Builder egressPoint(ConnectPoint egressPoint) {
+            this.egressPoint = egressPoint;
+            return this;
+        }
+
+        /**
+         * Builds a virtual network intent from the accumulated parameters.
+         *
+         * @return virtual network intent
+         */
+        public VirtualNetworkIntent build() {
+
+            return new VirtualNetworkIntent(
+                    networkId,
+                    appId,
+                    key,
+                    selector,
+                    treatment,
+                    ingressPoint,
+                    egressPoint,
+                    constraints,
+                    priority
+            );
+        }
+    }
+
+
+    /**
+     * Creates a new point-to-point intent with the supplied ingress/egress
+     * ports and constraints.
+     *
+     * @param networkId    virtual network identifier
+     * @param appId        application identifier
+     * @param key          key of the intent
+     * @param selector     traffic selector
+     * @param treatment    treatment
+     * @param ingressPoint ingress port
+     * @param egressPoint  egress port
+     * @param constraints  optional list of constraints
+     * @param priority     priority to use for flows generated by this intent
+     * @throws NullPointerException if {@code ingressPoint} or
+     *                              {@code egressPoints} or {@code appId} is null.
+     */
+    private VirtualNetworkIntent(NetworkId networkId,
+                                 ApplicationId appId,
+                                 Key key,
+                                 TrafficSelector selector,
+                                 TrafficTreatment treatment,
+                                 ConnectPoint ingressPoint,
+                                 ConnectPoint egressPoint,
+                                 List<Constraint> constraints,
+                                 int priority) {
+        super(appId, key, Collections.emptyList(), selector, treatment, constraints,
+              priority);
+
+        checkNotNull(networkId, NETWORK_ID_NULL);
+        checkArgument(!ingressPoint.equals(egressPoint),
+                      "ingress and egress should be different (ingress: %s, egress: %s)", ingressPoint, egressPoint);
+
+        this.networkId = networkId;
+        this.ingressPoint = checkNotNull(ingressPoint);
+        this.egressPoint = checkNotNull(egressPoint);
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected VirtualNetworkIntent() {
+        super();
+        this.networkId = null;
+        this.ingressPoint = null;
+        this.egressPoint = null;
+    }
+
+    /**
+     * Returns the virtual network identifier.
+     *
+     * @return network identifier
+     */
+    public NetworkId networkId() {
+        return networkId;
+    }
+
+    /**
+     * Returns the port on which the ingress traffic should be connected to
+     * the egress.
+     *
+     * @return ingress port
+     */
+    public ConnectPoint ingressPoint() {
+        return ingressPoint;
+    }
+
+    /**
+     * Returns the port on which the traffic should egress.
+     *
+     * @return egress port
+     */
+    public ConnectPoint egressPoint() {
+        return egressPoint;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("networkId", networkId)
+                .add("id", id())
+                .add("key", key())
+                .add("appId", appId())
+                .add("priority", priority())
+                .add("resources", resources())
+                .add("selector", selector())
+                .add("treatment", treatment())
+                .add("ingress", ingressPoint)
+                .add("egress", egressPoint)
+                .add("constraints", constraints())
+                .toString();
+    }
+
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
index c2bc250..5deff3c 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
@@ -26,6 +26,10 @@
 import org.onosproject.net.Link;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
 import org.onosproject.store.Store;
 
 import java.util.Set;
@@ -223,4 +227,73 @@
      */
     Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId);
 
+    /**
+     * Add or update the intent to the store.
+     *
+     * @param intent virtual intent
+     * @param state  intent state
+     */
+    void addOrUpdateIntent(Intent intent, IntentState state);
+
+    /**
+     * Remove the virtual intent from the store.
+     *
+     * @param intentKey intent key
+     * @return intent data
+     */
+    IntentData removeIntent(Key intentKey);
+
+    /**
+     * Adds the intent to tunnel identifier mapping to the store.
+     *
+     * @param intent   intent
+     * @param tunnelId tunnel identifier
+     */
+    void addTunnelId(Intent intent, TunnelId tunnelId);
+
+    /**
+     * Return the set of tunnel identifiers store against the intent.
+     *
+     * @param intent intent
+     * @return set of tunnel identifiers
+     */
+    Set<TunnelId> getTunnelIds(Intent intent);
+
+    /**
+     * Removes the intent to tunnel identifier mapping from the store.
+     *
+     * @param intent   intent
+     * @param tunnelId tunnel identifier
+     */
+    void removeTunnelId(Intent intent, TunnelId tunnelId);
+
+    /**
+     * Return all intents.
+     *
+     * @return set of intents
+     */
+    Set<Intent> getIntents();
+
+    /**
+     * Return the intent for the specified intent key.
+     *
+     * @param key intent key
+     * @return intent
+     */
+    Intent getIntent(Key key);
+
+    /**
+     * Return the set of intent data.
+     *
+     * @return set of intent data
+     */
+    Set<IntentData> getIntentData();
+
+    /**
+     * Return the intent data matching the intent key.
+     *
+     * @param key intent key
+     * @return intent data
+     */
+    IntentData getIntentData(Key key);
 }
diff --git a/incubator/net/BUCK b/incubator/net/BUCK
index fba929b..17fa793 100644
--- a/incubator/net/BUCK
+++ b/incubator/net/BUCK
@@ -2,13 +2,15 @@
     '//lib:CORE_DEPS',
     '//core/common:onos-core-common',
     '//incubator/api:onos-incubator-api',
+    '//incubator/store:onos-incubator-store',
+    '//utils/rest:onlab-rest',
 ]
 
 TEST_DEPS = [
+    '//lib:TEST_REST',
     '//lib:TEST_ADAPTERS',
     '//core/api:onos-api-tests',
     '//core/common:onos-core-common-tests',
-    '//incubator/store:onos-incubator-store',
     '//core/store/serializers:onos-core-serializers',
     '//lib:concurrent-trees',
 ]
diff --git a/incubator/net/pom.xml b/incubator/net/pom.xml
index 0346ac4..e5ea75c 100644
--- a/incubator/net/pom.xml
+++ b/incubator/net/pom.xml
@@ -95,6 +95,14 @@
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.scr.annotations</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-osgi</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentService.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentService.java
new file mode 100644
index 0000000..191bec2
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentService.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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;
+
+import com.google.common.collect.Iterators;
+import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.event.AbstractListenerManager;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkService;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
+import org.onosproject.incubator.net.virtual.VirtualPort;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.IntentPartitionService;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.*;
+
+/**
+ * intent service implementation built on the virtual network service.
+ */
+public class VirtualNetworkIntentService extends AbstractListenerManager<IntentEvent, IntentListener>
+        implements IntentService, VnetService {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private static final String NETWORK_NULL = "Network cannot be null";
+    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";
+    private static final String KEY_NULL = "Key cannot be null";
+    private static final String APP_ID_NULL = "Intent app identifier cannot be null";
+    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;
+    protected IntentPartitionService partitionService;
+
+    private final VirtualNetwork network;
+    private final VirtualNetworkService manager;
+
+    /**
+     * Creates a new VirtualNetworkIntentService object.
+     *
+     * @param virtualNetworkManager virtual network manager service
+     * @param network               virtual network
+     * @param serviceDirectory      service directory
+     */
+    public VirtualNetworkIntentService(VirtualNetworkService virtualNetworkManager, VirtualNetwork network,
+                                       ServiceDirectory serviceDirectory) {
+        checkNotNull(network, NETWORK_NULL);
+        this.network = network;
+        this.manager = virtualNetworkManager;
+        this.store = serviceDirectory.get(VirtualNetworkStore.class);
+        this.intentService = serviceDirectory.get(IntentService.class);
+        this.partitionService = serviceDirectory.get(IntentPartitionService.class);
+    }
+
+    @Override
+    public void submit(Intent intent) {
+        checkNotNull(intent, INTENT_NULL);
+        checkState(intent instanceof VirtualNetworkIntent, "Only VirtualNetworkIntent is supported.");
+        checkArgument(validateIntent((VirtualNetworkIntent) intent), "Invalid Intent");
+
+        intentService.submit(intent);
+    }
+
+    /**
+     * Returns true if the virtual network intent is valid.
+     *
+     * @param intent virtual network intent
+     * @return true if intent is valid
+     */
+    private boolean validateIntent(VirtualNetworkIntent intent) {
+        checkNotNull(intent, INTENT_NULL);
+        checkNotNull(intent.networkId(), NETWORK_ID_NULL);
+        checkNotNull(intent.appId(), APP_ID_NULL);
+        checkNotNull(intent.key(), INTENT_KEY_NULL);
+        ConnectPoint ingressPoint = intent.ingressPoint();
+        ConnectPoint egressPoint = intent.egressPoint();
+
+        return (validateConnectPoint(ingressPoint) && validateConnectPoint(egressPoint));
+    }
+
+    /**
+     * Returns true if the connect point is valid.
+     *
+     * @param connectPoint connect point
+     * @return true if connect point is valid
+     */
+    private boolean validateConnectPoint(ConnectPoint connectPoint) {
+        checkNotNull(connectPoint, CP_NULL);
+        Port port = getPort(connectPoint.deviceId(), connectPoint.port());
+        return port == null ? false : true;
+    }
+
+    /**
+     * Returns the virtual port for the given device identifier and port number.
+     *
+     * @param deviceId   virtual device identifier
+     * @param portNumber virtual port number
+     * @return virtual port
+     */
+    private Port getPort(DeviceId deviceId, PortNumber portNumber) {
+        checkNotNull(deviceId, DEVICE_NULL);
+
+        Optional<VirtualPort> foundPort = manager.getVirtualPorts(this.network.id(), deviceId)
+                .stream()
+                .filter(port -> port.number().equals(portNumber))
+                .findFirst();
+        if (foundPort.isPresent()) {
+            return foundPort.get();
+        }
+        return null;
+    }
+
+    @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.info("Withdrawing pt-pt intent: " + physicalIntent);
+                    intentService.withdraw(physicalIntent);
+                });
+        // Now withdraw the virtual intent
+        log.info("Withdrawing virtual intent: " + intent);
+        intentService.withdraw(intent);
+    }
+
+    @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);
+    }
+
+    @Override
+    public Intent getIntent(Key key) {
+        checkNotNull(key, KEY_NULL);
+        return store.getIntent(key);
+    }
+
+    @Override
+    public Iterable<Intent> getIntents() {
+        return store.getIntents();
+    }
+
+    @Override
+    public Iterable<IntentData> getIntentData() {
+        return store.getIntentData();
+    }
+
+    @Override
+    public long getIntentCount() {
+        return Iterators.size(getIntents().iterator());
+    }
+
+    @Override
+    public IntentState getIntentState(Key intentKey) {
+        checkNotNull(intentKey, KEY_NULL);
+        return store.getIntentData(intentKey).state();
+    }
+
+    @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;
+    }
+
+    @Override
+    public boolean isLocal(Key intentKey) {
+        checkNotNull(intentKey, INTENT_KEY_NULL);
+        Intent intent = getIntent(intentKey);
+        checkNotNull(intent, INTENT_NULL);
+        return partitionService.isMine(intentKey);
+    }
+
+    @Override
+    public Iterable<Intent> getPending() {
+        return null;
+    }
+
+
+    @Override
+    public VirtualNetwork network() {
+        return network;
+    }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java
index 6c06968..f264658 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java
@@ -22,6 +22,7 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.osgi.DefaultServiceDirectory;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
@@ -34,9 +35,9 @@
 import org.onosproject.incubator.net.virtual.VirtualNetwork;
 import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
 import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
 import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
 import org.onosproject.incubator.net.virtual.VirtualNetworkProvider;
-import org.onosproject.incubator.net.virtual.VirtualNetworkProviderRegistry;
 import org.onosproject.incubator.net.virtual.VirtualNetworkProviderService;
 import org.onosproject.incubator.net.virtual.VirtualNetworkService;
 import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
@@ -50,6 +51,10 @@
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
 import org.onosproject.net.link.LinkService;
 import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
@@ -70,7 +75,7 @@
 public class VirtualNetworkManager
         extends AbstractListenerProviderRegistry<VirtualNetworkEvent, VirtualNetworkListener,
         VirtualNetworkProvider, VirtualNetworkProviderService>
-        implements VirtualNetworkService, VirtualNetworkAdminService, VirtualNetworkProviderRegistry {
+        implements VirtualNetworkService, VirtualNetworkAdminService {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
@@ -78,28 +83,51 @@
     private static final String NETWORK_NULL = "Network ID cannot be null";
     private static final String DEVICE_NULL = "Device ID cannot be null";
     private static final String LINK_POINT_NULL = "Link end-point cannot be null";
-    private static final String VIRTUAL_LINK_NULL = "Virtual Link cannot be null";
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected VirtualNetworkStore store;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentService intentService;
+
+    private final InternalVirtualIntentListener intentListener = new InternalVirtualIntentListener();
+
     private VirtualNetworkStoreDelegate delegate = this::post;
 
     // TODO: figure out how to coordinate "implementation" of a virtual network in a cluster
 
+    /**
+     * Only used for Junit test methods outside of this package.
+     *
+     * @param store virtual network store
+     */
+    public void setStore(VirtualNetworkStore store) {
+        this.store = store;
+    }
+
+    /**
+     * Only used for Junit test methods outside of this package.
+     *
+     * @param intentService intent service
+     */
+
+    public void setIntentService(IntentService intentService) {
+        this.intentService = intentService;
+    }
+
     @Activate
-    protected void activate() {
+    public void activate() {
         store.setDelegate(delegate);
         eventDispatcher.addSink(VirtualNetworkEvent.class, listenerRegistry);
-
+        intentService.addListener(intentListener);
         log.info("Started");
     }
 
     @Deactivate
-    protected void deactivate() {
+    public void deactivate() {
         store.unsetDelegate(delegate);
         eventDispatcher.removeSink(VirtualNetworkEvent.class);
-
+        intentService.removeListener(intentListener);
         log.info("Stopped");
     }
 
@@ -167,48 +195,18 @@
         checkNotNull(networkId, NETWORK_NULL);
         checkNotNull(src, LINK_POINT_NULL);
         checkNotNull(dst, LINK_POINT_NULL);
-        VirtualLink virtualLink = store.addLink(networkId, src, dst, Link.State.INACTIVE, null);
-        checkNotNull(virtualLink, VIRTUAL_LINK_NULL);
-
-        if (virtualLink.providerId() != null) {
-            VirtualNetworkProvider provider = getProvider(virtualLink.providerId());
-            if (provider != null) {
-                TunnelId tunnelId = provider.createTunnel(networkId, mapVirtualToPhysicalPort(networkId, src),
-                                                          mapVirtualToPhysicalPort(networkId, dst));
-                store.updateLink(virtualLink, tunnelId, Link.State.INACTIVE);
-            }
-        }
-        return virtualLink;
-    }
-
-    /**
-     * Maps the virtual connect point to a physical connect point.
-     *
-     * @param networkId network identifier
-     * @param virtualCp virtual connect point
-     * @return physical connect point
-     */
-    private ConnectPoint mapVirtualToPhysicalPort(NetworkId networkId,
-                                                  ConnectPoint virtualCp) {
-        Set<VirtualPort> ports = store.getPorts(networkId, virtualCp.deviceId());
-        for (VirtualPort port : ports) {
-            if (port.element().id().equals(virtualCp.elementId()) &&
-                    port.number().equals(virtualCp.port())) {
-                return new ConnectPoint(port.realizedBy().element().id(), port.realizedBy().number());
-            }
-        }
-        return null;
+        return store.addLink(networkId, src, dst, Link.State.ACTIVE, null);
     }
 
     /**
      * Maps the physical connect point to a virtual connect point.
      *
-     * @param networkId network identifier
+     * @param networkId  network identifier
      * @param physicalCp physical connect point
      * @return virtual connect point
      */
     private ConnectPoint mapPhysicalToVirtualToPort(NetworkId networkId,
-                                                  ConnectPoint physicalCp) {
+                                                    ConnectPoint physicalCp) {
         Set<VirtualPort> ports = store.getPorts(networkId, null);
         for (VirtualPort port : ports) {
             if (port.realizedBy().element().id().equals(physicalCp.elementId()) &&
@@ -224,14 +222,7 @@
         checkNotNull(networkId, NETWORK_NULL);
         checkNotNull(src, LINK_POINT_NULL);
         checkNotNull(dst, LINK_POINT_NULL);
-        VirtualLink virtualLink = store.removeLink(networkId, src, dst);
-
-        if (virtualLink != null && virtualLink.providerId() != null) {
-            VirtualNetworkProvider provider = getProvider(virtualLink.providerId());
-            if (provider != null) {
-                provider.destroyTunnel(networkId, virtualLink.tunnelId());
-            }
-        }
+        store.removeLink(networkId, src, dst);
     }
 
     @Override
@@ -257,6 +248,12 @@
         return store.getNetworks(tenantId);
     }
 
+    /**
+     * Returns the virtual network matching the network identifier.
+     *
+     * @param networkId network identifier
+     * @return virtual network
+     */
     private VirtualNetwork getVirtualNetwork(NetworkId networkId) {
         checkNotNull(networkId, NETWORK_NULL);
         return store.getNetwork(networkId);
@@ -299,17 +296,38 @@
         return (T) service;
     }
 
+    /**
+     * Returns the Vnet service matching the service key.
+     *
+     * @param serviceKey service key
+     * @return vnet service
+     */
     private VnetService lookup(ServiceKey serviceKey) {
         return networkServices.get(serviceKey);
     }
 
+    /**
+     * Creates a new service key using the specified network identifier and service class.
+     *
+     * @param networkId    network identifier
+     * @param serviceClass service class
+     * @param <T>          type of service
+     * @return service key
+     */
     private <T> ServiceKey networkServiceKey(NetworkId networkId, Class<T> serviceClass) {
         return new ServiceKey(networkId, serviceClass);
     }
 
 
+    /**
+     * Create a new vnet service instance.
+     *
+     * @param serviceKey service key
+     * @return vnet service
+     */
     private VnetService create(ServiceKey serviceKey) {
         VirtualNetwork network = getVirtualNetwork(serviceKey.networkId());
+        checkNotNull(network, NETWORK_NULL);
         VnetService service;
         if (serviceKey.serviceClass.equals(DeviceService.class)) {
             service = new VirtualNetworkDeviceService(this, network);
@@ -317,6 +335,8 @@
             service = new VirtualNetworkLinkService(this, network);
         } else if (serviceKey.serviceClass.equals(TopologyService.class)) {
             service = new VirtualNetworkTopologyService(this, network);
+        } else if (serviceKey.serviceClass.equals(IntentService.class)) {
+            service = new VirtualNetworkIntentService(this, network, new DefaultServiceDirectory());
         } else {
             return null;
         }
@@ -324,25 +344,94 @@
         return service;
     }
 
+    /**
+     * Service key class.
+     */
     private class ServiceKey {
         final NetworkId networkId;
         final Class serviceClass;
 
+        /**
+         * Constructor for service key.
+         *
+         * @param networkId    network identifier
+         * @param serviceClass service class
+         */
         public ServiceKey(NetworkId networkId, Class serviceClass) {
             checkNotNull(networkId, NETWORK_NULL);
             this.networkId = networkId;
             this.serviceClass = serviceClass;
         }
 
+        /**
+         * Returns the network identifier.
+         *
+         * @return network identifier
+         */
         public NetworkId networkId() {
             return networkId;
         }
 
+        /**
+         * Returns the service class.
+         *
+         * @return service class
+         */
         public Class serviceClass() {
             return serviceClass;
         }
     }
 
+    /**
+     * Internal intent event listener.
+     */
+    private class InternalVirtualIntentListener implements IntentListener {
+        @Override
+        public void event(IntentEvent event) {
+
+            // Ignore intent events that are not relevant.
+            if (!isRelevant(event)) {
+                return;
+            }
+
+            VirtualNetworkIntent intent = (VirtualNetworkIntent) event.subject();
+
+            switch (event.type()) {
+                case INSTALL_REQ:
+                    store.addOrUpdateIntent(intent, IntentState.INSTALL_REQ);
+                    break;
+                case INSTALLED:
+                    store.addOrUpdateIntent(intent, IntentState.INSTALLED);
+                    break;
+                case WITHDRAW_REQ:
+                    store.addOrUpdateIntent(intent, IntentState.WITHDRAW_REQ);
+                    break;
+                case WITHDRAWN:
+                    store.addOrUpdateIntent(intent, IntentState.WITHDRAWN);
+                    break;
+                case FAILED:
+                    store.addOrUpdateIntent(intent, IntentState.FAILED);
+                    break;
+                case CORRUPT:
+                    store.addOrUpdateIntent(intent, IntentState.CORRUPT);
+                    break;
+                case PURGED:
+                    store.removeIntent(intent.key());
+                default:
+                    break;
+            }
+        }
+
+        @Override
+        public boolean isRelevant(IntentEvent event) {
+            if (event.subject() instanceof VirtualNetworkIntent) {
+                return true;
+            }
+            return false;
+        }
+    }
+
+
     @Override
     protected VirtualNetworkProviderService createProviderService(VirtualNetworkProvider provider) {
         return new InternalVirtualNetworkProviderService(provider);
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkDeviceServiceTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkDeviceServiceTest.java
index ecb8b0d..d44d038 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkDeviceServiceTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkDeviceServiceTest.java
@@ -38,6 +38,8 @@
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.TestDeviceParams;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.TestableIntentService;
 import org.onosproject.store.service.TestStorageService;
 
 import java.util.Iterator;
@@ -54,6 +56,7 @@
     private VirtualNetworkManager manager;
     private DistributedVirtualNetworkStore virtualNetworkManagerStore;
     private CoreService coreService;
+    private TestableIntentService intentService = new FakeIntentManager();
 
     @Before
     public void setUp() throws Exception {
@@ -67,6 +70,7 @@
 
         manager = new VirtualNetworkManager();
         manager.store = virtualNetworkManagerStore;
+        manager.intentService = intentService;
         NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
         manager.activate();
     }
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentServiceTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentServiceTest.java
new file mode 100644
index 0000000..ef8de45
--- /dev/null
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentServiceTest.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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;
+
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.rest.BaseResource;
+import org.onosproject.TestApplicationId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.incubator.net.virtual.TenantId;
+import org.onosproject.incubator.net.virtual.VirtualDevice;
+import org.onosproject.incubator.net.virtual.VirtualLink;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
+import org.onosproject.incubator.store.virtual.impl.DistributedVirtualNetworkStore;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultPort;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.Link;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.TestDeviceParams;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentCompiler;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.IntentPartitionService;
+import org.onosproject.net.intent.IntentPartitionServiceAdapter;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.IntentTestsMocks;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.intent.TestableIntentService;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.store.service.TestStorageService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.junit.Assert.*;
+
+/**
+ * Junit tests for VirtualNetworkIntentService.
+ */
+public class VirtualNetworkIntentServiceTest extends TestDeviceParams {
+
+    private final String tenantIdValue1 = "TENANT_ID1";
+    private static final ApplicationId APP_ID =
+            new TestApplicationId(PtToPtIntentVirtualNetworkProvider.PTPT_INTENT_APPID);
+
+    private ConnectPoint cp1;
+    private ConnectPoint cp2;
+    private ConnectPoint cp3;
+    private ConnectPoint cp4;
+    private ConnectPoint cp5;
+    private ConnectPoint cp6;
+    private VirtualLink link1;
+    private VirtualLink link2;
+    private VirtualLink link3;
+    private VirtualLink link4;
+    private VirtualLink link5;
+    private VirtualLink link6;
+
+    private VirtualNetworkManager manager;
+    private static DistributedVirtualNetworkStore virtualNetworkManagerStore;
+    private CoreService coreService;
+    private TestableIntentService intentService = new FakeIntentManager();
+    private VirtualNetworkIntentService vnetIntentService;
+    private TestIntentCompiler compiler = new TestIntentCompiler();
+    private IntentExtensionService intentExtensionService;
+    private IntentPartitionService intentPartitionService;
+    private ServiceDirectory testDirectory;
+    private TestListener listener = new TestListener();
+    private IdGenerator idGenerator = new MockIdGenerator();
+    private static final int MAX_WAIT_TIME = 5;
+    private static final int MAX_PERMITS = 1;
+    private static Semaphore created;
+    private static Semaphore withdrawn;
+    private static Semaphore purged;
+
+    @Before
+    public void setUp() throws Exception {
+        virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
+
+        coreService = new VirtualNetworkIntentServiceTest.TestCoreService();
+
+        Intent.unbindIdGenerator(idGenerator);
+        Intent.bindIdGenerator(idGenerator);
+
+        virtualNetworkManagerStore.setCoreService(coreService);
+        TestUtils.setField(coreService, "coreService", new VirtualNetworkIntentServiceTest.TestCoreService());
+        TestUtils.setField(virtualNetworkManagerStore, "storageService", new TestStorageService());
+        virtualNetworkManagerStore.activate();
+
+        manager = new VirtualNetworkManager();
+        manager.store = virtualNetworkManagerStore;
+        NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
+        manager.intentService = intentService;
+        manager.activate();
+        intentService.addListener(listener);
+
+        // Register a compiler and an installer both setup for success.
+        intentExtensionService = intentService;
+        intentExtensionService.registerCompiler(VirtualNetworkIntent.class, compiler);
+
+        created = new Semaphore(0, true);
+        withdrawn = new Semaphore(0, true);
+        purged = new Semaphore(0, true);
+
+        intentPartitionService = new IntentPartitionServiceAdapter();
+        testDirectory = new TestServiceDirectory()
+                .add(VirtualNetworkStore.class, virtualNetworkManagerStore)
+                .add(IntentService.class, intentService)
+                .add(IntentPartitionService.class, intentPartitionService);
+        BaseResource.setServiceDirectory(testDirectory);
+    }
+
+    @After
+    public void tearDown() {
+        virtualNetworkManagerStore.deactivate();
+        manager.deactivate();
+        NetTestTools.injectEventDispatcher(manager, null);
+        Intent.unbindIdGenerator(idGenerator);
+        intentService.removeListener(listener);
+        created = null;
+        withdrawn = null;
+        purged = null;
+    }
+
+    /**
+     * Method to create the virtual network for further testing.
+     *
+     * @return virtual network
+     */
+    private VirtualNetwork setupVirtualNetworkTopology() {
+        manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
+        VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
+        VirtualDevice virtualDevice1 =
+                manager.createVirtualDevice(virtualNetwork.id(), DID1);
+        VirtualDevice virtualDevice2 =
+                manager.createVirtualDevice(virtualNetwork.id(), DID2);
+        VirtualDevice virtualDevice3 =
+                manager.createVirtualDevice(virtualNetwork.id(), DID3);
+        VirtualDevice virtualDevice4 =
+                manager.createVirtualDevice(virtualNetwork.id(), DID4);
+
+        Port port1 = new DefaultPort(virtualDevice1, PortNumber.portNumber(1), true);
+        manager.createVirtualPort(virtualNetwork.id(), virtualDevice1.id(), port1.number(), port1);
+        cp1 = new ConnectPoint(virtualDevice1.id(), port1.number());
+
+        Port port2 = new DefaultPort(virtualDevice1, PortNumber.portNumber(2), true);
+        manager.createVirtualPort(virtualNetwork.id(), virtualDevice1.id(), port2.number(), port2);
+        cp2 = new ConnectPoint(virtualDevice1.id(), port2.number());
+
+        Port port3 = new DefaultPort(virtualDevice2, PortNumber.portNumber(3), true);
+        manager.createVirtualPort(virtualNetwork.id(), virtualDevice2.id(), port3.number(), port3);
+        cp3 = new ConnectPoint(virtualDevice2.id(), port3.number());
+
+        Port port4 = new DefaultPort(virtualDevice2, PortNumber.portNumber(4), true);
+        manager.createVirtualPort(virtualNetwork.id(), virtualDevice2.id(), port4.number(), port4);
+        cp4 = new ConnectPoint(virtualDevice2.id(), port4.number());
+
+        Port port5 = new DefaultPort(virtualDevice3, PortNumber.portNumber(5), true);
+        manager.createVirtualPort(virtualNetwork.id(), virtualDevice3.id(), port5.number(), port5);
+        cp5 = new ConnectPoint(virtualDevice3.id(), port5.number());
+
+        Port port6 = new DefaultPort(virtualDevice3, PortNumber.portNumber(6), true);
+        manager.createVirtualPort(virtualNetwork.id(), virtualDevice3.id(), port6.number(), port6);
+        cp6 = new ConnectPoint(virtualDevice3.id(), port6.number());
+
+        link1 = manager.createVirtualLink(virtualNetwork.id(), cp1, cp3);
+        virtualNetworkManagerStore.updateLink(link1, link1.tunnelId(), Link.State.ACTIVE);
+        link2 = manager.createVirtualLink(virtualNetwork.id(), cp3, cp1);
+        virtualNetworkManagerStore.updateLink(link2, link2.tunnelId(), Link.State.ACTIVE);
+        link3 = manager.createVirtualLink(virtualNetwork.id(), cp4, cp5);
+        virtualNetworkManagerStore.updateLink(link3, link3.tunnelId(), Link.State.ACTIVE);
+        link4 = manager.createVirtualLink(virtualNetwork.id(), cp5, cp4);
+        virtualNetworkManagerStore.updateLink(link4, link4.tunnelId(), Link.State.ACTIVE);
+
+        vnetIntentService = new VirtualNetworkIntentService(manager, virtualNetwork, testDirectory);
+        vnetIntentService.intentService = intentService;
+        vnetIntentService.store = virtualNetworkManagerStore;
+        vnetIntentService.partitionService = intentPartitionService;
+        return virtualNetwork;
+    }
+
+    /**
+     * Tests the submit(), withdraw(), and purge() methods.
+     */
+    @Test
+    public void testCreateAndRemoveIntent() {
+        VirtualNetwork virtualNetwork = setupVirtualNetworkTopology();
+
+        Key intentKey = Key.of("test", APP_ID);
+
+        List<Constraint> constraints = new ArrayList<>();
+        constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
+
+        VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
+                .networkId(virtualNetwork.id())
+                .key(intentKey)
+                .appId(APP_ID)
+                .ingressPoint(cp1)
+                .egressPoint(cp5)
+                .constraints(constraints)
+                .build();
+        // Test the submit() method.
+        vnetIntentService.submit(virtualIntent);
+
+        // Wait for the both intents to go into an INSTALLED state.
+        try {
+            if (!created.tryAcquire(MAX_PERMITS, MAX_WAIT_TIME, TimeUnit.SECONDS)) {
+                fail("Failed to wait for intent to get installed.");
+            }
+        } catch (InterruptedException e) {
+            fail("Semaphore exception during intent installation." + e.getMessage());
+        }
+
+        // Test the getIntentState() method
+        assertEquals("The intent state did not match as expected.", IntentState.INSTALLED,
+                     vnetIntentService.getIntentState(virtualIntent.key()));
+
+        // Test the withdraw() method.
+        vnetIntentService.withdraw(virtualIntent);
+        // Wait for the both intents to go into a WITHDRAWN state.
+        try {
+            if (!withdrawn.tryAcquire(MAX_PERMITS, MAX_WAIT_TIME, TimeUnit.SECONDS)) {
+                fail("Failed to wait for intent to get withdrawn.");
+            }
+        } catch (InterruptedException e) {
+            fail("Semaphore exception during intent withdrawal." + e.getMessage());
+        }
+
+        // Test the getIntentState() method
+        assertEquals("The intent state did not match as expected.", IntentState.WITHDRAWN,
+                     vnetIntentService.getIntentState(virtualIntent.key()));
+
+        // Test the purge() method.
+        vnetIntentService.purge(virtualIntent);
+        // Wait for the both intents to be removed/purged.
+        try {
+            if (!purged.tryAcquire(MAX_PERMITS, MAX_WAIT_TIME, TimeUnit.SECONDS)) {
+                fail("Failed to wait for intent to get purged.");
+            }
+        } catch (InterruptedException e) {
+            fail("Semaphore exception during intent purging." + e.getMessage());
+        }
+
+    }
+
+    /**
+     * Tests the getIntents, getIntent(), getIntentData(), getIntentCount(),
+     * isLocal() methods.
+     */
+    @Test
+    public void testGetIntents() {
+        VirtualNetwork virtualNetwork = setupVirtualNetworkTopology();
+
+        Key intentKey = Key.of("test", APP_ID);
+
+        List<Constraint> constraints = new ArrayList<>();
+        constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
+
+        VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
+                .networkId(virtualNetwork.id())
+                .key(intentKey)
+                .appId(APP_ID)
+                .ingressPoint(cp1)
+                .egressPoint(cp5)
+                .constraints(constraints)
+                .build();
+        // Test the submit() method.
+        vnetIntentService.submit(virtualIntent);
+
+        // Wait for the both intents to go into an INSTALLED state.
+        try {
+            if (!created.tryAcquire(MAX_PERMITS, MAX_WAIT_TIME, TimeUnit.SECONDS)) {
+                fail("Failed to wait for intent to get installed.");
+            }
+        } catch (InterruptedException e) {
+            fail("Semaphore exception during intent installation." + e.getMessage());
+        }
+
+        // Test the getIntents() method
+        assertEquals("The intents size did not match as expected.", 1,
+                     Iterators.size(vnetIntentService.getIntents().iterator()));
+
+        // Test the getIntent() method
+        assertNotNull("The intent should have been found.", vnetIntentService.getIntent(virtualIntent.key()));
+
+        // Test the getIntentData() method
+        assertEquals("The intent data size did not match as expected.", 1,
+                     Iterators.size(vnetIntentService.getIntentData().iterator()));
+
+        // Test the getIntentCount() method
+        assertEquals("The intent count did not match as expected.", 1,
+                     vnetIntentService.getIntentCount());
+
+        // Test the isLocal() method
+        assertTrue("The intent should be local.", vnetIntentService.isLocal(virtualIntent.key()));
+
+    }
+
+    /**
+     * Test listener to listen for intent events.
+     */
+    private static class TestListener implements IntentListener {
+
+        @Override
+        public void event(IntentEvent event) {
+            switch (event.type()) {
+                case INSTALLED:
+                    // Release one permit on the created semaphore since the Intent event was received.
+                    virtualNetworkManagerStore.addOrUpdateIntent(event.subject(), IntentState.INSTALLED);
+                    created.release();
+                    break;
+                case WITHDRAWN:
+                    // Release one permit on the removed semaphore since the Intent event was received.
+                    virtualNetworkManagerStore.addOrUpdateIntent(event.subject(), IntentState.WITHDRAWN);
+                    withdrawn.release();
+                    break;
+                case PURGED:
+                    // Release one permit on the purged semaphore since the Intent event was received.
+                    purged.release();
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Core service test class.
+     */
+    private class TestCoreService extends CoreServiceAdapter {
+
+        @Override
+        public IdGenerator getIdGenerator(String topic) {
+            return new IdGenerator() {
+                private AtomicLong counter = new AtomicLong(0);
+
+                @Override
+                public long getNewId() {
+                    return counter.getAndIncrement();
+                }
+            };
+        }
+    }
+
+    private static class TestIntentCompiler implements IntentCompiler<VirtualNetworkIntent> {
+        @Override
+        public List<Intent> compile(VirtualNetworkIntent intent, List<Intent> installable) {
+            return Lists.newArrayList(new MockInstallableIntent());
+        }
+    }
+
+    private static class MockInstallableIntent extends FlowRuleIntent {
+
+        public MockInstallableIntent() {
+            super(APP_ID, Collections.singletonList(new IntentTestsMocks.MockFlowRule(100)), Collections.emptyList());
+        }
+    }
+}
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkLinkServiceTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkLinkServiceTest.java
index f056f7c..ee5a5dd 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkLinkServiceTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkLinkServiceTest.java
@@ -35,6 +35,8 @@
 import org.onosproject.net.NetTestTools;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.TestDeviceParams;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.TestableIntentService;
 import org.onosproject.net.link.LinkService;
 import org.onosproject.store.service.TestStorageService;
 
@@ -54,6 +56,7 @@
     private VirtualNetworkManager manager;
     private DistributedVirtualNetworkStore virtualNetworkManagerStore;
     private CoreService coreService;
+    private TestableIntentService intentService = new FakeIntentManager();
 
     @Before
     public void setUp() throws Exception {
@@ -67,6 +70,7 @@
 
         manager = new VirtualNetworkManager();
         manager.store = virtualNetworkManagerStore;
+        manager.intentService = intentService;
         NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
         manager.activate();
     }
@@ -103,12 +107,12 @@
         Iterator<Link> it = linkService.getLinks().iterator();
         assertEquals("The link set size did not match.", 2, Iterators.size(it));
 
-        // test the getActiveLinks() method where no links are ACTIVE
+        // test the getActiveLinks() method where all links are ACTIVE
         Iterator<Link> it2 = linkService.getActiveLinks().iterator();
-        assertEquals("The link set size did not match.", 0, Iterators.size(it2));
+        assertEquals("The link set size did not match.", 2, Iterators.size(it2));
 
         // test the getActiveLinks() method where one link is ACTIVE
-        virtualNetworkManagerStore.updateLink(link1, link1.tunnelId(), Link.State.ACTIVE);
+        virtualNetworkManagerStore.updateLink(link1, link1.tunnelId(), Link.State.INACTIVE);
         Iterator<Link> it3 = linkService.getActiveLinks().iterator();
         assertEquals("The link set size did not match.", 1, Iterators.size(it3));
 
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 df5ef28..2834881 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
@@ -27,6 +27,7 @@
 import org.onosproject.core.CoreServiceAdapter;
 import org.onosproject.core.IdGenerator;
 import org.onosproject.event.Event;
+import org.onosproject.incubator.net.tunnel.TunnelId;
 import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
 import org.onosproject.incubator.net.virtual.NetworkId;
 import org.onosproject.incubator.net.virtual.TenantId;
@@ -35,6 +36,7 @@
 import org.onosproject.incubator.net.virtual.VirtualLink;
 import org.onosproject.incubator.net.virtual.VirtualNetwork;
 import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
 import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
 import org.onosproject.incubator.net.virtual.VirtualNetworkService;
 import org.onosproject.incubator.net.virtual.VirtualPort;
@@ -46,6 +48,12 @@
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.TestDeviceParams;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.intent.TestableIntentService;
 import org.onosproject.store.service.TestStorageService;
 
 import java.util.Collection;
@@ -54,6 +62,7 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import static org.junit.Assert.*;
+import static org.onosproject.net.NetTestTools.APP_ID;
 
 /**
  * Junit tests for VirtualNetworkManager.
@@ -67,10 +76,13 @@
     private DistributedVirtualNetworkStore virtualNetworkManagerStore;
     private CoreService coreService;
     private TestListener listener = new TestListener();
+    private TestableIntentService intentService = new FakeIntentManager();
+    private IdGenerator idGenerator = new MockIdGenerator();
 
     @Before
     public void setUp() throws Exception {
         virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
+        Intent.bindIdGenerator(idGenerator);
 
         coreService = new TestCoreService();
         virtualNetworkManagerStore.setCoreService(coreService);
@@ -81,6 +93,7 @@
         manager = new VirtualNetworkManager();
         manager.store = virtualNetworkManagerStore;
         manager.addListener(listener);
+        manager.intentService = intentService;
         NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
         manager.activate();
         virtualNetworkManagerService = manager;
@@ -92,6 +105,7 @@
         manager.removeListener(listener);
         manager.deactivate();
         NetTestTools.injectEventDispatcher(manager, null);
+        Intent.unbindIdGenerator(idGenerator);
     }
 
     /**
@@ -377,6 +391,95 @@
     }
 
     /**
+     * Tests the addOrUpdateIntent() method in the store with a null intent.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testAddOrUpdateNullIntent() {
+        manager.store.addOrUpdateIntent(null, null);
+    }
+
+    /**
+     * Tests the removeIntent() method in the store with a null intent key.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testRemoveNullIntentKey() {
+        manager.store.removeIntent(null);
+    }
+
+    /**
+     * Tests the addOrUpdateIntent(), getIntents(), getIntent(), removeIntent() methods with the store.
+     */
+    @Test
+    public void testAddOrUpdateIntent() {
+        manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
+        VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
+        ConnectPoint cp1 = new ConnectPoint(DID1, P1);
+        ConnectPoint cp2 = new ConnectPoint(DID2, P1);
+
+        VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
+                .networkId(virtualNetwork.id())
+                .key(Key.of("Test", APP_ID))
+                .appId(APP_ID)
+                .ingressPoint(cp1)
+                .egressPoint(cp2)
+                .build();
+
+        // Add the intent to the store.
+        manager.store.addOrUpdateIntent(virtualIntent, IntentState.INSTALL_REQ);
+        assertEquals("The intent size should match.", 1, manager.store.getIntents().size());
+        assertNotNull("The intent should not be null.", manager.store.getIntent(virtualIntent.key()));
+
+        // remove the intent from the store.
+        manager.store.removeIntent(virtualIntent.key());
+        assertTrue("The intents should be empty.", manager.store.getIntents().isEmpty());
+        assertNull("The intent should be null.", manager.store.getIntent(virtualIntent.key()));
+    }
+
+    /**
+     * Tests the addTunnelId() method in the store with a null intent.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testAddTunnelIdNullIntent() {
+        manager.store.addTunnelId(null, null);
+    }
+
+    /**
+     * Tests the removeTunnelId() method in the store with a null intent.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testRemoveTunnelIdNullIntent() {
+        manager.store.removeTunnelId(null, null);
+    }
+
+    /**
+     * Tests the addTunnelId, getTunnelIds(), removeTunnelId() methods with the store.
+     */
+    @Test
+    public void testAddTunnelId() {
+        manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
+        VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
+        ConnectPoint cp1 = new ConnectPoint(DID1, P1);
+        ConnectPoint cp2 = new ConnectPoint(DID2, P1);
+
+        VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
+                .networkId(virtualNetwork.id())
+                .key(Key.of("Test", APP_ID))
+                .appId(APP_ID)
+                .ingressPoint(cp1)
+                .egressPoint(cp2)
+                .build();
+
+        TunnelId tunnelId = TunnelId.valueOf("virtual tunnel");
+        // Add the intent to tunnelID mapping to the store.
+        manager.store.addTunnelId(virtualIntent, tunnelId);
+        assertEquals("The tunnels size should match.", 1, manager.store.getTunnelIds(virtualIntent).size());
+
+        // Remove the intent to tunnelID mapping from the store.
+        manager.store.removeTunnelId(virtualIntent, tunnelId);
+        assertTrue("The tunnels should be empty.", manager.store.getTunnelIds(virtualIntent).isEmpty());
+    }
+
+    /**
      * Method to validate that the actual versus expected virtual network events were
      * received correctly.
      *
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyServiceTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyServiceTest.java
index d199723..802bc0f 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyServiceTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyServiceTest.java
@@ -38,6 +38,8 @@
 import org.onosproject.net.Path;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.TestDeviceParams;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.TestableIntentService;
 import org.onosproject.net.topology.LinkWeight;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyCluster;
@@ -62,6 +64,7 @@
     private VirtualNetworkManager manager;
     private DistributedVirtualNetworkStore virtualNetworkManagerStore;
     private CoreService coreService;
+    private TestableIntentService intentService = new FakeIntentManager();
 
     @Before
     public void setUp() throws Exception {
@@ -75,6 +78,7 @@
 
         manager = new VirtualNetworkManager();
         manager.store = virtualNetworkManagerStore;
+        manager.intentService = intentService;
         NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
         manager.activate();
     }
diff --git a/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java b/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java
index a9b5ac0..eb4e8b3 100644
--- a/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java
+++ b/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java
@@ -42,6 +42,7 @@
 import org.onosproject.incubator.net.virtual.VirtualLink;
 import org.onosproject.incubator.net.virtual.VirtualNetwork;
 import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
 import org.onosproject.incubator.net.virtual.VirtualNetworkService;
 import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
 import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate;
@@ -54,6 +55,10 @@
 import org.onosproject.net.Link;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
 import org.onosproject.store.AbstractStore;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.ConsistentMap;
@@ -64,6 +69,7 @@
 import org.onosproject.store.service.SetEvent;
 import org.onosproject.store.service.SetEventListener;
 import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
 import org.slf4j.Logger;
 
 import java.util.HashSet;
@@ -134,6 +140,14 @@
     private ConsistentMap<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetConsistentMap;
     private Map<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetMap;
 
+    // Track intent key to intent data
+    private ConsistentMap<Key, IntentData> intentKeyIntentDataConsistentMap;
+    private Map<Key, IntentData> intentKeyIntentDataMap;
+
+    // Track intent ID to TunnelIds
+    private ConsistentMap<Key, Set<TunnelId>> intentKeyTunnelIdSetConsistentMap;
+    private Map<Key, Set<TunnelId>> intentKeyTunnelIdSetMap;
+
     private static final Serializer SERIALIZER = Serializer
             .using(new KryoNamespace.Builder().register(KryoNamespaces.API)
                            .register(TenantId.class)
@@ -150,8 +164,11 @@
                            .register(DefaultVirtualPort.class)
                            .register(Device.class)
                            .register(TunnelId.class)
+                           .register(IntentData.class)
+                           .register(VirtualNetworkIntent.class)
+                           .register(WallClockTimestamp.class)
                            .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
-                           .build("VirtualNetworkStore"));
+                           .build());
 
     /**
      * Distributed network store service activate method.
@@ -220,11 +237,25 @@
 
         networkIdVirtualPortSetConsistentMap = storageService.<NetworkId, Set<VirtualPort>>consistentMapBuilder()
                 .withSerializer(SERIALIZER)
-                .withName("onos-networkId-virtualportss")
+                .withName("onos-networkId-virtualports")
                 .withRelaxedReadConsistency()
                 .build();
         networkIdVirtualPortSetMap = networkIdVirtualPortSetConsistentMap.asJavaMap();
 
+        intentKeyTunnelIdSetConsistentMap = storageService.<Key, Set<TunnelId>>consistentMapBuilder()
+                .withSerializer(SERIALIZER)
+                .withName("onos-intentKey-tunnelIds")
+                .withRelaxedReadConsistency()
+                .build();
+        intentKeyTunnelIdSetMap = intentKeyTunnelIdSetConsistentMap.asJavaMap();
+
+        intentKeyIntentDataConsistentMap = storageService.<Key, IntentData>consistentMapBuilder()
+                .withSerializer(SERIALIZER)
+                .withName("onos-intentKey-intentData")
+                .withRelaxedReadConsistency()
+                .build();
+        intentKeyIntentDataMap = intentKeyIntentDataConsistentMap.asJavaMap();
+
         log.info("Started");
     }
 
@@ -607,6 +638,85 @@
         return ImmutableSet.copyOf(portSet);
     }
 
+    @Override
+    public synchronized void addOrUpdateIntent(Intent intent, IntentState state) {
+        checkNotNull(intent, "Intent cannot be null");
+        IntentData intentData = removeIntent(intent.key());
+        if (intentData == null) {
+            intentData = new IntentData(intent, state, new WallClockTimestamp(System.currentTimeMillis()));
+        } else {
+            intentData = new IntentData(intent, state, intentData.version());
+        }
+        intentKeyIntentDataMap.put(intent.key(), intentData);
+    }
+
+    @Override
+    public IntentData removeIntent(Key intentKey) {
+        checkNotNull(intentKey, "Intent key cannot be null");
+        return intentKeyIntentDataMap.remove(intentKey);
+    }
+
+    @Override
+    public void addTunnelId(Intent intent, TunnelId tunnelId) {
+        // Add the tunnelId to the intent key set map
+        Set<TunnelId> tunnelIdSet = intentKeyTunnelIdSetMap.remove(intent.key());
+        if (tunnelIdSet == null) {
+            tunnelIdSet = new HashSet<>();
+        }
+        tunnelIdSet.add(tunnelId);
+        intentKeyTunnelIdSetMap.put(intent.key(), tunnelIdSet);
+    }
+
+    @Override
+    public Set<TunnelId> getTunnelIds(Intent intent) {
+        Set<TunnelId> tunnelIdSet = intentKeyTunnelIdSetMap.get(intent.key());
+        return tunnelIdSet == null ? new HashSet<TunnelId>() : ImmutableSet.copyOf(tunnelIdSet);
+    }
+
+    @Override
+    public void removeTunnelId(Intent intent, TunnelId tunnelId) {
+        Set<TunnelId> tunnelIdSet = new HashSet<>();
+        intentKeyTunnelIdSetMap.get(intent.key()).forEach(tunnelId1 -> {
+            if (tunnelId1.equals(tunnelId)) {
+                tunnelIdSet.add(tunnelId);
+            }
+        });
+
+        if (!tunnelIdSet.isEmpty()) {
+            intentKeyTunnelIdSetMap.compute(intent.key(), (key, existingTunnelIds) -> {
+                if (existingTunnelIds == null || existingTunnelIds.isEmpty()) {
+                    return new HashSet<>();
+                } else {
+                    return new HashSet<>(Sets.difference(existingTunnelIds, tunnelIdSet));
+                }
+            });
+        }
+    }
+
+    @Override
+    public Set<Intent> getIntents() {
+        Set<Intent> intents = new HashSet<>();
+        intentKeyIntentDataMap.values().forEach(intentData -> intents.add(intentData.intent()));
+        return ImmutableSet.copyOf(intents);
+    }
+
+    @Override
+    public Intent getIntent(Key key) {
+        IntentData intentData = intentKeyIntentDataMap.get(key);
+        return intentData == null ? null : intentData.intent();
+    }
+
+    @Override
+    public Set<IntentData> getIntentData() {
+        return ImmutableSet.copyOf(intentKeyIntentDataMap.values());
+    }
+
+    @Override
+    public IntentData getIntentData(Key key) {
+        IntentData intentData = intentKeyIntentDataMap.get(key);
+        return intentData ==  null ? null : new IntentData(intentData);
+    }
+
     /**
      * Listener class to map listener set events to the virtual network events.
      */