Replace Preconditions.CheckNotNull per RequireNonNull
[bgpcep.git] / bgp / openconfig-state / src / main / java / org / opendaylight / protocol / bgp / state / StateProviderImpl.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.protocol.bgp.state;
10
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.util.concurrent.CheckedFuture;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import io.netty.util.concurrent.GlobalEventExecutor;
16 import io.netty.util.concurrent.ScheduledFuture;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.TimerTask;
23 import java.util.concurrent.TimeUnit;
24 import java.util.stream.Collectors;
25 import javax.annotation.Nonnull;
26 import javax.annotation.concurrent.GuardedBy;
27 import javax.annotation.concurrent.ThreadSafe;
28 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
34 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
35 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
36 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
37 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
38 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
39 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
40 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
41 import org.opendaylight.protocol.bgp.rib.spi.state.BGPPeerState;
42 import org.opendaylight.protocol.bgp.rib.spi.state.BGPRIBState;
43 import org.opendaylight.protocol.bgp.rib.spi.state.BGPStateConsumer;
44 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
45 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.BgpBuilder;
46 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
47 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
48 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.PeerGroups;
49 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
50 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
51 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
52 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
53 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
54 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.ProtocolKey;
55 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.BGP;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.Rib;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.RibKey;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 @ThreadSafe
65 public final class StateProviderImpl implements TransactionChainListener, ClusterSingletonService, AutoCloseable {
66     private static final Logger LOG = LoggerFactory.getLogger(StateProviderImpl.class);
67     private static final ServiceGroupIdentifier SERVICE_GROUP_IDENTIFIER = ServiceGroupIdentifier
68         .create("bgp-state-provider-service-group");
69     private final BGPStateConsumer stateCollector;
70     private final BGPTableTypeRegistryConsumer bgpTableTypeRegistry;
71     private final KeyedInstanceIdentifier<NetworkInstance, NetworkInstanceKey> networkInstanceIId;
72     private final int timeout;
73     private final DataBroker dataBroker;
74     @GuardedBy("this")
75     private final Map<String, InstanceIdentifier<Bgp>> instanceIdentifiersCache = new HashMap<>();
76     private ClusterSingletonServiceRegistration singletonServiceRegistration;
77     @GuardedBy("this")
78     private BindingTransactionChain transactionChain;
79     @GuardedBy("this")
80     private ScheduledFuture<?> scheduleTask;
81
82     public StateProviderImpl(@Nonnull final DataBroker dataBroker, final int timeout,
83         @Nonnull BGPTableTypeRegistryConsumer bgpTableTypeRegistry, @Nonnull final BGPStateConsumer stateCollector,
84         @Nonnull final String networkInstanceName, @Nonnull final ClusterSingletonServiceProvider provider) {
85         this.dataBroker = requireNonNull(dataBroker);
86         this.bgpTableTypeRegistry = requireNonNull(bgpTableTypeRegistry);
87         this.stateCollector = requireNonNull(stateCollector);
88         this.networkInstanceIId = InstanceIdentifier.create(NetworkInstances.class)
89             .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
90         this.timeout = timeout;
91         this.singletonServiceRegistration = requireNonNull(provider)
92             .registerClusterSingletonService(this);
93     }
94
95     @Override
96     public synchronized void instantiateServiceInstance() {
97         this.transactionChain = this.dataBroker.createTransactionChain(this);
98         final TimerTask task = new TimerTask() {
99             @Override
100             public void run() {
101                 synchronized (StateProviderImpl.this) {
102                     final WriteTransaction wTx = StateProviderImpl.this.transactionChain.newWriteOnlyTransaction();
103                     try {
104                         updateBGPStats(wTx);
105                     } catch (final Exception e) {
106                         LOG.warn("Failed to update BGP Stats", e);
107                     } finally {
108                         wTx.submit();
109                     }
110                 }
111             }
112         };
113
114         this.scheduleTask = GlobalEventExecutor.INSTANCE.scheduleAtFixedRate(task, 0, this.timeout,
115             TimeUnit.SECONDS);
116     }
117
118     private synchronized void updateBGPStats(final WriteTransaction wTx) {
119         final Set<String> oldStats = new HashSet<>(this.instanceIdentifiersCache.keySet());
120         this.stateCollector.getRibStats()
121             .forEach(bgpStateConsumer -> {
122                 final KeyedInstanceIdentifier<Rib, RibKey> ribId = bgpStateConsumer.getInstanceIdentifier();
123                 final List<BGPPeerState> peerStats = this.stateCollector.getPeerStats().stream()
124                     .filter(peerState -> ribId.equals(peerState.getInstanceIdentifier())).collect(Collectors.toList());
125                 storeOperationalState(bgpStateConsumer, peerStats, ribId.getKey().getId().getValue(), wTx);
126                 oldStats.remove(ribId.getKey().getId().getValue());
127             });
128         oldStats.forEach(ribId -> removeStoredOperationalState(ribId, wTx));
129     }
130
131     private synchronized void removeStoredOperationalState(final String ribId, final WriteTransaction wTx) {
132         final InstanceIdentifier<Bgp> bgpIID = this.instanceIdentifiersCache.remove(ribId);
133         wTx.delete(LogicalDatastoreType.OPERATIONAL, bgpIID);
134     }
135
136     private synchronized void storeOperationalState(final BGPRIBState bgpStateConsumer,
137         final List<BGPPeerState> peerStats, final String ribId, final WriteTransaction wTx) {
138         final Global global = GlobalUtil.buildGlobal(bgpStateConsumer, this.bgpTableTypeRegistry);
139         final PeerGroups peerGroups = PeerGroupUtil.buildPeerGroups(peerStats);
140         final Neighbors neighbors = NeighborUtil.buildNeighbors(peerStats, this.bgpTableTypeRegistry);
141         InstanceIdentifier<Bgp> bgpIID = this.instanceIdentifiersCache.get(ribId);
142         if (bgpIID == null) {
143             final ProtocolKey protocolKey = new ProtocolKey(BGP.class, bgpStateConsumer.getInstanceIdentifier()
144                 .getKey().getId().getValue());
145             final KeyedInstanceIdentifier<Protocol, ProtocolKey> protocolIId = this.networkInstanceIId
146                 .child(Protocols.class).child(Protocol.class, protocolKey);
147             bgpIID = protocolIId.augmentation(Protocol1.class).child(Bgp.class);
148             this.instanceIdentifiersCache.put(ribId, bgpIID);
149         }
150
151         final Bgp bgp = new BgpBuilder().setGlobal(global).setNeighbors(neighbors).setPeerGroups(peerGroups).build();
152         wTx.put(LogicalDatastoreType.OPERATIONAL, bgpIID, bgp, WriteTransaction.CREATE_MISSING_PARENTS);
153     }
154
155     @Override
156     public void close() throws Exception {
157         if (this.singletonServiceRegistration != null) {
158             this.singletonServiceRegistration.close();
159             this.singletonServiceRegistration = null;
160         }
161     }
162
163     @Override
164     public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction,
165         final Throwable cause) {
166         LOG.error("Transaction chain failed {}.", transaction != null ? transaction.getIdentifier() : null, cause);
167     }
168
169     @Override
170     public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
171         LOG.debug("Transaction chain {} successful.", chain);
172     }
173
174     @Override
175     public synchronized ListenableFuture<Void> closeServiceInstance() {
176         this.scheduleTask.cancel(true);
177         final WriteTransaction wTx = this.transactionChain.newWriteOnlyTransaction();
178         this.instanceIdentifiersCache.keySet().forEach(ribId -> removeStoredOperationalState(ribId, wTx));
179         final CheckedFuture<Void, TransactionCommitFailedException> futureDelete = wTx.submit();
180         this.transactionChain.close();
181         return futureDelete;
182     }
183
184     @Override
185     public ServiceGroupIdentifier getIdentifier() {
186         return SERVICE_GROUP_IDENTIFIER;
187     }
188 }