6683b1d7fff67e3882aec506b96f0c4ce816ae34
[bgpcep.git] / graph / graph-impl / src / main / java / org / opendaylight / graph / impl / ConnectedGraphImpl.java
1 /*
2  * Copyright (c) 2019 Orange. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.graph.impl;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11
12 import java.nio.ByteBuffer;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.List;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.graph.ConnectedEdge;
18 import org.opendaylight.graph.ConnectedGraph;
19 import org.opendaylight.graph.ConnectedVertex;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.EdgeKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexKey;
31 import org.opendaylight.yangtools.yang.common.Uint32;
32 import org.opendaylight.yangtools.yang.common.Uint64;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * This Class implements the Connected Graph for path computation algorithms.
38  *
39  * @author Olivier Dugeon
40  * @author Philippe Niger
41  */
42 public class ConnectedGraphImpl implements ConnectedGraph {
43     private static final Logger LOG = LoggerFactory.getLogger(ConnectedGraphImpl.class);
44
45     /* List of Connected Vertics that composed this Connected Graph */
46     private final HashMap<Long, ConnectedVertexImpl> vertices = new HashMap<>();
47
48     /* List of Connected Edges that composed this Connected Graph */
49     private final HashMap<Long, ConnectedEdgeImpl> edges = new HashMap<>();
50
51     /* List of IP prefix attached to Vertices */
52     private final HashMap<IpPrefix, Prefix> prefixes = new HashMap<>();
53
54     /* Reference to the non connected Graph stored in DataStore */
55     private Graph graph;
56
57     /* Reference to Graph Model Server to store corresponding graph in DataStore */
58     private final ConnectedGraphServer connectedGraphServer;
59
60     public ConnectedGraphImpl(final Graph newGraph, final ConnectedGraphServer server) {
61         this.graph = newGraph;
62         createConnectedGraph();
63         this.connectedGraphServer = server;
64     }
65
66     /**
67      * Transform the associated Graph in a Connected Graph. This method will automatically create associated Connected
68      * Vertices, from the Graph Vertices, Connected Edges, from the Graph Edges and Prefix from the Graph Prefix.
69      *
70      */
71     private void createConnectedGraph() {
72         if (this.graph == null) {
73             return;
74         }
75         /* Add all vertices */
76         for (Vertex vertex : this.graph.nonnullVertex().values()) {
77             ConnectedVertexImpl cvertex = new ConnectedVertexImpl(vertex);
78             vertices.put(cvertex.getKey(), cvertex);
79         }
80         /* Add all edges */
81         for (Edge edge : this.graph.nonnullEdge().values()) {
82             ConnectedEdgeImpl cedge = new ConnectedEdgeImpl(edge);
83             edges.put(cedge.getKey(), cedge);
84         }
85         /* Add all prefixes */
86         for (Prefix prefix : this.graph.nonnullPrefix().values()) {
87             ConnectedVertexImpl cvertex = vertices.get(prefix.getVertexId().longValue());
88             if (cvertex != null) {
89                 cvertex.addPrefix(prefix);
90             }
91             prefixes.putIfAbsent(prefix.getPrefix(), prefix);
92         }
93     }
94
95     /**
96      * Return Connected Vertex if it exists or create a new one.
97      *
98      * @param  key   Unique Vertex Key identifier
99      * @return new or existing Connected Vertex
100      */
101     private ConnectedVertexImpl updateConnectedVertex(final @NonNull Long key) {
102         checkArgument(key != 0, "Provided Vertex Key must not be equal to 0");
103         ConnectedVertexImpl vertex = vertices.get(key);
104         if (vertex == null) {
105             vertex = new ConnectedVertexImpl(key);
106             vertices.put(key, vertex);
107         }
108         return vertex;
109     }
110
111     /**
112      * Return Connected Edge if it exist or create a new one.
113      *
114      * @param key   Unique Edge Key identifier
115      * @return new or existing Connected Edge
116      */
117     private ConnectedEdgeImpl updateConnectedEdge(final @NonNull Long key) {
118         checkArgument(key != 0, "Provided Edge Key must not be equal to 0");
119         ConnectedEdgeImpl edge = edges.get(key);
120         if (edge == null) {
121             edge = new ConnectedEdgeImpl(key);
122             edges.put(edge.getKey(), edge);
123         }
124         return edge;
125     }
126
127     /**
128      * Connect source and destination Connected Vertices with the given Connected Edge.
129      *
130      * @param srcVertex Source Connected Vertex
131      * @param dstVertex Destination Connected Vertex
132      * @param edge      Connected Edge
133      */
134     private static void connectVertices(final ConnectedVertexImpl srcVertex, final ConnectedVertexImpl dstVertex,
135             final ConnectedEdgeImpl edge) {
136         if (edge != null) {
137             edge.setSource(srcVertex);
138             edge.setDestination(dstVertex);
139         }
140         if (srcVertex != null) {
141             srcVertex.addOutput(edge);
142         }
143         if (dstVertex != null) {
144             dstVertex.addInput(edge);
145         }
146     }
147
148     @Override
149     public Graph getGraph() {
150         return this.graph;
151     }
152
153     @Override
154     public List<ConnectedVertex> getVertices() {
155         return new ArrayList<>(this.vertices.values());
156     }
157
158     @Override
159     public ConnectedVertex getConnectedVertex(final Long key) {
160         return vertices.get(key);
161     }
162
163     @Override
164     public ConnectedVertex getConnectedVertex(final IpAddress address) {
165         IpPrefix prefix = null;
166         if (address.getIpv4Address() != null) {
167             prefix = new IpPrefix(new Ipv4Prefix(address.getIpv4Address().getValue() + "/32"));
168         }
169         if (address.getIpv6Address() != null) {
170             prefix = new IpPrefix(new Ipv6Prefix(address.getIpv6Address().getValue() + "/128"));
171         }
172         if (prefix != null && prefixes.containsKey(prefix)) {
173             long key = prefixes.get(prefix).getVertexId().longValue();
174             return vertices.get(key);
175         } else {
176             return null;
177         }
178     }
179
180     @Override
181     public int getVerticesSize() {
182         return vertices.size();
183     }
184
185     @Override
186     public List<ConnectedEdge> getEdges() {
187         return new ArrayList<>(this.edges.values());
188     }
189
190     @Override
191     public ConnectedEdge getConnectedEdge(final Long key) {
192         return edges.get(key);
193     }
194
195     @Override
196     public ConnectedEdge getConnectedEdge(final IpAddress address) {
197         Uint64 key;
198         if (address.getIpv4Address() != null) {
199             key = Uint32.fromIntBits(IetfInetUtil.INSTANCE.ipv4AddressBits(address.getIpv4Address())).toUint64();
200             return getConnectedEdge(key.longValue());
201         }
202         if (address.getIpv6Address() != null) {
203             final byte[] ip = IetfInetUtil.INSTANCE.ipv6AddressBytes(address.getIpv6Address());
204             key = Uint64.fromLongBits(ByteBuffer.wrap(ip, Long.BYTES, Long.BYTES).getLong());
205             return getConnectedEdge(key.longValue());
206         }
207         return null;
208     }
209
210     @Override
211     public int getEdgesSize() {
212         return edges.size();
213     }
214
215     @Override
216     public List<Prefix> getPrefixes() {
217         return new ArrayList<>(this.prefixes.values());
218     }
219
220     @Override
221     public Prefix getPrefix(final IpPrefix prefix) {
222         return this.prefixes.get(prefix);
223     }
224
225     @Override
226     public ConnectedVertex addVertex(final Vertex vertex) {
227         checkArgument(vertex != null, "Provided Vertex is a null object");
228         ConnectedVertexImpl cvertex = updateConnectedVertex(vertex.getVertexId().longValue());
229         Vertex old = cvertex.getVertex();
230         this.connectedGraphServer.addVertex(this.graph, vertex, old);
231         cvertex.setVertex(vertex);
232         return cvertex;
233     }
234
235     @Override
236     public void deleteVertex(final VertexKey key) {
237         checkArgument(key != null, "Provided Vertex Key is a null object");
238         ConnectedVertexImpl cvertex = vertices.get(key.getVertexId().longValue());
239         if (cvertex != null) {
240             cvertex.disconnect();
241             vertices.remove(cvertex.getKey());
242             this.connectedGraphServer.deleteVertex(this.graph, cvertex.getVertex());
243             cvertex.setVertex(null);
244         }
245     }
246
247     @Override
248     public ConnectedEdge addEdge(final Edge edge) {
249         checkArgument(edge != null, "Provided Edge is a null object");
250         ConnectedEdgeImpl cedge = updateConnectedEdge(edge.getEdgeId().longValue());
251         Edge old = cedge.getEdge();
252         if (old == null) {
253             ConnectedVertexImpl source = null;
254             ConnectedVertexImpl destination = null;
255             if (edge.getLocalVertexId() != null) {
256                 source = updateConnectedVertex(edge.getLocalVertexId().longValue());
257             }
258             if (edge.getRemoteVertexId() != null) {
259                 destination = updateConnectedVertex(edge.getRemoteVertexId().longValue());
260             }
261             connectVertices(source, destination, cedge);
262         }
263         this.connectedGraphServer.addEdge(this.graph, edge, old);
264         cedge.setEdge(edge);
265         return cedge;
266     }
267
268     /**
269      * Connected Edge is kept in the edges Hash Map in order to memorize the total Bandwidth reserved by
270      * Constrained Paths that belong to this Edge. Connected Edges are removed when the Connected Graph is cleared.
271      */
272     @Override
273     public void deleteEdge(final EdgeKey key) {
274         checkArgument(key != null, "Provided Edge Key is a null object");
275         ConnectedEdgeImpl cedge = edges.get(key.getEdgeId().longValue());
276         if (cedge != null) {
277             this.connectedGraphServer.deleteEdge(this.graph, cedge.getEdge());
278             cedge.disconnect();
279             cedge.setEdge(null);
280         }
281     }
282
283     @Override
284     public void addPrefix(final Prefix prefix) {
285         checkArgument(prefix != null, "Provided Prefix is a null object");
286         ConnectedVertexImpl cvertex = updateConnectedVertex(prefix.getVertexId().longValue());
287         cvertex.addPrefix(prefix);
288         prefixes.putIfAbsent(prefix.getPrefix(), prefix);
289         this.connectedGraphServer.addPrefix(this.graph, prefix);
290     }
291
292     @Override
293     public void deletePrefix(final IpPrefix ippfx) {
294         checkArgument(ippfx != null, "Provided Prefix is a null object");
295         Prefix prefix = prefixes.get(ippfx);
296         if (prefix != null) {
297             ConnectedVertexImpl cvertex = vertices.get(prefix.getVertexId().longValue());
298             if (cvertex != null) {
299                 cvertex.removePrefix(prefix);
300             }
301             prefixes.remove(prefix.getPrefix());
302             this.connectedGraphServer.deletePrefix(this.graph, prefix);
303         }
304     }
305
306     @Override
307     public void clear() {
308         LOG.info("Reset Connected Graph({})", graph.getName());
309         this.vertices.clear();
310         this.edges.clear();
311         this.prefixes.clear();
312         this.connectedGraphServer.clearGraph(this.graph);
313         this.graph = null;
314     }
315
316     @Override
317     public String getSummary() {
318         return vertices.size() + "/" + edges.size() + "/" + prefixes.size();
319     }
320
321     /**
322      * Returns the name of the associated Graph.
323      *
324      * @return Graph name
325      */
326     @Override
327     public String toString() {
328         return this.graph.getName();
329     }
330 }