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