Bump upstreams
[bgpcep.git] / bmp / bmp-impl / src / main / java / org / opendaylight / protocol / bmp / impl / app / BmpRouterImpl.java
index 5fd727ca2515eda5f4f1022f637aef6ef1bcf046..ab33bb7b2a7330639b59adf7e4c2271891583ba6 100644 (file)
@@ -5,44 +5,45 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.protocol.bmp.impl.app;
 
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.base.Preconditions;
 import com.google.common.net.InetAddresses;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.MoreExecutors;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import javax.annotation.concurrent.GuardedBy;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import java.util.concurrent.ExecutionException;
+import org.checkerframework.checker.lock.qual.GuardedBy;
+import org.checkerframework.checker.lock.qual.Holding;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
 import org.opendaylight.protocol.bmp.api.BmpSession;
 import org.opendaylight.protocol.bmp.impl.spi.BmpRouter;
 import org.opendaylight.protocol.bmp.impl.spi.BmpRouterPeer;
 import org.opendaylight.protocol.util.Ipv4Util;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.OpenMessage;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev171207.InitiationMessage;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev171207.PeerDownNotification;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev171207.PeerHeader;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev171207.PeerUpNotification;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev171207.string.informations.StringInformation;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev171207.RouterId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev171207.peers.Peer;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev171207.routers.Router;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.OpenMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev200120.InitiationMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev200120.PeerDownNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev200120.PeerHeader;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev200120.PeerUpNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev200120.string.informations.StringInformation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev200120.RouterId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev200120.peers.Peer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev200120.routers.Router;
 import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
