Graph modelisation for Path Computation Algorithm
[bgpcep.git] / graph / graph-impl / src / main / java / org / opendaylight / graph / impl / GraphListener.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
9 package org.opendaylight.graph.impl;
10
11 import static com.google.common.base.Preconditions.checkState;
12
13 import java.util.Collection;
14 import org.opendaylight.graph.ConnectedGraph;
15 import org.opendaylight.graph.ConnectedGraphProvider;
16 import org.opendaylight.mdsal.binding.api.DataBroker;
17 import org.opendaylight.mdsal.binding.api.DataObjectModification;
18 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
19 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
20 import org.opendaylight.mdsal.binding.api.DataTreeModification;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.GraphTopology;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.GraphKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
28 import org.opendaylight.yangtools.concepts.ListenerRegistration;
29 import org.opendaylight.yangtools.yang.binding.DataObject;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * This Class Implements the DataStoreService interface providing the methods required to manage the network
36  * representation elements in the Data Store.
37  *
38  *
39  * @author Olivier Dugeon
40  * @author Philippe Niger
41  */
42
43 public class GraphListener implements DataTreeChangeListener<Graph> {
44
45     private static final Logger LOG = LoggerFactory.getLogger(GraphListener.class);
46     private final DataBroker dataBroker;
47     private final InstanceIdentifier<Graph> graphIdentifier;
48     private final ConnectedGraphProvider graphProvider;
49     private ListenerRegistration<GraphListener> listenerRegistration = null;
50
51     public GraphListener(final DataBroker dataBroker, final ConnectedGraphProvider provider) {
52         this.dataBroker = dataBroker;
53         this.graphIdentifier = InstanceIdentifier.builder(GraphTopology.class).child(Graph.class).build();
54         this.graphProvider = provider;
55         LOG.info("Graph Model Listener started");
56     }
57
58     /**
59      * Initialization of the Graph Topology Listener. This method is called through the blueprint.
60      */
61     public void init() {
62         checkState(this.listenerRegistration == null, "Graph Listener has been registered before");
63         final DataTreeIdentifier<Graph> treeId = DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
64                 graphIdentifier);
65         this.listenerRegistration = this.dataBroker.registerDataTreeChangeListener(treeId, this);
66         LOG.info("Registered listener {} on Graph Model at {}", this, this.graphIdentifier);
67     }
68
69     /**
70      * Close this Listener.
71      */
72     public void close() {
73         if (this.listenerRegistration != null) {
74             LOG.debug("Unregistered listener {} on Graph", this);
75             this.listenerRegistration.close();
76             this.listenerRegistration = null;
77         }
78     }
79
80     /**
81      * Parse Sub Tree modification. This method is called with the Modified Children from
82      * the Data Tree Modification root.This method is necessary as the getModificationType() method returns
83      * SUBTREE_MODIFIED only when Data Object is already present in the Data Store. Thus, this is indication is only
84      * relevant for deletion not for insertion where WRITE modification type is return even if it concerns a child.
85      *
86      * @param cgraph   Connected Graph where children Data Object must insert or remove
87      * @param children List of children (Vertex, Edge or Prefix)
88      */
89     private void parseSubTree(ConnectedGraph cgraph,
90             Collection<? extends DataObjectModification<? extends DataObject>> children) {
91         for (DataObjectModification<? extends DataObject> child : children) {
92             DataObject value;
93             switch (child.getModificationType()) {
94                 case DELETE:
95                     value = child.getDataBefore();
96                     if (value instanceof Vertex) {
97                         cgraph.deleteVertex(((Vertex )value).key());
98                     }
99                     if (value instanceof Edge) {
100                         cgraph.deleteEdge(((Edge )value).key());
101                     }
102                     if (value instanceof Prefix) {
103                         cgraph.deletePrefix(((Prefix )value).getPrefix());
104                     }
105                     break;
106                 case SUBTREE_MODIFIED:
107                 case WRITE:
108                     value = child.getDataAfter();
109                     if (value instanceof Vertex) {
110                         cgraph.addVertex((Vertex )value);
111                     }
112                     if (value instanceof Edge) {
113                         cgraph.addEdge((Edge )value);
114                     }
115                     if (value instanceof Prefix) {
116                         cgraph.addPrefix((Prefix )value);
117                     }
118                     break;
119                 default:
120                     break;
121             }
122         }
123     }
124
125     @Override
126     public void onDataTreeChanged(final Collection<DataTreeModification<Graph>> changes) {
127         for (DataTreeModification<Graph> change : changes) {
128             DataObjectModification<Graph> root = change.getRootNode();
129             GraphKey key = change.getRootPath().getRootIdentifier().firstKeyOf(Graph.class);
130             switch (root.getModificationType()) {
131                 case DELETE:
132                     graphProvider.deleteGraph(key);
133                     break;
134                 case SUBTREE_MODIFIED:
135                     /* getModificationType() returns SUBTREE_MODIFIED only when Data Object is already present in the
136                      * Data Store, thus, only for deletion. Thus, to insert children, we must used parseSubTree()
137                      * method (See above). This method is called only when the graph already exists.
138                      */
139                 case WRITE:
140                     /* First look if the Graph was not already configured */
141                     ConnectedGraph cgraph = this.graphProvider.getConnectedGraph(key);
142                     if (cgraph == null) {
143                         graphProvider.addGraph(root.getDataAfter());
144                     } else {
145                         /* Graph exist, process Children */
146                         parseSubTree(cgraph, root.getModifiedChildren());
147                     }
148                     break;
149                 default:
150                     break;
151             }
152         }
153     }
154
155 }
156