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