2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.bgpcep.bgp.topology.provider.config;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Iterables;
13 import java.util.Collection;
14 import java.util.Dictionary;
15 import java.util.HashSet;
16 import java.util.Hashtable;
18 import java.util.function.Function;
19 import javax.annotation.concurrent.GuardedBy;
20 import org.opendaylight.bgpcep.bgp.topology.provider.spi.BgpTopologyDeployer;
21 import org.opendaylight.bgpcep.bgp.topology.provider.spi.BgpTopologyProvider;
22 import org.opendaylight.bgpcep.bgp.topology.provider.spi.TopologyReferenceSingletonService;
23 import org.opendaylight.bgpcep.topology.TopologyReference;
24 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
27 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
28 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
29 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
32 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
33 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
34 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
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.network.topology.Topology;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
38 import org.opendaylight.yangtools.concepts.AbstractRegistration;
39 import org.opendaylight.yangtools.concepts.ListenerRegistration;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
42 import org.osgi.framework.BundleContext;
43 import org.osgi.framework.ServiceRegistration;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 public final class BgpTopologyDeployerImpl implements AutoCloseable, ClusteredDataTreeChangeListener<Topology>, BgpTopologyDeployer {
49 private static final Logger LOG = LoggerFactory.getLogger(BgpTopologyDeployerImpl.class);
50 private static final InstanceIdentifier<Topology> TOPOLOGY_IID = InstanceIdentifier.create(NetworkTopology.class).child(Topology.class);
51 private static final int MAX_REGISTRATION_ATTEMPTS = 10;
52 private static final int SLEEP_TIME = MAX_REGISTRATION_ATTEMPTS;
55 private final Set<BgpTopologyProvider> topologyProviders = new HashSet<>();
56 private final DataBroker dataBroker;
57 private final ListenerRegistration<BgpTopologyDeployerImpl> registration;
58 private final BundleContext context;
59 private final ClusterSingletonServiceProvider singletonProvider;
61 private boolean closed;
63 public BgpTopologyDeployerImpl(final BundleContext context, final DataBroker dataBroker, final ClusterSingletonServiceProvider singletonProvider) {
64 this.context = Preconditions.checkNotNull(context);
65 this.dataBroker = Preconditions.checkNotNull(dataBroker);
66 this.singletonProvider = Preconditions.checkNotNull(singletonProvider);
68 this.dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(NetworkTopology.class).child(Topology.class)), this);
69 LOG.info("BGP topology deployer started.");
73 public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Topology>> changes) {
75 LOG.trace("BGP Topology Provider Deployer was already closed, skipping changes.");
78 for (final DataTreeModification<Topology> change : changes) {
79 final DataObjectModification<Topology> rootNode = change.getRootNode();
80 final Topology dataBefore = rootNode.getDataBefore();
81 final Topology dataAfter = rootNode.getDataAfter();
82 LOG.trace("BGP topology deployer configuration changed: modification type: [{}], data before:[{}], data after: [{}]", rootNode.getModificationType(), dataBefore, dataAfter);
83 switch (rootNode.getModificationType()) {
85 filterTopologyBuilders(dataBefore).forEach(provider -> provider.onTopologyBuilderRemoved(dataBefore));
87 case SUBTREE_MODIFIED:
88 filterTopologyBuilders(dataBefore).forEach(provider -> provider.onTopologyBuilderRemoved(dataBefore));
89 filterTopologyBuilders(dataAfter).forEach(provider -> provider.onTopologyBuilderCreated(dataAfter, null));
92 filterTopologyBuilders(dataAfter).forEach(provider -> provider.onTopologyBuilderCreated(dataAfter, null));
101 public synchronized AbstractRegistration registerTopologyProvider(final BgpTopologyProvider topologyBuilder) {
102 this.topologyProviders.add(topologyBuilder);
103 return new AbstractRegistration() {
105 protected void removeRegistration() {
106 synchronized (BgpTopologyDeployerImpl.this) {
107 BgpTopologyDeployerImpl.this.topologyProviders.remove(topologyBuilder);
114 public DataBroker getDataBroker() {
115 return this.dataBroker;
119 public AbstractRegistration registerService(final TopologyReferenceSingletonService topologyProviderService) {
120 final Dictionary<String, String> properties = new Hashtable<>();
121 properties.put("topology-id", topologyProviderService.getInstanceIdentifier().firstKeyOf(Topology.class).getTopologyId().getValue());
122 final ServiceRegistration<?> registerService = this.context.registerService(new String[]{TopologyReference.class.getName()}, topologyProviderService, properties);
123 final ClusterSingletonServiceRegistration registerClusterSingletonService = registerSingletonService(topologyProviderService);
124 return new AbstractRegistration() {
126 protected void removeRegistration() {
128 registerClusterSingletonService.close();
129 } catch (final Exception e) {
130 LOG.warn("Failed to close ClusterSingletonServiceRegistration {} for TopologyBuilder {}",
131 registerClusterSingletonService, topologyProviderService.getInstanceIdentifier(), e);
133 registerService.unregister();
139 public void createInstance(final Topology topology) {
140 final Function<Topology, Void> writeFunction = topology1 -> {
141 final WriteTransaction wTx = this.dataBroker.newWriteOnlyTransaction();
142 final KeyedInstanceIdentifier<Topology, TopologyKey> topologyIIdKeyed =
143 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, topology1.getKey());
144 wTx.put(LogicalDatastoreType.CONFIGURATION, topologyIIdKeyed, topology1, true);
149 filterTopologyBuilders(topology).forEach(provider -> provider.onTopologyBuilderCreated(topology, writeFunction));
153 public void removeInstance(final Topology topology) {
154 filterTopologyBuilders(topology).forEach(provider -> provider.onTopologyBuilderRemoved(topology));
158 public InstanceIdentifier<Topology> getInstanceIdentifier() {
163 public synchronized void close() throws Exception {
164 this.registration.close();
165 LOG.info("BGP topology deployer stopped.");
169 private Iterable<BgpTopologyProvider> filterTopologyBuilders(final Topology topology) {
170 return Iterables.filter(this.topologyProviders, input -> input.topologyTypeFilter(topology));
173 private ClusterSingletonServiceRegistration registerSingletonService(final ClusterSingletonService clusterSingletonService) {
174 return ClusterSingletonServiceRegistrationHelper.registerSingletonService(this.singletonProvider, clusterSingletonService, MAX_REGISTRATION_ATTEMPTS, SLEEP_TIME);