@@ -51,7 +52,7 @@ import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class BmpRouterImpl implements BmpRouter, TransactionChainListener {
+public final class BmpRouterImpl implements BmpRouter, FutureCallback<Empty> {
 
     private static final Logger LOG = LoggerFactory.getLogger(BmpRouterImpl.class);
 
@@ -73,45 +74,48 @@ public class BmpRouterImpl implements BmpRouter, TransactionChainListener {
     private BmpSession session;
     private RouterId routerId;
     private String routerIp;
+    @GuardedBy("this")
     private YangInstanceIdentifier routerYangIId;
+    @GuardedBy("this")
     private YangInstanceIdentifier peersYangIId;
 
     public BmpRouterImpl(final RouterSessionManager sessionManager) {
         this.sessionManager = requireNonNull(sessionManager);
-        this.domDataBroker = sessionManager.getDomDataBroker();
-        this.domTxChain = this.domDataBroker.createTransactionChain(this);
-        this.extensions = sessionManager.getExtensions();
-        this.tree = sessionManager.getCodecTree();
+        domDataBroker = sessionManager.getDomDataBroker();
+        domTxChain = domDataBroker.createMergingTransactionChain();
+        domTxChain.addCallback(this);
+        extensions = sessionManager.getExtensions();
+        tree = sessionManager.getCodecTree();
     }
 
     @Override
-    public void onSessionUp(final BmpSession session) {
-        this.session = session;
-        this.routerIp = InetAddresses.toAddrString(this.session.getRemoteAddress());
-        this.routerId = new RouterId(Ipv4Util.getIpAddress(this.session.getRemoteAddress()));
+    public synchronized void onSessionUp(final BmpSession psession) {
+        session = psession;
+        routerIp = InetAddresses.toAddrString(session.getRemoteAddress());
+        routerId = new RouterId(Ipv4Util.getIpAddress(session.getRemoteAddress()));
         // check if this session is redundant
-        if (!this.sessionManager.addSessionListener(this)) {
+        if (!sessionManager.addSessionListener(this)) {
             LOG.warn("Redundant BMP session with remote router {} ({}) detected. This BMP session will be abandoned.",
-                this.routerIp, this.session);
-            this.close();
+                routerIp, session);
+            close();
         } else {
-            this.routerYangIId = YangInstanceIdentifier.builder(this.sessionManager.getRoutersYangIId())
-                .nodeWithKey(Router.QNAME, ROUTER_ID_QNAME, this.routerIp).build();
-            this.peersYangIId = YangInstanceIdentifier.builder(this.routerYangIId).node(Peer.QNAME).build();
+            routerYangIId = YangInstanceIdentifier.builder(sessionManager.getRoutersYangIId())
+                .nodeWithKey(Router.QNAME, ROUTER_ID_QNAME, routerIp).build();
+            peersYangIId = YangInstanceIdentifier.builder(routerYangIId).node(Peer.QNAME).build();
             createRouterEntry();
-            LOG.info("BMP session with remote router {} ({}) is up now.", this.routerIp, this.session);
+            LOG.info("BMP session with remote router {} ({}) is up now.", routerIp, session);
         }
     }
 
     @Override
-    public void onSessionDown(final Exception e) {
+    public synchronized void onSessionDown(final Exception exception) {
         // we want to tear down as we want to do clean up like closing the transaction chain, etc.
         // even when datastore is not writable (routerYangIId == null / redundant session)
         tearDown();
     }
 
     @Override
-    public void onMessage(final Notification message) {
+    public void onMessage(final Notification<?> message) {
         if (message instanceof InitiationMessage) {
             onInitiate((InitiationMessage) message);
         } else if (message instanceof PeerUpNotification) {
@@ -122,40 +126,42 @@ public class BmpRouterImpl implements BmpRouter, TransactionChainListener {
     }
 
     @Override
-    public RouterId getRouterId() {
-        return this.routerId;
+    public synchronized RouterId getRouterId() {
+        return routerId;
     }
 
     @Override
+    @SuppressWarnings("checkstyle:IllegalCatch")
     public synchronized void close() {
-        if (this.session != null) {
+        if (session != null) {
             try {
-                this.session.close();
-            } catch (final Exception e) {
-                LOG.error("Fail to close session.", e);
+                session.close();
+            } catch (final Exception exc) {
+                LOG.error("Fail to close session.", exc);
             }
         }
     }
 
-    @GuardedBy("this")
+    @Holding("this")
+    @SuppressWarnings("checkstyle:IllegalCatch")
     private synchronized void tearDown() {
         // the session has been teared down before
-        if (this.session == null) {
+        if (session == null) {
             return;
         }
         // we want to display remote router's IP here, as sometimes this.session.close() is already
         // invoked before tearDown(), and session channel is null in this case, which leads to unuseful
         // log information
-        LOG.info("BMP Session with remote router {} ({}) went down.", this.routerIp, this.session);
-        this.session = null;
-        final Iterator<BmpRouterPeer> it = this.peers.values().iterator();
+        LOG.info("BMP Session with remote router {} ({}) went down.", routerIp, session);
+        session = null;
+        final Iterator<BmpRouterPeer> it = peers.values().iterator();
         try {
             while (it.hasNext()) {
                 it.next().close();
                 it.remove();
             }
-            this.domTxChain.close();
-        } catch(final Exception e) {
+            domTxChain.close();
+        } catch (final Exception e) {
             LOG.error("Failed to properly close BMP application.", e);
         } finally {
             // remove session only when session is valid, otherwise
@@ -164,85 +170,106 @@ public class BmpRouterImpl implements BmpRouter, TransactionChainListener {
             if (isDatastoreWritable()) {
                 try {
                     // it means the session was closed before it was written to datastore
-                    final DOMDataWriteTransaction wTx = this.domDataBroker.newWriteOnlyTransaction();
-                    wTx.delete(LogicalDatastoreType.OPERATIONAL, this.routerYangIId);
-                    wTx.submit().checkedGet();
-                } catch (final TransactionCommitFailedException e) {
+                    final DOMDataTreeWriteTransaction wTx = domDataBroker.newWriteOnlyTransaction();
+                    wTx.delete(LogicalDatastoreType.OPERATIONAL, routerYangIId);
+                    wTx.commit().get();
+                } catch (final InterruptedException | ExecutionException e) {
                     LOG.error("Failed to remove BMP router data from DS.", e);
                 }
-                this.sessionManager.removeSessionListener(this);
+                sessionManager.removeSessionListener(this);
             }
         }
     }
 
     @Override
-    public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction,
-        final Throwable cause) {
+    public synchronized void onFailure(final Throwable cause) {
         LOG.error("Transaction chain failed.", cause);
     }
 
     @Override
-    public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
-        LOG.debug("Transaction chain {} successfully.", chain);
+    public void onSuccess(final Empty value) {
+        LOG.debug("Transaction chain finished successfully.");
     }
 
-    private boolean isDatastoreWritable() {
-        return (this.routerYangIId != null);
+    private synchronized boolean isDatastoreWritable() {
+        return routerYangIId != null;
     }
 
     private synchronized void createRouterEntry() {
         Preconditions.checkState(isDatastoreWritable());
-        final DOMDataWriteTransaction wTx = this.domTxChain.newWriteOnlyTransaction();
-        wTx.put(LogicalDatastoreType.OPERATIONAL, this.routerYangIId,
+        final DOMDataTreeWriteTransaction wTx = domTxChain.newWriteOnlyTransaction();
+        wTx.put(LogicalDatastoreType.OPERATIONAL, routerYangIId,
                 Builders.mapEntryBuilder()
-                .withNodeIdentifier(new NodeIdentifierWithPredicates(Router.QNAME, ROUTER_ID_QNAME, this.routerIp))
-                .withChild(ImmutableNodes.leafNode(ROUTER_ID_QNAME, this.routerIp))
+                .withNodeIdentifier(NodeIdentifierWithPredicates.of(Router.QNAME, ROUTER_ID_QNAME, routerIp))
+                .withChild(ImmutableNodes.leafNode(ROUTER_ID_QNAME, routerIp))
                 .withChild(ImmutableNodes.leafNode(ROUTER_STATUS_QNAME, DOWN))
                 .withChild(ImmutableNodes.mapNodeBuilder(Peer.QNAME).build()).build());
-        wTx.submit();
+        wTx.commit().addCallback(new FutureCallback<CommitInfo>() {
+            @Override
+            public void onSuccess(final CommitInfo result) {
+                LOG.trace("Successful commit");
+            }
+
+            @Override
+            public void onFailure(final Throwable trw) {
+                LOG.error("Failed commit", trw);
+            }
+        }, MoreExecutors.directExecutor());
     }
 
     private synchronized void onInitiate(final InitiationMessage initiation) {
         Preconditions.checkState(isDatastoreWritable());
-        final DOMDataWriteTransaction wTx = this.domTxChain.newWriteOnlyTransaction();
-        wTx.merge(LogicalDatastoreType.OPERATIONAL, this.routerYangIId,
+        final DOMDataTreeWriteTransaction wTx = domTxChain.newWriteOnlyTransaction();
+        wTx.merge(LogicalDatastoreType.OPERATIONAL, routerYangIId,
                 Builders.mapEntryBuilder()
-                .withNodeIdentifier(new NodeIdentifierWithPredicates(Router.QNAME, ROUTER_ID_QNAME, this.routerIp))
+                .withNodeIdentifier(NodeIdentifierWithPredicates.of(Router.QNAME, ROUTER_ID_QNAME, routerIp))
                 .withChild(ImmutableNodes.leafNode(ROUTER_NAME_QNAME, initiation.getTlvs().getNameTlv().getName()))
-                .withChild(ImmutableNodes.leafNode(ROUTER_DESCRIPTION_QNAME, initiation.getTlvs().getDescriptionTlv().getDescription()))
-                .withChild(ImmutableNodes.leafNode(ROUTER_INFO_QNAME, getStringInfo(initiation.getTlvs().getStringInformation())))
+                .withChild(ImmutableNodes.leafNode(ROUTER_DESCRIPTION_QNAME, initiation.getTlvs().getDescriptionTlv()
+                        .getDescription()))
+                .withChild(ImmutableNodes.leafNode(ROUTER_INFO_QNAME, getStringInfo(initiation.getTlvs()
+                        .getStringInformation())))
                 .withChild(ImmutableNodes.leafNode(ROUTER_STATUS_QNAME, UP)).build());
-        wTx.submit();
+        wTx.commit().addCallback(new FutureCallback<CommitInfo>() {
+            @Override
+            public void onSuccess(final CommitInfo result) {
+                LOG.trace("Successful commit");
+            }
+
+            @Override
+            public void onFailure(final Throwable trw) {
+                LOG.error("Failed commit", trw);
+            }
+        }, MoreExecutors.directExecutor());
     }
 
-    private void onPeerUp(final PeerUpNotification peerUp) {
+    private synchronized void onPeerUp(final PeerUpNotification peerUp) {
         final PeerId peerId = getPeerIdFromOpen(peerUp.getReceivedOpen());
         if (!getPeer(peerId).isPresent()) {
-            final BmpRouterPeer peer = BmpRouterPeerImpl.createRouterPeer(this.domTxChain, this.peersYangIId, peerUp,
-                this.extensions, this.tree, peerId);
-            this.peers.put(peerId, peer);
-            LOG.debug("Router {}: Peer {} goes up.", this.routerIp, peerId.getValue());
+            final BmpRouterPeer peer = BmpRouterPeerImpl.createRouterPeer(domTxChain, peersYangIId, peerUp,
+                extensions, tree, peerId);
+            peers.put(peerId, peer);
+            LOG.debug("Router {}: Peer {} goes up.", routerIp, peerId.getValue());
         } else {
-            LOG.debug("Peer: {} for Router: {} already exists.", peerId.getValue(), this.routerIp);
+            LOG.debug("Peer: {} for Router: {} already exists.", peerId.getValue(), routerIp);
         }
     }
 
-    private void delegateToPeer(final Notification perPeerMessage) {
+    private synchronized void delegateToPeer(final Notification<?> perPeerMessage) {
         final PeerId peerId = getPeerId((PeerHeader) perPeerMessage);
         final Optional<BmpRouterPeer> maybePeer = getPeer(peerId);
         if (maybePeer.isPresent()) {
-            maybePeer.get().onPeerMessage(perPeerMessage);
+            maybePeer.orElseThrow().onPeerMessage(perPeerMessage);
             if (perPeerMessage instanceof PeerDownNotification) {
-                this.peers.remove(peerId);
-                LOG.debug("Router {}: Peer {} removed.", this.routerIp, peerId.getValue());
+                peers.remove(peerId);
+                LOG.debug("Router {}: Peer {} removed.", routerIp, peerId.getValue());
             }
         } else {
-            LOG.debug("Peer: {} for Router: {} was not found.", peerId.getValue(), this.routerIp);
+            LOG.debug("Peer: {} for Router: {} was not found.", peerId.getValue(), routerIp);
         }
     }
 
     private Optional<BmpRouterPeer> getPeer(final PeerId peerId) {
-        return Optional.ofNullable(this.peers.get(peerId));
+        return Optional.ofNullable(peers.get(peerId));
     }
 
     private static PeerId getPeerId(final PeerHeader peerHeader) {