dbed0b12d0669e9aa070add6c7d474e7da11f689
[bgpcep.git] / pcep / tunnel / tunnel-provider / src / main / java / org / opendaylight / bgpcep / pcep / tunnel / provider / TunnelProviderDeployer.java
1 /*
2  * Copyright (c) 2017 AT&T Intellectual Property. 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.tunnel.provider;
9
10 import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.CONFIGURATION;
11
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.concurrent.TimeUnit;
17 import java.util.stream.Collectors;
18 import org.apache.commons.lang3.StringUtils;
19 import org.checkerframework.checker.lock.qual.GuardedBy;
20 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
21 import org.opendaylight.mdsal.binding.api.DataBroker;
22 import org.opendaylight.mdsal.binding.api.DataObjectModification;
23 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
24 import org.opendaylight.mdsal.binding.api.DataTreeModification;
25 import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry;
26 import org.opendaylight.mdsal.binding.api.RpcProviderService;
27 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.config.rev181109.PcepTunnelTopologyConfig;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.tunnel.pcep.rev181109.TopologyTypes1;
30 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
31 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
35 import org.opendaylight.yangtools.concepts.Registration;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.osgi.framework.BundleContext;
38 import org.osgi.service.component.annotations.Activate;
39 import org.osgi.service.component.annotations.Component;
40 import org.osgi.service.component.annotations.Deactivate;
41 import org.osgi.service.component.annotations.Reference;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 @Component(service = { })
46 public final class TunnelProviderDeployer implements ClusteredDataTreeChangeListener<Topology>, AutoCloseable {
47     private static final Logger LOG = LoggerFactory.getLogger(TunnelProviderDeployer.class);
48     private static final long TIMEOUT_NS = TimeUnit.SECONDS.toNanos(5);
49
50     private final TunnelProviderDependencies dependencies;
51     @GuardedBy("this")
52     private final Map<TopologyId, PCEPTunnelClusterSingletonService> pcepTunnelServices = new HashMap<>();
53     private final Registration reg;
54
55     @Activate
56     public TunnelProviderDeployer(@Reference final DataBroker dataBroker,
57             @Reference final RpcProviderService rpcProviderRegistry,
58             @Reference final RpcConsumerRegistry rpcConsumerRegistry,
59             @Reference final ClusterSingletonServiceProvider cssp,
60             // FIXME: do not reference BundleContext in an alternative constructor
61             final BundleContext bundleContext) {
62         dependencies = new TunnelProviderDependencies(dataBroker, cssp, rpcProviderRegistry, rpcConsumerRegistry,
63                 bundleContext);
64         reg = dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(CONFIGURATION,
65                 InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class).build()), this);
66         LOG.info("Tunnel Provider Deployer created");
67     }
68
69     @Deactivate
70     @Override
71     public synchronized void close() {
72         reg.close();
73         pcepTunnelServices.values().iterator().forEachRemaining(PCEPTunnelClusterSingletonService::close);
74         pcepTunnelServices.clear();
75         LOG.info("Tunnel Provider Deployer closed");
76     }
77
78     @SuppressWarnings("checkstyle:IllegalCatch")
79     private static void closeTopology(final PCEPTunnelClusterSingletonService topology, final TopologyId topologyId) {
80         if (topology != null) {
81             try {
82                 topology.closeServiceInstance().get(TIMEOUT_NS, TimeUnit.NANOSECONDS);
83             } catch (final Exception e) {
84                 LOG.error("Topology {} instance failed to close service instance", topologyId, e);
85             }
86             topology.close();
87         }
88     }
89
90     @Override
91     public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Topology>> changes) {
92         final List<DataObjectModification<Topology>> topoChanges = changes.stream()
93                 .map(DataTreeModification::getRootNode)
94                 .collect(Collectors.toList());
95
96         topoChanges.stream().iterator().forEachRemaining(this::handleTopologyChange);
97     }
98
99     private synchronized void handleTopologyChange(final DataObjectModification<Topology> topo) {
100         switch (topo.getModificationType()) {
101             case SUBTREE_MODIFIED:
102                 updateTunnelTopologyProvider(topo.getDataAfter());
103                 break;
104             case WRITE:
105                 createTunnelTopologyProvider(topo.getDataAfter());
106                 break;
107             case DELETE:
108                 removeTunnelTopologyProvider(topo.getDataBefore());
109                 break;
110             default:
111         }
112     }
113
114     private static boolean filterPcepTopologies(final TopologyTypes topologyTypes) {
115         if (topologyTypes == null) {
116             return false;
117         }
118         final TopologyTypes1 aug = topologyTypes.augmentation(TopologyTypes1.class);
119         return aug != null && aug.getTopologyTunnelPcep() != null;
120     }
121
122     private synchronized void createTunnelTopologyProvider(final Topology topology) {
123         if (!filterPcepTopologies(topology.getTopologyTypes())) {
124             return;
125         }
126         final TopologyId topologyId = topology.getTopologyId();
127         if (pcepTunnelServices.containsKey(topology.getTopologyId())) {
128             LOG.warn("Tunnel Topology {} already exist. New instance won't be created", topologyId);
129             return;
130         }
131         LOG.debug("Create Tunnel Topology {}", topologyId);
132
133         final PcepTunnelTopologyConfig config = topology.augmentation(PcepTunnelTopologyConfig.class);
134         final String pcepTopoID = StringUtils
135                 .substringBetween(config.getPcepTopologyReference().getValue(), "=\"", "\"");
136         final InstanceIdentifier<Topology> pcepTopoRef = InstanceIdentifier.builder(NetworkTopology.class)
137                 .child(Topology.class, new TopologyKey(new TopologyId(pcepTopoID))).build();
138
139
140         final PCEPTunnelClusterSingletonService tunnelTopoCss =
141                 new PCEPTunnelClusterSingletonService(dependencies, pcepTopoRef, topologyId);
142         pcepTunnelServices.put(topology.getTopologyId(), tunnelTopoCss);
143     }
144
145     private synchronized void updateTunnelTopologyProvider(final Topology topology) {
146         if (!filterPcepTopologies(topology.getTopologyTypes())) {
147             return;
148         }
149         final TopologyId topologyId = topology.getTopologyId();
150         final PCEPTunnelClusterSingletonService previous = pcepTunnelServices.remove(topology.getTopologyId());
151         closeTopology(previous, topologyId);
152         createTunnelTopologyProvider(topology);
153     }
154
155     private synchronized void removeTunnelTopologyProvider(final Topology topo) {
156         if (!filterPcepTopologies(topo.getTopologyTypes())) {
157             return;
158         }
159         final TopologyId topologyId = topo.getTopologyId();
160         final PCEPTunnelClusterSingletonService topology = pcepTunnelServices.remove(topologyId);
161         closeTopology(topology, topologyId);
162     }
163 }