Convert DataChangeListeners to DataTreeChangeListeners
[nemo.git] / nemo-impl / src / main / java / org / opendaylight / nemo / intent / computation / VNComputationUnit.java
index b6da4d314bef66acf507637bf6b376ee29aa8c2c..2198aa2cebeb995a74829965722ad77ecaa59ec6 100644 (file)
-/*\r
- * Copyright (c) 2015 Huawei, Inc. and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-\r
-package org.opendaylight.nemo.intent.computation;\r
-\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.UUID;\r
-import java.util.concurrent.ExecutionException;\r
-\r
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;\r
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;\r
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;\r
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
-import org.opendaylight.nemo.intent.algorithm.Edge;\r
-import org.opendaylight.nemo.intent.algorithm.RoutingAlgorithm;\r
-import org.opendaylight.nemo.intent.algorithm.Vertex;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.VirtualNetworks;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetwork;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetworkKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualLinks;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualNodes;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualPaths;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualRoutes;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.links.VirtualLink;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.nodes.VirtualNode;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPath;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRoute;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLinkBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.UserId;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualLinkId;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNetworkId;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNodeId;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualPathId;\r
-import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
-import org.opendaylight.yangtools.yang.binding.DataObject;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-import com.google.common.base.Optional;\r
-\r
-/**\r
- * The virtual network computation unit implements the following functions:\r
- * (1) Maintain a user's virtual network topology information generated in\r
- *     terms of the user's intents through subscribing from the data store.\r
- * (2) Automatically recompute all routes of the virtual network when it\r
- *     changed, and store or update the routes into the data store.\r
- * (3) Provide the path computation with SLA constraints to any other modules\r
- *     that need it.\r
- *\r
- * @author Zhigang Ji\r
- */\r
-public class VNComputationUnit implements AutoCloseable {\r
-    private static final Logger LOG = LoggerFactory.getLogger(VNComputationUnit.class);\r
-\r
-    private final DataBroker dataBroker;\r
-\r
-    /**\r
-     * The user id for the virtual network maintained by\r
-     * this computation unit.\r
-     */\r
-    private UserId userId;\r
-\r
-    /**\r
-     * The routing algorithm instance.\r
-     */\r
-    private RoutingAlgorithm routingAlgorithm;\r
-\r
-    /**\r
-     * The virtual routers in the virtual network.\r
-     */\r
-    private Set<VirtualNodeId> virtualRouters;\r
-\r
-    /**\r
-     * The registration for the virtual node change listener.\r
-     */\r
-    private ListenerRegistration<DataChangeListener> virtualNodeChangeListenerReg;\r
-\r
-    /**\r
-     * The registration for the virtual link change listener.\r
-     */\r
-    private ListenerRegistration<DataChangeListener> virtualLinkChangeListenerReg;\r
-\r
-    public VNComputationUnit(DataBroker dataBroker, UserId userId) {\r
-        super();\r
-\r
-        this.dataBroker = dataBroker;\r
-        this.userId = userId;\r
-        routingAlgorithm = new RoutingAlgorithm();\r
-        virtualRouters = new HashSet<VirtualNodeId>();\r
-\r
-        VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));\r
-        InstanceIdentifier<VirtualNode> virtualNodeIid = InstanceIdentifier\r
-                .builder(VirtualNetworks.class)\r
-                .child(VirtualNetwork.class, virtualNetworkKey)\r
-                .child(VirtualNodes.class)\r
-                .child(VirtualNode.class)\r
-                .build();\r
-        InstanceIdentifier<VirtualLink> virtualLinkIid = InstanceIdentifier\r
-                .builder(VirtualNetworks.class)\r
-                .child(VirtualNetwork.class, virtualNetworkKey)\r
-                .child(VirtualLinks.class)\r
-                .child(VirtualLink.class)\r
-                .build();\r
-\r
-        virtualNodeChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,\r
-                virtualNodeIid, new VirtualNodeChangeListener(), DataChangeScope.BASE);\r
-        virtualLinkChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,\r
-                virtualLinkIid, new VirtualLinkChangeListener(), DataChangeScope.BASE);\r
-\r
-        LOG.debug("Initialized the virtual network computation unit for the user {}.", userId.getValue());\r
-\r
-        return;\r
-    }\r
-\r
-    public VNComputationUnit(DataBroker dataBroker, VirtualNetwork virtualNetwork) {\r
-        super();\r
-\r
-        this.dataBroker = dataBroker;\r
-        userId = virtualNetwork.getUserId();\r
-        routingAlgorithm = new RoutingAlgorithm();\r
-        virtualRouters = new HashSet<VirtualNodeId>();\r
-\r
-        List<VirtualNode> virtualNodes = virtualNetwork.getVirtualNodes().getVirtualNode();\r
-        Vertex vertex;\r
-\r
-        for ( VirtualNode virtualNode : virtualNodes ) {\r
-            vertex = new Vertex(virtualNode.getNodeId().getValue());\r
-            routingAlgorithm.addVertex(vertex);\r
-\r
-            if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {\r
-                virtualRouters.add(virtualNode.getNodeId());\r
-            }\r
-        }\r
-\r
-        List<VirtualLink> virtualLinks = virtualNetwork.getVirtualLinks().getVirtualLink();\r
-\r
-        for ( VirtualLink virtualLink : virtualLinks ) {\r
-            routingAlgorithm.addEdge(new Edge(virtualLink));\r
-        }\r
-\r
-//        computeRoute(virtualNetwork);\r
-\r
-        return;\r
-    }\r
-\r
-    /**\r
-     * Compute a shortest virtual path from the given source vertex to\r
-     * target one without any constraint.\r
-     *\r
-     * @param source The given source virtual node id.\r
-     * @param target The given target virtual node id.\r
-     * @return The virtual path if successful,or null otherwise.\r
-     */\r
-    public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target) {\r
-        List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),\r
-                routingAlgorithm.getVertex(target.getValue()));\r
-\r
-        if ( null == edges || edges.isEmpty() ) {\r
-            return null;\r
-        }\r
-\r
-        List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =\r
-                new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());\r
-        org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;\r
-        long metric = 0;\r
-        long delay = 0;\r
-\r
-        for ( Edge edge : edges ) {\r
-            virtualLink = new VirtualLinkBuilder()\r
-                    .setLinkId(new VirtualLinkId(edge.getId()))\r
-                    .setOrder((long) virtualLinks.size())\r
-                    .build();\r
-            virtualLinks.add(virtualLink);\r
-\r
-            metric += edge.getMetric();\r
-//            delay += edge.getDelay();\r
-        }\r
-\r
-        VirtualPath virtualPath = new VirtualPathBuilder()\r
-                .setPathId(new VirtualPathId(UUID.randomUUID().toString()))\r
-                .setVirtualLink(virtualLinks)\r
-                .setMetric(metric)\r
-                .setBandwidth(0L)\r
-                .setDelay(delay)\r
-                .build();\r
-\r
-        return virtualPath;\r
-    }\r
-\r
-    /**\r
-     * Compute a shortest virtual path with the given bandwidth from the\r
-     * given source vertex to target one.\r
-     *\r
-     * @param source The given source virtual node id.\r
-     * @param target The given target virtual node id.\r
-     * @param bandwidth The given bandwidth for the virtual path.\r
-     * @return The virtual path if successful,or null otherwise.\r
-     */\r
-    public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target, long bandwidth) {\r
-        List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),\r
-                routingAlgorithm.getVertex(target.getValue()), bandwidth);\r
-\r
-        if ( null == edges || edges.isEmpty() ) {\r
-            return null;\r
-        }\r
-\r
-        List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =\r
-                new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());\r
-        org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;\r
-        long metric = 0;\r
-        long delay = 0;\r
-\r
-        for ( Edge edge : edges ) {\r
-            edge.setBandwidth(edge.getBandwidth() - bandwidth);\r
-            routingAlgorithm.updateEdge(edge);\r
-\r
-            virtualLink = new VirtualLinkBuilder()\r
-                    .setLinkId(new VirtualLinkId(edge.getId()))\r
-                    .setOrder((long)virtualLinks.size())\r
-                    .build();\r
-            virtualLinks.add(virtualLink);\r
-\r
-            metric += edge.getMetric();\r
-//            delay += edge.getDelay();\r
-        }\r
-\r
-        VirtualPath virtualPath = new VirtualPathBuilder()\r
-                .setPathId(new VirtualPathId(UUID.randomUUID().toString()))\r
-                .setVirtualLink(virtualLinks)\r
-                .setMetric(metric)\r
-                .setBandwidth(bandwidth)\r
-                .setDelay(delay)\r
-                .build();\r
-\r
-        return virtualPath;\r
-    }\r
-\r
-    @Override\r
-    public void close() throws Exception {\r
-        if ( null != virtualNodeChangeListenerReg ) {\r
-            virtualNodeChangeListenerReg.close();\r
-        }\r
-\r
-        if ( null != virtualLinkChangeListenerReg ) {\r
-            virtualLinkChangeListenerReg.close();\r
-        }\r
-\r
-        return;\r
-    }\r
-\r
-    /**\r
-     * Compute the routes between all virtual routers in the virtual\r
-     * network, and store or update them into the data store.\r
-     */\r
-    private void computeRoute() {\r
-        Map<VirtualRouteKey, VirtualPath> routes = new HashMap<VirtualRouteKey, VirtualPath>();\r
-        VirtualPath virtualPath;\r
-\r
-        for ( VirtualNodeId source : virtualRouters ) {\r
-            for ( VirtualNodeId target : virtualRouters ) {\r
-                if ( !source.equals(target) ) {\r
-                    virtualPath = computePath(source, target);\r
-\r
-                    if ( null == virtualPath ) {\r
-                        continue;\r
-                    }\r
-\r
-                    routes.put(new VirtualRouteKey(source, target), virtualPath);\r
-                }\r
-            }\r
-        }\r
-\r
-        updateRoute(routes);\r
-\r
-        return;\r
-    }\r
-\r
-    /**\r
-     * Compute the routes between all virtual routers in the virtual\r
-     * network, and store them into the virtual network.\r
-     *\r
-     * @param virtualNetwork The virtual network to store the routes.\r
-     */\r
-    private void computeRoute(VirtualNetwork virtualNetwork) {\r
-        List<VirtualRoute> virtualRoutes = virtualNetwork.getVirtualRoutes().getVirtualRoute();\r
-        List<VirtualPath> virtualPaths = virtualNetwork.getVirtualPaths().getVirtualPath();\r
-        VirtualRoute virtualRoute;\r
-        VirtualPath virtualPath;\r
-\r
-        for ( VirtualNodeId source : virtualRouters ) {\r
-            for ( VirtualNodeId target : virtualRouters ) {\r
-                if ( !source.equals(target) ) {\r
-                    virtualPath = computePath(source, target);\r
-\r
-                    if ( null == virtualPath ) {\r
-                        continue;\r
-                    }\r
-\r
-                    virtualRoute = new VirtualRouteBuilder().setSrcNodeId(source)\r
-                            .setDestNodeId(target)\r
-                            .setPathId(virtualPath.getPathId())\r
-                            .build();\r
-\r
-                    virtualPaths.add(virtualPath);\r
-                    virtualRoutes.add(virtualRoute);\r
-                }\r
-            }\r
-        }\r
-\r
-        return;\r
-    }\r
-\r
-    /**\r
-     * Update the given routes into the data store. If the route\r
-     * already exists, remove it's old virtual path and store the\r
-     * given new one into the data store.\r
-     *\r
-     * @param routes The given routes to be updated.\r
-     */\r
-    private void updateRoute(Map<VirtualRouteKey, VirtualPath> routes) {\r
-        ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();\r
-\r
-        VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));\r
-        InstanceIdentifier<VirtualRoute> virtualRouteIid;\r
-        InstanceIdentifier<VirtualPath> virtualPathIid;\r
-        Optional<VirtualRoute> result;\r
-        VirtualRoute virtualRoute;\r
-\r
-        for ( Map.Entry<VirtualRouteKey, VirtualPath> route : routes.entrySet() ) {\r
-            virtualRouteIid = InstanceIdentifier.builder(VirtualNetworks.class)\r
-                    .child(VirtualNetwork.class, virtualNetworkKey)\r
-                    .child(VirtualRoutes.class)\r
-                    .child(VirtualRoute.class, route.getKey())\r
-                    .build();\r
-\r
-            try {\r
-                result = readWriteTransaction.read(LogicalDatastoreType.CONFIGURATION, virtualRouteIid).get();\r
-            } catch ( InterruptedException exception ) {\r
-                LOG.error("Can not read the virtual route from the virtual node {} to {}.",\r
-                        route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());\r
-\r
-                continue;\r
-            } catch ( ExecutionException exception ) {\r
-                LOG.error("Can not read the virtual route from the virtual node {} to {}.",\r
-                        route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());\r
-\r
-                continue;\r
-            }\r
-\r
-            if ( result.isPresent() ) {\r
-                virtualRoute = result.get();\r
-                virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)\r
-                        .child(VirtualNetwork.class, virtualNetworkKey)\r
-                        .child(VirtualPaths.class)\r
-                        .child(VirtualPath.class, new VirtualPathKey(virtualRoute.getPathId()))\r
-                        .build();\r
-                readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, virtualPathIid);\r
-            }\r
-\r
-            virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)\r
-                    .child(VirtualNetwork.class, virtualNetworkKey)\r
-                    .child(VirtualPaths.class)\r
-                    .child(VirtualPath.class, route.getValue().getKey())\r
-                    .build();\r
-            readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualPathIid, route.getValue(), true);\r
-\r
-            virtualRoute = new VirtualRouteBuilder().setSrcNodeId(route.getKey().getSrcNodeId())\r
-                    .setDestNodeId(route.getKey().getDestNodeId())\r
-                    .setPathId(route.getValue().getPathId())\r
-                    .build();\r
-            readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualRouteIid, virtualRoute, true);\r
-        }\r
-\r
-        readWriteTransaction.submit();\r
-\r
-        return;\r
-    }\r
-\r
-    /**\r
-     * A listener to change events related to virtual nodes being\r
-     * added, removed or updated.\r
-     *\r
-     * @author Zhigang Ji\r
-     */\r
-    private class VirtualNodeChangeListener implements DataChangeListener {\r
-        @Override\r
-        public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {\r
-            if ( null == change ) {\r
-                return;\r
-            }\r
-\r
-            Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();\r
-\r
-            if ( null != createdData && !createdData.isEmpty() ) {\r
-                VirtualNode virtualNode;\r
-                Vertex vertex;\r
-\r
-                for ( DataObject dataObject : createdData.values() ) {\r
-                    if ( dataObject instanceof VirtualNode ) {\r
-                        virtualNode = (VirtualNode)dataObject;\r
-                        vertex = new Vertex(virtualNode.getNodeId().getValue());\r
-\r
-                        routingAlgorithm.addVertex(vertex);\r
-\r
-                        if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {\r
-                            virtualRouters.add(virtualNode.getNodeId());\r
-                        }\r
-                    }\r
-                }\r
-            }\r
-\r
-            return;\r
-        }\r
-    }\r
-\r
-    /**\r
-     * A listener to change events related to virtual links being\r
-     * added, removed or updated.\r
-     *\r
-     * @author Zhigang Ji\r
-     */\r
-    private class VirtualLinkChangeListener implements DataChangeListener {\r
-        @Override\r
-        public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {\r
-            if ( null == change ) {\r
-                return;\r
-            }\r
-\r
-            Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();\r
-\r
-            if ( null != createdData && !createdData.isEmpty() ) {\r
-                boolean needRerouting = false;\r
-\r
-                for ( DataObject dataObject : createdData.values() ) {\r
-                    if ( dataObject instanceof VirtualLink ) {\r
-                        VirtualLink virtualLink = (VirtualLink)dataObject;\r
-                        Edge edge = new Edge(virtualLink);\r
-\r
-                        routingAlgorithm.addEdge(edge);\r
-\r
-                        if ( virtualRouters.contains(virtualLink.getSrcNodeId())\r
-                                && virtualRouters.contains(virtualLink.getDestNodeId()) ) {\r
-                            needRerouting = true;\r
-                        }\r
-                    }\r
-                }\r
-\r
-                if ( needRerouting ) {\r
-                    computeRoute();\r
-                }\r
-            }\r
-\r
-            return;\r
-        }\r
-    }\r
-}\r
+/*
+ * Copyright (c) 2015 Huawei, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.nemo.intent.computation;
+
+import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.nemo.intent.algorithm.Edge;
+import org.opendaylight.nemo.intent.algorithm.RoutingAlgorithm;
+import org.opendaylight.nemo.intent.algorithm.Vertex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.VirtualNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetwork;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetworkKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualLinks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualPaths;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualRoutes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.links.VirtualLink;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.nodes.VirtualNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRoute;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLinkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.UserId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualLinkId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNetworkId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualPathId;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The virtual network computation unit implements the following functions:
+ * (1) Maintain a user's virtual network topology information generated in
+ *     terms of the user's intents through subscribing from the data store.
+ * (2) Automatically recompute all routes of the virtual network when it
+ *     changed, and store or update the routes into the data store.
+ * (3) Provide the path computation with SLA constraints to any other modules
+ *     that need it.
+ *
+ * @author Zhigang Ji
+ */
+public class VNComputationUnit implements AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(VNComputationUnit.class);
+
+    private final DataBroker dataBroker;
+
+    /**
+     * The user id for the virtual network maintained by
+     * this computation unit.
+     */
+    private UserId userId;
+
+    /**
+     * The routing algorithm instance.
+     */
+    private RoutingAlgorithm routingAlgorithm;
+
+    /**
+     * The virtual routers in the virtual network.
+     */
+    private Set<VirtualNodeId> virtualRouters = ConcurrentHashMap.newKeySet();
+
+    /**
+     * The registration for the virtual node change listener.
+     */
+    private ListenerRegistration<?> virtualNodeChangeListenerReg;
+
+    /**
+     * The registration for the virtual link change listener.
+     */
+    private ListenerRegistration<?> virtualLinkChangeListenerReg;
+
+    public VNComputationUnit(DataBroker dataBroker, UserId userId) {
+        super();
+
+        this.dataBroker = dataBroker;
+        this.userId = userId;
+        routingAlgorithm = new RoutingAlgorithm();
+
+        VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));
+        InstanceIdentifier<VirtualNode> virtualNodeIid = InstanceIdentifier
+                .builder(VirtualNetworks.class)
+                .child(VirtualNetwork.class, virtualNetworkKey)
+                .child(VirtualNodes.class)
+                .child(VirtualNode.class)
+                .build();
+        InstanceIdentifier<VirtualLink> virtualLinkIid = InstanceIdentifier
+                .builder(VirtualNetworks.class)
+                .child(VirtualNetwork.class, virtualNetworkKey)
+                .child(VirtualLinks.class)
+                .child(VirtualLink.class)
+                .build();
+
+        virtualNodeChangeListenerReg = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(
+                LogicalDatastoreType.CONFIGURATION, virtualNodeIid), new VirtualNodeChangeListener());
+        virtualLinkChangeListenerReg = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(
+                LogicalDatastoreType.CONFIGURATION, virtualLinkIid), new VirtualLinkChangeListener());
+
+        LOG.debug("Initialized the virtual network computation unit for the user {}.", userId.getValue());
+
+        return;
+    }
+
+    public VNComputationUnit(DataBroker dataBroker, VirtualNetwork virtualNetwork) {
+        super();
+
+        this.dataBroker = dataBroker;
+        userId = virtualNetwork.getUserId();
+        routingAlgorithm = new RoutingAlgorithm();
+        virtualRouters = new HashSet<>();
+
+        List<VirtualNode> virtualNodes = virtualNetwork.getVirtualNodes().getVirtualNode();
+        Vertex vertex;
+
+        for ( VirtualNode virtualNode : virtualNodes ) {
+            vertex = new Vertex(virtualNode.getNodeId().getValue());
+            routingAlgorithm.addVertex(vertex);
+
+            if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {
+                virtualRouters.add(virtualNode.getNodeId());
+            }
+        }
+
+        List<VirtualLink> virtualLinks = virtualNetwork.getVirtualLinks().getVirtualLink();
+
+        for ( VirtualLink virtualLink : virtualLinks ) {
+            routingAlgorithm.addEdge(new Edge(virtualLink));
+        }
+
+//        computeRoute(virtualNetwork);
+
+        return;
+    }
+
+    /**
+     * Compute a shortest virtual path from the given source vertex to
+     * target one without any constraint.
+     *
+     * @param source The given source virtual node id.
+     * @param target The given target virtual node id.
+     * @return The virtual path if successful,or null otherwise.
+     */
+    public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target) {
+        List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),
+                routingAlgorithm.getVertex(target.getValue()));
+
+        if ( null == edges || edges.isEmpty() ) {
+            return null;
+        }
+
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =
+                new ArrayList<>(edges.size());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;
+        long metric = 0;
+        long delay = 0;
+
+        for ( Edge edge : edges ) {
+            virtualLink = new VirtualLinkBuilder()
+                    .setLinkId(new VirtualLinkId(edge.getId()))
+                    .setOrder((long) virtualLinks.size())
+                    .build();
+            virtualLinks.add(virtualLink);
+
+            metric += edge.getMetric();
+//            delay += edge.getDelay();
+        }
+
+        VirtualPath virtualPath = new VirtualPathBuilder()
+                .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
+                .setVirtualLink(virtualLinks)
+                .setMetric(metric)
+                .setBandwidth(0L)
+                .setDelay(delay)
+                .build();
+
+        return virtualPath;
+    }
+
+    /**
+     * Compute a shortest virtual path with the given bandwidth from the
+     * given source vertex to target one.
+     *
+     * @param source The given source virtual node id.
+     * @param target The given target virtual node id.
+     * @param bandwidth The given bandwidth for the virtual path.
+     * @return The virtual path if successful,or null otherwise.
+     */
+    public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target, long bandwidth) {
+        List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),
+                routingAlgorithm.getVertex(target.getValue()), bandwidth);
+
+        if ( null == edges || edges.isEmpty() ) {
+            return null;
+        }
+
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =
+                new ArrayList<>(edges.size());
+        org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;
+        long metric = 0;
+        long delay = 0;
+
+        for ( Edge edge : edges ) {
+            edge.setBandwidth(edge.getBandwidth() - bandwidth);
+            routingAlgorithm.updateEdge(edge);
+
+            virtualLink = new VirtualLinkBuilder()
+                    .setLinkId(new VirtualLinkId(edge.getId()))
+                    .setOrder((long)virtualLinks.size())
+                    .build();
+            virtualLinks.add(virtualLink);
+
+            metric += edge.getMetric();
+//            delay += edge.getDelay();
+        }
+
+        VirtualPath virtualPath = new VirtualPathBuilder()
+                .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
+                .setVirtualLink(virtualLinks)
+                .setMetric(metric)
+                .setBandwidth(bandwidth)
+                .setDelay(delay)
+                .build();
+
+        return virtualPath;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if ( null != virtualNodeChangeListenerReg ) {
+            virtualNodeChangeListenerReg.close();
+        }
+
+        if ( null != virtualLinkChangeListenerReg ) {
+            virtualLinkChangeListenerReg.close();
+        }
+
+        return;
+    }
+
+    /**
+     * Compute the routes between all virtual routers in the virtual
+     * network, and store or update them into the data store.
+     */
+    private void computeRoute() {
+        Map<VirtualRouteKey, VirtualPath> routes = new HashMap<>();
+        VirtualPath virtualPath;
+
+        for ( VirtualNodeId source : virtualRouters ) {
+            for ( VirtualNodeId target : virtualRouters ) {
+                if ( !source.equals(target) ) {
+                    virtualPath = computePath(source, target);
+
+                    if ( null == virtualPath ) {
+                        continue;
+                    }
+
+                    routes.put(new VirtualRouteKey(source, target), virtualPath);
+                }
+            }
+        }
+
+        updateRoute(routes);
+
+        return;
+    }
+
+    /**
+     * Compute the routes between all virtual routers in the virtual
+     * network, and store them into the virtual network.
+     *
+     * @param virtualNetwork The virtual network to store the routes.
+     */
+    private void computeRoute(VirtualNetwork virtualNetwork) {
+        List<VirtualRoute> virtualRoutes = virtualNetwork.getVirtualRoutes().getVirtualRoute();
+        List<VirtualPath> virtualPaths = virtualNetwork.getVirtualPaths().getVirtualPath();
+        VirtualRoute virtualRoute;
+        VirtualPath virtualPath;
+
+        for ( VirtualNodeId source : virtualRouters ) {
+            for ( VirtualNodeId target : virtualRouters ) {
+                if ( !source.equals(target) ) {
+                    virtualPath = computePath(source, target);
+
+                    if ( null == virtualPath ) {
+                        continue;
+                    }
+
+                    virtualRoute = new VirtualRouteBuilder().setSrcNodeId(source)
+                            .setDestNodeId(target)
+                            .setPathId(virtualPath.getPathId())
+                            .build();
+
+                    virtualPaths.add(virtualPath);
+                    virtualRoutes.add(virtualRoute);
+                }
+            }
+        }
+
+        return;
+    }
+
+    /**
+     * Update the given routes into the data store. If the route
+     * already exists, remove it's old virtual path and store the
+     * given new one into the data store.
+     *
+     * @param routes The given routes to be updated.
+     */
+    private void updateRoute(Map<VirtualRouteKey, VirtualPath> routes) {
+        ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();
+
+        VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));
+        InstanceIdentifier<VirtualRoute> virtualRouteIid;
+        InstanceIdentifier<VirtualPath> virtualPathIid;
+        Optional<VirtualRoute> result;
+        VirtualRoute virtualRoute;
+
+        for ( Map.Entry<VirtualRouteKey, VirtualPath> route : routes.entrySet() ) {
+            virtualRouteIid = InstanceIdentifier.builder(VirtualNetworks.class)
+                    .child(VirtualNetwork.class, virtualNetworkKey)
+                    .child(VirtualRoutes.class)
+                    .child(VirtualRoute.class, route.getKey())
+                    .build();
+
+            try {
+                result = readWriteTransaction.read(LogicalDatastoreType.CONFIGURATION, virtualRouteIid).get();
+            } catch ( InterruptedException exception ) {
+                LOG.error("Can not read the virtual route from the virtual node {} to {}.",
+                        route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());
+
+                continue;
+            } catch ( ExecutionException exception ) {
+                LOG.error("Can not read the virtual route from the virtual node {} to {}.",
+                        route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());
+
+                continue;
+            }
+
+            if ( result.isPresent() ) {
+                virtualRoute = result.get();
+                virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)
+                        .child(VirtualNetwork.class, virtualNetworkKey)
+                        .child(VirtualPaths.class)
+                        .child(VirtualPath.class, new VirtualPathKey(virtualRoute.getPathId()))
+                        .build();
+                readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, virtualPathIid);
+            }
+
+            virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)
+                    .child(VirtualNetwork.class, virtualNetworkKey)
+                    .child(VirtualPaths.class)
+                    .child(VirtualPath.class, route.getValue().getKey())
+                    .build();
+            readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualPathIid, route.getValue(), true);
+
+            virtualRoute = new VirtualRouteBuilder().setSrcNodeId(route.getKey().getSrcNodeId())
+                    .setDestNodeId(route.getKey().getDestNodeId())
+                    .setPathId(route.getValue().getPathId())
+                    .build();
+            readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualRouteIid, virtualRoute, true);
+        }
+
+        readWriteTransaction.submit();
+
+        return;
+    }
+
+    /**
+     * A listener to change events related to virtual nodes being
+     * added, removed or updated.
+     *
+     * @author Zhigang Ji
+     */
+    private class VirtualNodeChangeListener implements DataTreeChangeListener<VirtualNode> {
+        @Override
+        public void onDataTreeChanged(Collection<DataTreeModification<VirtualNode>> changes) {
+            for (DataTreeModification<VirtualNode> change: changes) {
+                DataObjectModification<VirtualNode> rootNode = change.getRootNode();
+                switch (rootNode.getModificationType()) {
+                    case WRITE:
+                        if (rootNode.getDataBefore() == null) {
+                            VirtualNode virtualNode = rootNode.getDataAfter();
+                            Vertex vertex = new Vertex(virtualNode.getNodeId().getValue());
+
+                            routingAlgorithm.addVertex(vertex);
+
+                            if (VirtualNode.NodeType.Vrouter == virtualNode.getNodeType()) {
+                                virtualRouters.add(virtualNode.getNodeId());
+                            }
+                        }
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * A listener to change events related to virtual links being
+     * added, removed or updated.
+     *
+     * @author Zhigang Ji
+     */
+    private class VirtualLinkChangeListener implements DataTreeChangeListener<VirtualLink> {
+        @Override
+        public void onDataTreeChanged(Collection<DataTreeModification<VirtualLink>> changes) {
+            boolean needRerouting = false;
+            for (DataTreeModification<VirtualLink> change: changes) {
+                DataObjectModification<VirtualLink> rootNode = change.getRootNode();
+                switch (rootNode.getModificationType()) {
+                    case WRITE:
+                        if (rootNode.getDataBefore() == null) {
+                            VirtualLink virtualLink = rootNode.getDataAfter();
+                            Edge edge = new Edge(virtualLink);
+
+                            routingAlgorithm.addEdge(edge);
+
+                            if (virtualRouters.contains(virtualLink.getSrcNodeId())
+                                    && virtualRouters.contains(virtualLink.getDestNodeId())) {
+                                needRerouting = true;
+                            }
+                        }
+                        break;
+                    default:
+                        break;
+                }
+
+                if ( needRerouting ) {
+                    computeRoute();
+                }
+            }
+        }
+    }
+}