Eliminate circular dependencies and convert to BP annotations in elanmanager
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / listeners / HwvtepTerminationPointListener.java
index 6dee7060f45eb0c8011d6ffef3626ee58889f796..a90aa3e84516e8517a2c5ccb18c97a067e65a024 100644 (file)
@@ -7,24 +7,31 @@
  */
 package org.opendaylight.netvirt.elan.l2gw.listeners;
 
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import javax.annotation.Nonnull;
+import javax.inject.Inject;
+import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 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.hwvtep.HwvtepClusteredDataTreeChangeListener;
 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
 import org.opendaylight.netvirt.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.netvirt.elan.l2gw.utils.SettableFutureCallback;
 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
-import org.opendaylight.netvirt.elan.utils.ElanUtils;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
@@ -37,9 +44,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,25 +55,26 @@ import org.slf4j.LoggerFactory;
 /**
  * Listener for physical locator presence in operational datastore.
  */
+@Singleton
 public class HwvtepTerminationPointListener
-        extends HwvtepClusteredDataTreeChangeListener<TerminationPoint, HwvtepTerminationPointListener>
-        implements AutoCloseable {
+        extends HwvtepClusteredDataTreeChangeListener<TerminationPoint, HwvtepTerminationPointListener> {
 
     private static final Logger LOG = LoggerFactory.getLogger(HwvtepTerminationPointListener.class);
 
-    private DataBroker broker;
-    private ListenerRegistration<DataChangeListener> lstnerRegistration;
+    private final DataBroker broker;
     private final ElanL2GatewayUtils elanL2GatewayUtils;
-    private final EntityOwnershipService entityOwnershipService;
+    private final ElanClusterUtils elanClusterUtils;
 
-    public HwvtepTerminationPointListener(DataBroker broker, ElanUtils elanUtils,
-                                          EntityOwnershipService entityOwnershipService) {
+    @Inject
+    public HwvtepTerminationPointListener(DataBroker broker, ElanL2GatewayUtils elanL2GatewayUtils,
+            ElanClusterUtils elanClusterUtils) {
         super(TerminationPoint.class, HwvtepTerminationPointListener.class);
 
         this.broker = broker;
-        this.elanL2GatewayUtils = elanUtils.getElanL2GatewayUtils();
-        this.entityOwnershipService = entityOwnershipService;
-        registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+        this.elanL2GatewayUtils = elanL2GatewayUtils;
+        this.elanClusterUtils = elanClusterUtils;
+        //No longer needed as port reconciliation is added in plugin
+        //registerListener(LogicalDatastoreType.OPERATIONAL, broker);
         LOG.debug("created HwvtepTerminationPointListener");
     }
 
@@ -74,7 +82,7 @@ public class HwvtepTerminationPointListener
     static Map<InstanceIdentifier<TerminationPoint>, Boolean> teps = new ConcurrentHashMap<>();
 
     public static void runJobAfterPhysicalLocatorIsAvialable(InstanceIdentifier<TerminationPoint> key,
-            Runnable runnable) {
+                                                             Runnable runnable) {
         if (teps.get(key) != null) {
             LOG.debug("physical locator already available {} running job ", key);
             runnable.run();
@@ -86,29 +94,24 @@ public class HwvtepTerminationPointListener
         }
     }
 
-    @Override
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public void close() {
-        if (lstnerRegistration != null) {
-            try {
-                // TODO use https://git.opendaylight.org/gerrit/#/c/44145/ when merged, and remove @SuppressWarnings
-                lstnerRegistration.close();
-            } catch (final Exception e) {
-                LOG.error("Error when cleaning up DataChangeListener.", e);
-            }
-            lstnerRegistration = null;
-        }
-    }
-
     @Override
     protected void removed(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint del) {
         LOG.trace("physical locator removed {}", identifier);
         teps.remove(identifier);
+        final HwvtepPhysicalPortAugmentation portAugmentation =
+                del.getAugmentation(HwvtepPhysicalPortAugmentation.class);
+        if (portAugmentation != null) {
+            final NodeId nodeId = identifier.firstIdentifierOf(Node.class).firstKeyOf(Node.class).getNodeId();
+            elanClusterUtils.runOnlyInOwnerNode(HwvtepSouthboundConstants.ELAN_ENTITY_NAME,
+                "Handling Physical port delete",
+                () -> handlePortDeleted(identifier, portAugmentation, del, nodeId));
+            return;
+        }
     }
 
     @Override
     protected void updated(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint original,
-            TerminationPoint update) {
+                           TerminationPoint update) {
         LOG.trace("physical locator available {}", identifier);
     }
 
@@ -118,8 +121,8 @@ public class HwvtepTerminationPointListener
                 add.getAugmentation(HwvtepPhysicalPortAugmentation.class);
         if (portAugmentation != null) {
             final NodeId nodeId = identifier.firstIdentifierOf(Node.class).firstKeyOf(Node.class).getNodeId();
-            ElanClusterUtils.runOnlyInLeaderNode(entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_NAME,
-                    "handling Physical Switch add", () -> handlePortAdded(portAugmentation, add, nodeId));
+            elanClusterUtils.runOnlyInOwnerNode(HwvtepSouthboundConstants.ELAN_ENTITY_NAME,
+                () -> handlePortAdded(portAugmentation, add, nodeId));
             return;
         }
 
@@ -140,7 +143,8 @@ public class HwvtepTerminationPointListener
 
     @Override
     protected InstanceIdentifier<TerminationPoint> getWildCardPath() {
-        return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
+        return InstanceIdentifier.create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID)).child(Node.class)
                 .child(TerminationPoint.class);
     }
 
@@ -150,7 +154,7 @@ public class HwvtepTerminationPointListener
     }
 
     private List<ListenableFuture<Void>> handlePortAdded(HwvtepPhysicalPortAugmentation portAugmentation,
-            TerminationPoint portAdded, NodeId psNodeId) {
+                                                         TerminationPoint portAdded, NodeId psNodeId) {
         Node psNode = HwvtepUtils.getHwVtepNode(broker, LogicalDatastoreType.OPERATIONAL, psNodeId);
         if (psNode != null) {
             String psName = psNode.getAugmentation(PhysicalSwitchAugmentation.class).getHwvtepNodeName().getValue();
@@ -159,15 +163,12 @@ public class HwvtepTerminationPointListener
                 if (isL2GatewayConfigured(l2GwDevice)) {
                     List<L2gatewayConnection> l2GwConns = L2GatewayConnectionUtils.getAssociatedL2GwConnections(broker,
                             l2GwDevice.getL2GatewayIds());
-                    if (l2GwConns != null) {
-                        String newPortId = portAdded.getTpId().getValue();
-                        NodeId hwvtepNodeId = new NodeId(l2GwDevice.getHwvtepNodeId());
-                        List<VlanBindings> vlanBindings = getVlanBindings(l2GwConns, hwvtepNodeId, psName, newPortId);
-                        List<ListenableFuture<Void>> futures = new ArrayList<>();
-                        futures.add(elanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(hwvtepNodeId, psName,
-                                newPortId, vlanBindings));
-                        return futures;
-                    }
+                    String newPortId = portAdded.getTpId().getValue();
+                    NodeId hwvtepNodeId = new NodeId(l2GwDevice.getHwvtepNodeId());
+                    List<VlanBindings> vlanBindings = getVlanBindings(l2GwConns, hwvtepNodeId, psName, newPortId);
+                    return Collections.singletonList(
+                            elanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(hwvtepNodeId, psName, newPortId,
+                                    vlanBindings));
                 }
             } else {
                 LOG.error("{} details are not present in L2Gateway Cache", psName);
@@ -178,8 +179,32 @@ public class HwvtepTerminationPointListener
         return Collections.emptyList();
     }
 
+    private List<ListenableFuture<Void>> handlePortDeleted(InstanceIdentifier<TerminationPoint> identifier,
+                                                           HwvtepPhysicalPortAugmentation portAugmentation,
+                                                           TerminationPoint portDeleted,
+                                                           NodeId psNodeId) throws ReadFailedException {
+        InstanceIdentifier<Node> psNodeIid = identifier.firstIdentifierOf(Node.class);
+        final ReadWriteTransaction tx = broker.newReadWriteTransaction();
+        final SettableFuture settableFuture = SettableFuture.create();
+        List<ListenableFuture<Void>> futures = Collections.singletonList(settableFuture);
+        Futures.addCallback(tx.read(LogicalDatastoreType.CONFIGURATION, psNodeIid),
+                new SettableFutureCallback(settableFuture) {
+                    @Override
+                    public void onSuccess(@Nonnull Object resultNode) {
+                        Optional<Node> nodeOptional = (Optional<Node>) resultNode;
+                        if (nodeOptional.isPresent()) {
+                            //case of port deleted
+                            tx.delete(LogicalDatastoreType.CONFIGURATION, identifier);
+                            Futures.addCallback(tx.submit(), new SettableFutureCallback(settableFuture),
+                                                MoreExecutors.directExecutor());
+                        }
+                    }
+                }, MoreExecutors.directExecutor());
+        return futures;
+    }
+
     private List<VlanBindings> getVlanBindings(List<L2gatewayConnection> l2GwConns, NodeId hwvtepNodeId, String psName,
-            String newPortId) {
+                                               String newPortId) {
         List<VlanBindings> vlanBindings = new ArrayList<>();
         for (L2gatewayConnection l2GwConn : l2GwConns) {
             L2gateway l2Gateway = L2GatewayConnectionUtils.getNeutronL2gateway(broker, l2GwConn.getL2gatewayId());
@@ -218,7 +243,7 @@ public class HwvtepTerminationPointListener
     }
 
     private boolean isL2GatewayConfigured(L2GatewayDevice l2GwDevice) {
-        return l2GwDevice.getHwvtepNodeId() != null && l2GwDevice.isConnected()
-                && l2GwDevice.getL2GatewayIds().size() > 0 && l2GwDevice.getTunnelIp() != null;
+        return l2GwDevice.getHwvtepNodeId() != null
+                && !l2GwDevice.getL2GatewayIds().isEmpty() && l2GwDevice.getTunnelIp() != null;
     }
 }