Graph: add Multi-Topology support
[bgpcep.git] / graph / graph-impl / src / main / java / org / opendaylight / graph / impl / ConnectedGraphImpl.java
index 8e356b5c5dbef28fe96e13e1e34a910c4e62e6a4..9604591b31afa3580cf3dc1d8d3d552f10785082 100644 (file)
@@ -5,28 +5,41 @@
  * 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.graph.impl;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.graph.ConnectedEdge;
+import org.opendaylight.graph.ConnectedEdgeTrigger;
 import org.opendaylight.graph.ConnectedGraph;
+import org.opendaylight.graph.ConnectedGraphTrigger;
 import org.opendaylight.graph.ConnectedVertex;
+import org.opendaylight.graph.ConnectedVertexTrigger;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.EdgeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.graph.topology.Graph;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.graph.topology.graph.Edge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.graph.topology.graph.EdgeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.graph.topology.graph.Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.graph.topology.graph.Vertex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.graph.topology.graph.VertexKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,13 +49,10 @@ import org.slf4j.LoggerFactory;
  * @author Olivier Dugeon
  * @author Philippe Niger
  */
-
-
 public class ConnectedGraphImpl implements ConnectedGraph {
-
     private static final Logger LOG = LoggerFactory.getLogger(ConnectedGraphImpl.class);
 
-    /* List of Connected Vertics that composed this Connected Graph */
+    /* List of Connected Vertices that composed this Connected Graph */
     private final HashMap<Long, ConnectedVertexImpl> vertices = new HashMap<>();
 
     /* List of Connected Edges that composed this Connected Graph */
@@ -51,13 +61,17 @@ public class ConnectedGraphImpl implements ConnectedGraph {
     /* List of IP prefix attached to Vertices */
     private final HashMap<IpPrefix, Prefix> prefixes = new HashMap<>();
 
+    /* List of Triggers attached to the Connected Graph */
+    private final ConcurrentHashMap<TopologyKey, ConnectedGraphTrigger> graphTriggers = new ConcurrentHashMap<>();
+    private final ListeningExecutorService exec = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+
     /* Reference to the non connected Graph stored in DataStore */
     private Graph graph;
 
     /* Reference to Graph Model Server to store corresponding graph in DataStore */
     private final ConnectedGraphServer connectedGraphServer;
 
-    public ConnectedGraphImpl(Graph newGraph, ConnectedGraphServer server) {
+    public ConnectedGraphImpl(final Graph newGraph, final ConnectedGraphServer server) {
         this.graph = newGraph;
         createConnectedGraph();
         this.connectedGraphServer = server;
@@ -73,28 +87,22 @@ public class ConnectedGraphImpl implements ConnectedGraph {
             return;
         }
         /* Add all vertices */
-        if (this.graph.getVertex() != null) {
-            for (Vertex vertex : this.graph.getVertex()) {
-                ConnectedVertexImpl cvertex = new ConnectedVertexImpl(vertex);
-                vertices.put(cvertex.getKey(), cvertex);
-            }
+        for (Vertex vertex : this.graph.nonnullVertex().values()) {
+            ConnectedVertexImpl cvertex = new ConnectedVertexImpl(vertex);
+            vertices.put(cvertex.getKey(), cvertex);
         }
         /* Add all edges */
-        if (this.graph.getEdge() != null) {
-            for (Edge edge : this.graph.getEdge()) {
-                ConnectedEdgeImpl cedge = new ConnectedEdgeImpl(edge);
-                edges.put(cedge.getKey(), cedge);
-            }
+        for (Edge edge : this.graph.nonnullEdge().values()) {
+            ConnectedEdgeImpl cedge = new ConnectedEdgeImpl(edge);
+            edges.put(cedge.getKey(), cedge);
         }
         /* Add all prefixes */
-        if (this.graph.getPrefix() != null) {
-            for (Prefix prefix : this.graph.getPrefix()) {
-                ConnectedVertexImpl cvertex = vertices.get(prefix.getVertexId().longValue());
-                if (cvertex != null) {
-                    cvertex.addPrefix(prefix);
-                }
-                prefixes.putIfAbsent(prefix.getPrefix(), prefix);
+        for (Prefix prefix : this.graph.nonnullPrefix().values()) {
+            ConnectedVertexImpl cvertex = vertices.get(prefix.getVertexId().longValue());
+            if (cvertex != null) {
+                cvertex.addPrefix(prefix);
             }
+            prefixes.putIfAbsent(prefix.getPrefix(), prefix);
         }
     }
 
@@ -104,7 +112,7 @@ public class ConnectedGraphImpl implements ConnectedGraph {
      * @param  key   Unique Vertex Key identifier
      * @return new or existing Connected Vertex
      */
-    private ConnectedVertexImpl updateConnectedVertex(@NonNull Long key) {
+    private ConnectedVertexImpl updateConnectedVertex(final @NonNull Long key) {
         checkArgument(key != 0, "Provided Vertex Key must not be equal to 0");
         ConnectedVertexImpl vertex = vertices.get(key);
         if (vertex == null) {
@@ -120,7 +128,7 @@ public class ConnectedGraphImpl implements ConnectedGraph {
      * @param key   Unique Edge Key identifier
      * @return new or existing Connected Edge
      */
-    private ConnectedEdgeImpl updateConnectedEdge(@NonNull Long key) {
+    private ConnectedEdgeImpl updateConnectedEdge(final @NonNull Long key) {
         checkArgument(key != 0, "Provided Edge Key must not be equal to 0");
         ConnectedEdgeImpl edge = edges.get(key);
         if (edge == null) {
@@ -137,7 +145,8 @@ public class ConnectedGraphImpl implements ConnectedGraph {
      * @param dstVertex Destination Connected Vertex
      * @param edge      Connected Edge
      */
-    private void connectVertices(ConnectedVertexImpl srcVertex, ConnectedVertexImpl dstVertex, ConnectedEdgeImpl edge) {
+    private static void connectVertices(final ConnectedVertexImpl srcVertex, final ConnectedVertexImpl dstVertex,
+            final ConnectedEdgeImpl edge) {
         if (edge != null) {
             edge.setSource(srcVertex);
             edge.setDestination(dstVertex);
@@ -157,16 +166,19 @@ public class ConnectedGraphImpl implements ConnectedGraph {
 
     @Override
     public List<ConnectedVertex> getVertices() {
-        return new ArrayList<ConnectedVertex>(this.vertices.values());
+        return new ArrayList<>(this.vertices.values());
     }
 
     @Override
-    public ConnectedVertex getConnectedVertex(@NonNull Long key) {
+    public ConnectedVertex getConnectedVertex(final Long key) {
         return vertices.get(key);
     }
 
     @Override
-    public ConnectedVertex getConnectedVertex(IpAddress address) {
+    public ConnectedVertex getConnectedVertex(final IpAddress address) {
+        if (address == null) {
+            return null;
+        }
         IpPrefix prefix = null;
         if (address.getIpv4Address() != null) {
             prefix = new IpPrefix(new Ipv4Prefix(address.getIpv4Address().getValue() + "/32"));
@@ -189,27 +201,47 @@ public class ConnectedGraphImpl implements ConnectedGraph {
 
     @Override
     public List<ConnectedEdge> getEdges() {
-        return new ArrayList<ConnectedEdge>(this.edges.values());
+        return new ArrayList<>(this.edges.values());
     }
 
     @Override
-    public ConnectedEdge getConnectedEdge(@NonNull Long key) {
+    public ConnectedEdge getConnectedEdge(final Long key) {
         return edges.get(key);
     }
 
     @Override
-    public ConnectedEdge getConnectedEdge(IpAddress address) {
-        for (ConnectedEdge cedge : edges.values()) {
-            if (cedge.getEdge() == null) {
-                continue;
-            }
-            if (cedge.getEdge().getEdgeAttributes().getLocalAddress().equals(address)) {
-                return cedge;
-            }
+    public ConnectedEdge getConnectedEdge(final IpAddress address) {
+        if (address == null) {
+            return null;
+        }
+        if (address.getIpv4Address() != null) {
+            return getConnectedEdge(address.getIpv4Address());
+        }
+        if (address.getIpv6Address() != null) {
+            return getConnectedEdge(address.getIpv6Address());
         }
         return null;
     }
 
+    @Override
+    public ConnectedEdge getConnectedEdge(final Ipv4Address address) {
+        if (address == null) {
+            return null;
+        }
+        final Uint64 key = Uint32.fromIntBits(IetfInetUtil.INSTANCE.ipv4AddressBits(address)).toUint64();
+        return getConnectedEdge(key.longValue());
+    }
+
+    @Override
+    public ConnectedEdge getConnectedEdge(final Ipv6Address address) {
+        if (address == null) {
+            return null;
+        }
+        final byte[] ip = IetfInetUtil.INSTANCE.ipv6AddressBytes(address);
+        final Uint64 key = Uint64.fromLongBits(ByteBuffer.wrap(ip, Long.BYTES, Long.BYTES).getLong());
+        return getConnectedEdge(key.longValue());
+    }
+
     @Override
     public int getEdgesSize() {
         return edges.size();
@@ -217,26 +249,39 @@ public class ConnectedGraphImpl implements ConnectedGraph {
 
     @Override
     public List<Prefix> getPrefixes() {
-        return new ArrayList<Prefix>(this.prefixes.values());
+        return new ArrayList<>(this.prefixes.values());
     }
 
     @Override
-    public Prefix getPrefix(IpPrefix prefix) {
+    public Prefix getPrefix(final IpPrefix prefix) {
         return this.prefixes.get(prefix);
     }
 
+    private void callVertexTrigger(ConnectedVertexImpl cvertex, Vertex vertex) {
+        List<ConnectedVertexTrigger> vertexTriggers = cvertex.getTriggers();
+        if (vertexTriggers == null || vertexTriggers.isEmpty()) {
+            return;
+        }
+        for (ConnectedGraphTrigger trigger : graphTriggers.values()) {
+            this.exec.submit(() -> trigger.verifyVertex(vertexTriggers, cvertex, vertex));
+        }
+    }
+
     @Override
-    public ConnectedVertex addVertex(Vertex vertex) {
+    public ConnectedVertex addVertex(final Vertex vertex) {
         checkArgument(vertex != null, "Provided Vertex is a null object");
         ConnectedVertexImpl cvertex = updateConnectedVertex(vertex.getVertexId().longValue());
         Vertex old = cvertex.getVertex();
         this.connectedGraphServer.addVertex(this.graph, vertex, old);
         cvertex.setVertex(vertex);
+        if (old != null) {
+            callVertexTrigger(cvertex, old);
+        }
         return cvertex;
     }
 
     @Override
-    public void deleteVertex(VertexKey key) {
+    public void deleteVertex(final VertexKey key) {
         checkArgument(key != null, "Provided Vertex Key is a null object");
         ConnectedVertexImpl cvertex = vertices.get(key.getVertexId().longValue());
         if (cvertex != null) {
@@ -244,11 +289,22 @@ public class ConnectedGraphImpl implements ConnectedGraph {
             vertices.remove(cvertex.getKey());
             this.connectedGraphServer.deleteVertex(this.graph, cvertex.getVertex());
             cvertex.setVertex(null);
+            callVertexTrigger(cvertex, null);
+        }
+    }
+
+    private void callEdgeTrigger(ConnectedEdgeImpl cedge, Edge edge) {
+        List<ConnectedEdgeTrigger> edgeTriggers = cedge.getTriggers();
+        if (edgeTriggers == null || edgeTriggers.isEmpty()) {
+            return;
+        }
+        for (ConnectedGraphTrigger trigger : graphTriggers.values()) {
+            this.exec.submit(() -> trigger.verifyEdge(edgeTriggers, cedge, edge));
         }
     }
 
     @Override
-    public ConnectedEdge addEdge(Edge edge) {
+    public ConnectedEdge addEdge(final Edge edge) {
         checkArgument(edge != null, "Provided Edge is a null object");
         ConnectedEdgeImpl cedge = updateConnectedEdge(edge.getEdgeId().longValue());
         Edge old = cedge.getEdge();
@@ -265,23 +321,28 @@ public class ConnectedGraphImpl implements ConnectedGraph {
         }
         this.connectedGraphServer.addEdge(this.graph, edge, old);
         cedge.setEdge(edge);
+        callEdgeTrigger(cedge, old);
         return cedge;
     }
 
+    /**
+     * Connected Edge is kept in the edges Hash Map in order to memorize the total Bandwidth reserved by
+     * Constrained Paths that belong to this Edge. Connected Edges are removed when the Connected Graph is cleared.
+     */
     @Override
-    public void deleteEdge(EdgeKey key) {
+    public void deleteEdge(final EdgeKey key) {
         checkArgument(key != null, "Provided Edge Key is a null object");
         ConnectedEdgeImpl cedge = edges.get(key.getEdgeId().longValue());
         if (cedge != null) {
             this.connectedGraphServer.deleteEdge(this.graph, cedge.getEdge());
             cedge.disconnect();
-            edges.remove(cedge.getKey());
             cedge.setEdge(null);
+            callEdgeTrigger(cedge, null);
         }
     }
 
     @Override
-    public void addPrefix(Prefix prefix) {
+    public void addPrefix(final Prefix prefix) {
         checkArgument(prefix != null, "Provided Prefix is a null object");
         ConnectedVertexImpl cvertex = updateConnectedVertex(prefix.getVertexId().longValue());
         cvertex.addPrefix(prefix);
@@ -290,7 +351,7 @@ public class ConnectedGraphImpl implements ConnectedGraph {
     }
 
     @Override
-    public void deletePrefix(IpPrefix ippfx) {
+    public void deletePrefix(final IpPrefix ippfx) {
         checkArgument(ippfx != null, "Provided Prefix is a null object");
         Prefix prefix = prefixes.get(ippfx);
         if (prefix != null) {
@@ -318,6 +379,16 @@ public class ConnectedGraphImpl implements ConnectedGraph {
         return vertices.size() + "/" + edges.size() + "/" + prefixes.size();
     }
 
+    @Override
+    public boolean registerTrigger(ConnectedGraphTrigger trigger, TopologyKey key) {
+        return graphTriggers.putIfAbsent(key, trigger) == null;
+    }
+
+    @Override
+    public boolean unRegisterTrigger(ConnectedGraphTrigger trigger, TopologyKey key) {
+        return graphTriggers.remove(key, trigger);
+    }
+
     /**
      * Returns the name of the associated Graph.
      *