KeyMapping is immutable
[bgpcep.git] / pcep / topology / topology-provider / src / main / java / org / opendaylight / bgpcep / pcep / topology / provider / config / PCEPTopologyDeployerImpl.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  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.topology.provider.config;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.Map;
15 import java.util.concurrent.TimeUnit;
16 import org.checkerframework.checker.lock.qual.GuardedBy;
17 import org.checkerframework.checker.lock.qual.Holding;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.bgpcep.pcep.server.PceServerProvider;
20 import org.opendaylight.bgpcep.pcep.topology.provider.TopologySessionListenerFactory;
21 import org.opendaylight.bgpcep.pcep.topology.spi.stats.TopologySessionStatsRegistry;
22 import org.opendaylight.bgpcep.programming.spi.InstructionScheduler;
23 import org.opendaylight.bgpcep.programming.spi.InstructionSchedulerFactory;
24 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
25 import org.opendaylight.mdsal.binding.api.DataBroker;
26 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
27 import org.opendaylight.mdsal.binding.api.DataTreeModification;
28 import org.opendaylight.mdsal.binding.api.RpcProviderService;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
31 import org.opendaylight.protocol.pcep.PCEPDispatcher;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.config.rev200120.pcep.config.SessionConfig;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.config.rev181109.PcepTopologyTypeConfig;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.TopologyTypes1;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
39 import org.opendaylight.yangtools.concepts.ListenerRegistration;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.osgi.framework.BundleContext;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class PCEPTopologyDeployerImpl implements ClusteredDataTreeChangeListener<Topology>, AutoCloseable {
46     private static final Logger LOG = LoggerFactory.getLogger(PCEPTopologyDeployerImpl.class);
47     private static final long TIMEOUT_NS = TimeUnit.SECONDS.toNanos(5);
48
49     private final InstructionSchedulerFactory instructionSchedulerFactory;
50     private final TopologySessionListenerFactory sessionListenerFactory;
51     private final ClusterSingletonServiceProvider singletonService;
52     private final PCEPDispatcher pcepDispatcher;
53     private final DataBroker dataBroker;
54     private final RpcProviderService rpcProviderRegistry;
55     private final TopologySessionStatsRegistry stateRegistry;
56     private final PceServerProvider pceServerProvider;
57     private final BundleContext bundleContext;
58
59     @GuardedBy("this")
60     private final Map<TopologyId, PCEPTopologyProviderBean> pcepTopologyServices = new HashMap<>();
61     @GuardedBy("this")
62     private ListenerRegistration<PCEPTopologyDeployerImpl> listenerRegistration;
63
64     public PCEPTopologyDeployerImpl(final DataBroker dataBroker, final ClusterSingletonServiceProvider singletonService,
65             final RpcProviderService rpcProviderRegistry, final PCEPDispatcher pcepDispatcher,
66             final TopologySessionListenerFactory sessionListenerFactory,
67             final InstructionSchedulerFactory instructionSchedulerFactory,
68             final TopologySessionStatsRegistry stateRegistry, final PceServerProvider pceServerProvider,
69             // FIXME: we should not be needing this OSGi dependency
70             final BundleContext bundleContext) {
71         this.dataBroker = requireNonNull(dataBroker);
72         this.singletonService = requireNonNull(singletonService);
73         this.rpcProviderRegistry = requireNonNull(rpcProviderRegistry);
74         this.pcepDispatcher = requireNonNull(pcepDispatcher);
75         this.sessionListenerFactory = requireNonNull(sessionListenerFactory);
76         this.instructionSchedulerFactory = requireNonNull(instructionSchedulerFactory);
77         this.stateRegistry = requireNonNull(stateRegistry);
78         this.pceServerProvider = requireNonNull(pceServerProvider);
79         this.bundleContext = requireNonNull(bundleContext);
80     }
81
82     public synchronized void init() {
83         LOG.info("PCEP Topology Deployer initialized");
84         listenerRegistration = dataBroker.registerDataTreeChangeListener(
85             DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
86                 InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class).build()), this);
87     }
88
89     @Override
90     public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Topology>> changes) {
91         for (var change : changes) {
92             final var topo = change.getRootNode();
93             switch (topo.getModificationType()) {
94                 case SUBTREE_MODIFIED:
95                 case WRITE:
96                     // FIXME: BGPCEP-983: propagate all modifications
97                     updateTopologyProvider(topo.getDataAfter());
98                     break;
99                 case DELETE:
100                     removeTopologyProvider(topo.getDataBefore());
101                     break;
102                 default:
103                     throw new IllegalStateException("Unhandled modification type " + topo.getModificationType());
104             }
105         }
106     }
107
108     @Holding("this")
109     private void updateTopologyProvider(final Topology topology) {
110         if (!filterPcepTopologies(topology.getTopologyTypes())) {
111             return;
112         }
113         final TopologyId topologyId = topology.getTopologyId();
114         LOG.info("Updating Topology {}", topologyId);
115         final PCEPTopologyProviderBean previous = pcepTopologyServices.remove(topologyId);
116         closeTopology(previous, topologyId);
117         createTopologyProvider(topology);
118     }
119
120     @Holding("this")
121     private void createTopologyProvider(final Topology topology) {
122         if (!filterPcepTopologies(topology.getTopologyTypes())) {
123             return;
124         }
125         final TopologyId topologyId = topology.getTopologyId();
126         if (pcepTopologyServices.containsKey(topologyId)) {
127             LOG.warn("Topology Provider {} already exist. New instance won't be created", topologyId);
128             return;
129         }
130         LOG.info("Creating Topology {}", topologyId);
131         LOG.trace("Topology {}.", topology);
132
133         final SessionConfig config = topology.augmentation(PcepTopologyTypeConfig.class).getSessionConfig();
134         final InstructionScheduler instructionScheduler = instructionSchedulerFactory
135                 .createInstructionScheduler(topologyId.getValue());
136
137         final PCEPTopologyProviderBean pcepTopologyProviderBean = new PCEPTopologyProviderBean(singletonService,
138             bundleContext, dataBroker, pcepDispatcher, rpcProviderRegistry, sessionListenerFactory, stateRegistry,
139             pceServerProvider);
140         pcepTopologyServices.put(topologyId, pcepTopologyProviderBean);
141
142         pcepTopologyProviderBean.start(new PCEPTopologyConfiguration(config, topology), instructionScheduler);
143     }
144
145     @Holding("this")
146     private synchronized void removeTopologyProvider(final Topology topology) {
147         if (!filterPcepTopologies(topology.getTopologyTypes())) {
148             return;
149         }
150         final TopologyId topologyId = topology.getTopologyId();
151         closeTopology(pcepTopologyServices.remove(topologyId), topologyId);
152     }
153
154     @Override
155     public synchronized void close() {
156         LOG.info("PCEP Topology Deployer closing");
157         if (listenerRegistration != null) {
158             listenerRegistration.close();
159             listenerRegistration = null;
160         }
161         for (Map.Entry<TopologyId, PCEPTopologyProviderBean> entry : pcepTopologyServices.entrySet()) {
162             closeTopology(entry.getValue(), entry.getKey());
163         }
164         pcepTopologyServices.clear();
165         LOG.info("PCEP Topology Deployer closed");
166     }
167
168     @SuppressWarnings("checkstyle:IllegalCatch")
169     private static void closeTopology(final PCEPTopologyProviderBean topology, final TopologyId topologyId) {
170         if (topology == null) {
171             return;
172         }
173         LOG.info("Removing Topology {}", topologyId);
174         try {
175             topology.closeServiceInstance().get(TIMEOUT_NS, TimeUnit.NANOSECONDS);
176             topology.close();
177         } catch (final Exception e) {
178             LOG.error("Topology {} instance failed to close service instance", topologyId, e);
179         }
180     }
181
182     private static boolean filterPcepTopologies(final @Nullable TopologyTypes topologyTypes) {
183         if (topologyTypes == null) {
184             return false;
185         }
186         final TopologyTypes1 aug = topologyTypes.augmentation(TopologyTypes1.class);
187         return aug != null && aug.getTopologyPcep() != null;
188     }
189 }