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