Bump upstreams
[bgpcep.git] / pcep / server / server-provider / src / main / java / org / opendaylight / bgpcep / pcep / server / provider / PathManagerListener.java
1 /*
2  * Copyright (c) 2021 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.bgpcep.pcep.server.provider;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.util.List;
13 import java.util.stream.Collectors;
14 import org.opendaylight.mdsal.binding.api.DataBroker;
15 import org.opendaylight.mdsal.binding.api.DataObjectModification;
16 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
17 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
18 import org.opendaylight.mdsal.binding.api.DataTreeModification;
19 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PcepNodeConfig;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLsp;
22 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
23 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
24 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
25 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
26 import org.opendaylight.yangtools.concepts.Registration;
27 import org.opendaylight.yangtools.yang.binding.DataObject;
28 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33  * This Class Implements the DataStoreService interface providing the methods required to manage the path
34  * representation elements in the Data Store.
35  *
36  * @author Olivier Dugeon
37  */
38
39 public final class PathManagerListener implements DataTreeChangeListener<Node>, AutoCloseable {
40     private static final Logger LOG = LoggerFactory.getLogger(PathManagerListener.class);
41
42     private Registration listenerRegistration;
43
44     private final PathManagerProvider pathManager;
45
46     public PathManagerListener(final DataBroker dataBroker,
47             final KeyedInstanceIdentifier<Topology, TopologyKey> topology, final PathManagerProvider pathManager) {
48         this.pathManager = requireNonNull(pathManager);
49         listenerRegistration = dataBroker.registerLegacyTreeChangeListener(
50                 DataTreeIdentifier.of(LogicalDatastoreType.CONFIGURATION, topology.child(Node.class)), this);
51         LOG.info("Registered listener for Managed TE Path on Topology {}",
52             topology.getKey().getTopologyId().getValue());
53     }
54
55     /**
56      * Close this Listener.
57      */
58     @Override
59     public void close() {
60         if (listenerRegistration != null) {
61             LOG.debug("Unregistered listener {} for Managed TE Path", this);
62             listenerRegistration.close();
63             listenerRegistration = null;
64         }
65     }
66
67     /**
68      * Handle Configured LSP modifications.
69      *
70      * @param nodeId    Node Identifier to which the modified children belongs to.
71      * @param lspMod    List of Configured LSP modifications.
72      */
73     private void handleLspChange(final NodeId nodeId,
74             final List<? extends DataObjectModification<? extends DataObject>> lspMod) {
75         for (DataObjectModification<? extends DataObject> lsp : lspMod) {
76             ConfiguredLsp cfgLsp;
77             switch (lsp.modificationType()) {
78                 case DELETE:
79                     cfgLsp = (ConfiguredLsp) lsp.dataBefore();
80                     LOG.debug("Delete Managed TE Path: {}", cfgLsp.getName());
81                     pathManager.deleteManagedTePath(nodeId, cfgLsp.key());
82                     break;
83                 case SUBTREE_MODIFIED:
84                 case WRITE:
85                     cfgLsp = (ConfiguredLsp) lsp.dataAfter();
86                     LOG.debug("Update Managed TE Path {}", cfgLsp);
87                     pathManager.createManagedTePath(nodeId, cfgLsp);
88                     break;
89                 default:
90                     break;
91             }
92
93         }
94     }
95
96     /**
97      * Parse Sub Tree modification. Given list has been filtered to get only Path Computation Client1 modifications.
98      * This function first create, update or delete Managed TE Node that corresponds to the given NodeId. Then, it
99      * filter the children to retain only the Configured LSP modifications.
100      *
101      * @param nodeId    Node Identifier to which the modified children belongs to.
102      * @param pccMod    List of PCEP Node Configuration modifications.
103      */
104     private void handlePccChange(final NodeId nodeId,
105             final List<? extends DataObjectModification<? extends DataObject>> pccMod) {
106         for (var node : pccMod) {
107             /* First, process PCC modification */
108             switch (node.modificationType()) {
109                 case DELETE:
110                     LOG.debug("Delete Managed TE Node: {}", nodeId);
111                     pathManager.deleteManagedTeNode(nodeId);
112                     break;
113                 case SUBTREE_MODIFIED:
114                 case WRITE:
115                     /* First look if the Managed TE Node belongs to this PCC was not already created */
116                     final var pccNode = (PcepNodeConfig) node.dataAfter();
117                     if (!pathManager.checkManagedTeNode(nodeId)) {
118                         LOG.info("Create new Managed Node {}", nodeId);
119                         pathManager.createManagedTeNode(nodeId, pccNode);
120                     } else {
121                         /* Then, look to Configured LSP modification */
122                         final var lspMod = node.modifiedChildren()
123                                 .stream().filter(mod -> mod.dataType().equals(ConfiguredLsp.class))
124                                 .collect(Collectors.toList());
125                         if (!lspMod.isEmpty()) {
126                             handleLspChange(nodeId, lspMod);
127                         }
128                     }
129                     break;
130                 default:
131                     break;
132             }
133         }
134     }
135
136     @Override
137     public void onDataTreeChanged(final List<DataTreeModification<Node>> changes) {
138         for (var change : changes) {
139             final var root = change.getRootNode();
140
141             final String nodeAddr = root.modificationType() == DataObjectModification.ModificationType.DELETE
142                     ? root.dataBefore().getNodeId().getValue()
143                     : root.dataAfter().getNodeId().getValue();
144             NodeId nodeId;
145             if (nodeAddr.startsWith("pcc://")) {
146                 nodeId = new NodeId(nodeAddr);
147             } else {
148                 nodeId = new NodeId("pcc://" + nodeAddr);
149             }
150
151             /* Look only to PcepNodeConfig.class modification */
152             final var pccMod = root.modifiedChildren().stream()
153                     .filter(mod -> mod.dataType().equals(PcepNodeConfig.class))
154                     .collect(Collectors.toList());
155             if (!pccMod.isEmpty()) {
156                 handlePccChange(nodeId, pccMod);
157             }
158         }
159     }
160 }
161