Migrate to MD-SAL APIs
[bgpcep.git] / bgp / topology-provider / src / main / java / org / opendaylight / bgpcep / bgp / topology / provider / config / BgpTopologyDeployerImpl.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. 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.bgp.topology.provider.config;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.util.Collection;
13 import java.util.Dictionary;
14 import java.util.HashSet;
15 import java.util.Hashtable;
16 import java.util.Set;
17 import java.util.stream.Collectors;
18 import org.checkerframework.checker.lock.qual.GuardedBy;
19 import org.opendaylight.bgpcep.bgp.topology.provider.spi.BgpTopologyDeployer;
20 import org.opendaylight.bgpcep.bgp.topology.provider.spi.BgpTopologyProvider;
21 import org.opendaylight.bgpcep.bgp.topology.provider.spi.TopologyReferenceSingletonService;
22 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
23 import org.opendaylight.mdsal.binding.api.DataBroker;
24 import org.opendaylight.mdsal.binding.api.DataObjectModification;
25 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
26 import org.opendaylight.mdsal.binding.api.DataTreeModification;
27 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
28 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
29 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
30 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
31 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
34 import org.opendaylight.yangtools.concepts.AbstractRegistration;
35 import org.opendaylight.yangtools.concepts.ListenerRegistration;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 public final class BgpTopologyDeployerImpl implements BgpTopologyDeployer, AutoCloseable,
41         ClusteredDataTreeChangeListener<Topology> {
42
43     private static final Logger LOG = LoggerFactory.getLogger(BgpTopologyDeployerImpl.class);
44     private static final InstanceIdentifier<Topology> TOPOLOGY_IID =
45             InstanceIdentifier.create(NetworkTopology.class).child(Topology.class);
46
47     @GuardedBy("this")
48     private final Set<BgpTopologyProvider> topologyProviders = new HashSet<>();
49     @GuardedBy("this")
50     private final Set<Topology> topologies = new HashSet<>();
51     private final DataBroker dataBroker;
52     private final ClusterSingletonServiceProvider singletonProvider;
53     private ListenerRegistration<BgpTopologyDeployerImpl> registration;
54     @GuardedBy("this")
55     private boolean closed;
56
57     public BgpTopologyDeployerImpl(final DataBroker dataBroker,
58             final ClusterSingletonServiceProvider singletonProvider) {
59         this.dataBroker = requireNonNull(dataBroker);
60         this.singletonProvider = requireNonNull(singletonProvider);
61     }
62
63     public void init() {
64         this.registration = this.dataBroker.registerDataTreeChangeListener(
65                 DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION, TOPOLOGY_IID), this);
66         LOG.info("BGP topology deployer started.");
67     }
68
69     @Override
70     public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Topology>> changes) {
71         if (this.closed) {
72             LOG.trace("BGP Topology Provider Deployer was already closed, skipping changes.");
73             return;
74         }
75         for (final DataTreeModification<Topology> change : changes) {
76             final DataObjectModification<Topology> rootNode = change.getRootNode();
77             final Topology dataBefore = rootNode.getDataBefore();
78             final Topology dataAfter = rootNode.getDataAfter();
79             LOG.trace("BGP topology deployer configuration changed: modification type: [{}],"
80                     + " data before:[{}], data after: [{}]", rootNode.getModificationType(), dataBefore, dataAfter);
81             switch (rootNode.getModificationType()) {
82                 case DELETE:
83                     filterTopologyBuilders(dataBefore)
84                             .forEach(provider -> provider.onTopologyBuilderRemoved(dataBefore));
85                     this.topologies.remove(dataBefore);
86                     break;
87                 case SUBTREE_MODIFIED:
88                     filterTopologyBuilders(dataBefore).forEach(provider
89                         -> provider.onTopologyBuilderRemoved(dataBefore));
90                     this.topologies.remove(dataBefore);
91                     filterTopologyBuilders(dataAfter).forEach(provider
92                         -> provider.onTopologyBuilderCreated(dataAfter));
93                     this.topologies.add(dataAfter);
94                     break;
95                 case WRITE:
96                     filterTopologyBuilders(dataAfter).forEach(provider
97                         -> provider.onTopologyBuilderCreated(dataAfter));
98                     this.topologies.add(dataAfter);
99                     break;
100                 default:
101                     break;
102             }
103         }
104     }
105
106     @Override
107     public synchronized AbstractRegistration registerTopologyProvider(final BgpTopologyProvider topologyBuilder) {
108         filterTopologies(topologyBuilder).forEach(topology -> topologyBuilder.onTopologyBuilderCreated(topology));
109         this.topologyProviders.add(topologyBuilder);
110         return new AbstractRegistration() {
111             @Override
112             protected void removeRegistration() {
113                 synchronized (BgpTopologyDeployerImpl.this) {
114                     filterTopologies(topologyBuilder)
115                             .forEach(topology -> topologyBuilder.onTopologyBuilderRemoved(topology));
116                     BgpTopologyDeployerImpl.this.topologyProviders.remove(topologyBuilder);
117                 }
118             }
119         };
120     }
121
122     @Override
123     public DataBroker getDataBroker() {
124         return this.dataBroker;
125     }
126
127     @Override
128     @SuppressWarnings("checkstyle:IllegalCatch")
129     public AbstractRegistration registerService(final TopologyReferenceSingletonService topologyProviderService) {
130         final Dictionary<String, String> properties = new Hashtable<>();
131         properties.put("topology-id", topologyProviderService.getInstanceIdentifier()
132                 .firstKeyOf(Topology.class).getTopologyId().getValue());
133         final ClusterSingletonServiceRegistration registerClusterSingletonService =
134                 registerSingletonService(topologyProviderService);
135         return new AbstractRegistration() {
136             @Override
137             protected void removeRegistration() {
138                 try {
139                     registerClusterSingletonService.close();
140                 } catch (final Exception e) {
141                     LOG.warn("Failed to close ClusterSingletonServiceRegistration {} for TopologyBuilder {}",
142                             registerClusterSingletonService, topologyProviderService.getInstanceIdentifier(), e);
143                 }
144             }
145         };
146     }
147
148     @Override
149     public synchronized void close() {
150         if (this.registration != null) {
151             this.registration.close();
152             this.registration = null;
153         }
154
155         LOG.info("BGP topology deployer stopped.");
156         this.closed = true;
157     }
158
159     private Iterable<BgpTopologyProvider> filterTopologyBuilders(final Topology topology) {
160         return this.topologyProviders.stream().filter(input -> input.topologyTypeFilter(topology))
161                 .collect(Collectors.toList());
162     }
163
164     private Iterable<Topology> filterTopologies(final BgpTopologyProvider topologyBuilder) {
165         return this.topologies.stream().filter(topology -> topologyBuilder.topologyTypeFilter(topology))
166                 .collect(Collectors.toList());
167     }
168
169     private ClusterSingletonServiceRegistration registerSingletonService(
170             final ClusterSingletonService clusterSingletonService) {
171         return ClusterSingletonServiceRegistrationHelper
172                 .registerSingletonService(this.singletonProvider, clusterSingletonService);
173     }
174
175 }