NETVIRT-1630 migrate to md-sal APIs
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / SubnetmapChangeListener.java
index 816b4efdd98dd9c9b5305d6348bbd8581be8b282..e2d1c7e663922e2746111a32b91d8ab1387499b7 100644 (file)
@@ -8,25 +8,28 @@
 
 package org.opendaylight.netvirt.vpnmanager;
 
-import com.google.common.base.Optional;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-import javax.annotation.PostConstruct;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Singleton;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
-import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
+import org.opendaylight.infrautils.utils.concurrent.Executors;
+import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
+import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.vpntargets.VpnTarget;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes.NetworkType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
@@ -36,52 +39,47 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Singleton
-public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Subnetmap, SubnetmapChangeListener> {
+public class SubnetmapChangeListener extends AbstractAsyncDataTreeChangeListener<Subnetmap> {
     private static final Logger LOG = LoggerFactory.getLogger(SubnetmapChangeListener.class);
     private final DataBroker dataBroker;
     private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
     private final VpnUtil vpnUtil;
     private final IVpnManager vpnManager;
+    private final ManagedNewTransactionRunner txRunner;
 
     @Inject
     public SubnetmapChangeListener(final DataBroker dataBroker, final VpnSubnetRouteHandler vpnSubnetRouteHandler,
                                    VpnUtil vpnUtil, IVpnManager vpnManager) {
-        super(Subnetmap.class, SubnetmapChangeListener.class);
+        super(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.create(Subnetmaps.class).child(Subnetmap.class),
+                Executors.newListeningSingleThreadExecutor("SubnetmapChangeListener", LOG));
         this.dataBroker = dataBroker;
         this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
         this.vpnUtil = vpnUtil;
         this.vpnManager = vpnManager;
+        this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
+        start();
     }
 
-    @PostConstruct
     public void start() {
         LOG.info("{} start", getClass().getSimpleName());
-        registerListener(dataBroker);
     }
 
     @Override
-    protected InstanceIdentifier<Subnetmap> getWildCardPath() {
-        return InstanceIdentifier.create(Subnetmaps.class).child(Subnetmap.class);
+    @PreDestroy
+    public void close() {
+        super.close();
+        Executors.shutdownAndAwaitTermination(getExecutorService());
     }
 
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    private void registerListener(final DataBroker db) {
-        try {
-            registerListener(LogicalDatastoreType.CONFIGURATION, db);
-        } catch (final Exception e) {
-            LOG.error("VPNManager subnetMap config DataChange listener registration fail!", e);
-            throw new IllegalStateException("VPNManager subnetMap config DataChange listener registration failed.", e);
-        }
-    }
 
     @Override
-    protected void add(InstanceIdentifier<Subnetmap> identifier, Subnetmap subnetmap) {
-        LOG.debug("SubnetmapChangeListener add subnetmap method - key: {}, value: {}", identifier, subnetmap);
+    public void add(InstanceIdentifier<Subnetmap> identifier, Subnetmap subnetmap) {
+        LOG.debug("add: subnetmap method - key: {}, value: {}", identifier, subnetmap);
         Uuid subnetId = subnetmap.getId();
         Network network = vpnUtil.getNeutronNetwork(subnetmap.getNetworkId());
         if (network == null) {
-            LOG.error("SubnetMapChangeListener:add: network was not found for subnetId {}", subnetId.getValue());
+            LOG.error("add: network was not found for subnetId {}", subnetId.getValue());
             return;
         }
         if (subnetmap.getVpnId() != null) {
@@ -97,22 +95,27 @@ public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Sub
         String elanInstanceName = subnetmap.getNetworkId().getValue();
         long elanTag = getElanTag(elanInstanceName);
         if (elanTag == 0L) {
-            LOG.error("SubnetMapChangeListener:add: unable to fetch elantag from ElanInstance {} for subnet {}",
+            LOG.error("add: unable to fetch elantag from ElanInstance {} for subnet {}",
                       elanInstanceName, subnetId.getValue());
             return;
         }
         Uuid vpnId = subnetmap.getVpnId();
         if (vpnId != null) {
             boolean isBgpVpn = !vpnId.equals(subnetmap.getRouterId());
-            LOG.info("SubnetMapChangeListener:add: subnetmap {} with elanTag {} to VPN {}", subnetmap, elanTag,
+            LOG.info("add: subnetmap {} with elanTag {} to VPN {}", subnetmap, elanTag,
                      vpnId);
             vpnSubnetRouteHandler.onSubnetAddedToVpn(subnetmap, isBgpVpn, elanTag);
             if (isBgpVpn && subnetmap.getRouterId() == null) {
                 Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
                 if (!routeTargets.isEmpty()) {
-                    synchronized (subnetmap.getSubnetIp().intern()) {
+                    // FIXME: separate this out somehow?
+                    final ReentrantLock lock = JvmGlobalLocks.getLockForString(subnetmap.getSubnetIp());
+                    lock.lock();
+                    try {
                         vpnManager.updateRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
                                 vpnId.getValue());
+                    } finally {
+                        lock.unlock();
                     }
                 }
             }
@@ -120,34 +123,34 @@ public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Sub
     }
 
     @Override
-    protected void remove(InstanceIdentifier<Subnetmap> identifier, Subnetmap subnetmap) {
-        LOG.trace("SubnetmapListener:remove: subnetmap method - key: {}, value: {}", identifier, subnetmap);
+    public void remove(InstanceIdentifier<Subnetmap> identifier, Subnetmap subnetmap) {
+        LOG.trace("remove: subnetmap method - key: {}, value: {}", identifier, subnetmap);
     }
 
     @Override
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    protected void update(InstanceIdentifier<Subnetmap> identifier, Subnetmap subnetmapOriginal, Subnetmap
+    public void update(InstanceIdentifier<Subnetmap> identifier, Subnetmap subnetmapOriginal, Subnetmap
             subnetmapUpdate) {
-        LOG.debug("SubnetMapChangeListener update method - key {}, original {}, update {}", identifier,
+        LOG.debug("update: method - key {}, original {}, update {}", identifier,
                   subnetmapOriginal, subnetmapUpdate);
         Uuid subnetId = subnetmapUpdate.getId();
         Network network = vpnUtil.getNeutronNetwork(subnetmapUpdate.getNetworkId());
         if (network == null) {
-            LOG.error("SubnetMapChangeListener:update: network was not found for subnetId {}", subnetId.getValue());
+            LOG.error("update: network was not found for subnetId {}", subnetId.getValue());
             return;
         }
         String elanInstanceName = subnetmapUpdate.getNetworkId().getValue();
         long elanTag = getElanTag(elanInstanceName);
         if (elanTag == 0L) {
-            LOG.error("SubnetMapChangeListener:update: unable to fetch elantag from ElanInstance {} for subnetId {}",
+            LOG.error("update: unable to fetch elantag from ElanInstance {} for subnetId {}",
                       elanInstanceName, subnetId);
             return;
         }
         updateVlanDataEntry(subnetmapOriginal.getVpnId(), subnetmapUpdate.getVpnId(), subnetmapUpdate,
                 subnetmapOriginal, elanInstanceName);
         if (VpnUtil.getIsExternal(network)) {
-            LOG.debug("SubnetMapChangeListener:update: provider subnetwork {} is handling in "
+            LOG.debug("update: provider subnetwork {} is handling in "
                       + "ExternalSubnetVpnInstanceListener", subnetId.getValue());
             return;
         }
@@ -155,7 +158,7 @@ public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Sub
         Uuid vpnIdOld = subnetmapOriginal.getVpnId();
         Uuid vpnIdNew = subnetmapUpdate.getVpnId();
         if (!Objects.equals(vpnIdOld, vpnIdNew)) {
-            LOG.info("SubnetMapChangeListener:update: update subnetOpDataEntry for subnet {} imported in VPN",
+            LOG.info("update: update subnetOpDataEntry for subnet {} imported in VPN",
                      subnetmapUpdate.getId().getValue());
             updateSubnetmapOpDataEntry(subnetmapOriginal.getVpnId(), subnetmapUpdate.getVpnId(), subnetmapUpdate,
                                        subnetmapOriginal, elanTag);
@@ -164,7 +167,7 @@ public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Sub
         Uuid inetVpnIdOld = subnetmapOriginal.getInternetVpnId();
         Uuid inetVpnIdNew = subnetmapUpdate.getInternetVpnId();
         if (!Objects.equals(inetVpnIdOld, inetVpnIdNew)) {
-            LOG.info("SubnetMapChangeListener:update: update subnetOpDataEntry for subnet {} imported in InternetVPN",
+            LOG.info("update: update subnetOpDataEntry for subnet {} imported in InternetVPN",
                      subnetmapUpdate.getId().getValue());
             updateSubnetmapOpDataEntry(inetVpnIdOld, inetVpnIdNew, subnetmapUpdate, subnetmapOriginal, elanTag);
         }
@@ -176,7 +179,7 @@ public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Sub
         if (newPortList.size() == oldPortList.size()) {
             return;
         }
-        LOG.info("SubnetMapChangeListener:update: update port list for subnet {}", subnetmapUpdate.getId().getValue());
+        LOG.info("update: update port list for subnet {}", subnetmapUpdate.getId().getValue());
         if (newPortList.size() > oldPortList.size()) {
             for (Uuid portId : newPortList) {
                 if (! oldPortList.contains(portId)) {
@@ -212,7 +215,7 @@ public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Sub
             vpnSubnetRouteHandler.onSubnetDeletedFromVpn(subnetmapOriginal, true);
         }
         // subnet updated in VPN
-        if (vpnIdOld != null && vpnIdNew != null && (!vpnIdNew.equals(vpnIdOld))) {
+        if (vpnIdOld != null && vpnIdNew != null && !vpnIdNew.equals(vpnIdOld)) {
             vpnSubnetRouteHandler.onSubnetUpdatedInVpn(subnetmapUpdate, elanTag);
         }
     }
@@ -232,21 +235,18 @@ public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Sub
         }
     }
 
-    @Override
-    protected SubnetmapChangeListener getDataTreeChangeListener() {
-        return this;
-    }
-
+    @SuppressWarnings("all")
     protected long getElanTag(String elanInstanceName) {
-        InstanceIdentifier<ElanInstance> elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class)
-                .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
-        long elanTag = 0L;
-        try {
-            Optional<ElanInstance> elanInstance = SingleTransactionDataBroker.syncReadOptional(dataBroker,
-                    LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
-            if (elanInstance.isPresent()) {
-                if (elanInstance.get().getElanTag() != null) {
-                    elanTag = elanInstance.get().getElanTag();
+        final long[] elanTag = {0L};
+
+        ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
+            InstanceIdentifier<ElanInstance> elanIdentifierId = InstanceIdentifier.builder(ElanInstances.class)
+                    .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
+            ElanInstance elanInstance = tx.read(LogicalDatastoreType.CONFIGURATION, elanIdentifierId)
+                    .get().orElse(null);
+            if (elanInstance != null) {
+                if (elanInstance.getElanTag() != null) {
+                    elanTag[0] =elanInstance.getElanTag().longValue();
                 } else {
                     LOG.error("Notification failed because of failure in fetching elanTag for ElanInstance {}",
                             elanInstanceName);
@@ -254,10 +254,8 @@ public class SubnetmapChangeListener extends AsyncDataTreeChangeListenerBase<Sub
             } else {
                 LOG.error("Notification failed because of failure in reading ELANInstance {}", elanInstanceName);
             }
-        } catch (ReadFailedException e) {
-            LOG.error("Notification failed because of failure in fetching elanTag for ElanInstance {}",
-                elanInstanceName, e);
-        }
-        return elanTag;
+        }), LOG, "Error binding an ELAN tag for elanInstance {}", elanInstanceName);
+
+        return elanTag[0];
     }
 }